diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Tue Feb  5 19:17:21 2002
+++ b/Documentation/Changes	Tue Feb  5 19:17:21 2002
@@ -106,8 +106,8 @@
 your kernel.  This change does, however, mean that you need a recent
 release of binutils.
 
-System utililities
-==================
+System utilities
+================
 
 Architectural changes
 ---------------------
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Feb  5 19:17:21 2002
+++ b/MAINTAINERS	Tue Feb  5 19:17:21 2002
@@ -1581,8 +1581,8 @@
 S:	Maintained
 
 USB KAWASAKI LSI DRIVER
-P:	Brad Hards
-M:	bradh@frogmouth.net
+P:	Oliver Neukum
+M:	drivers@neukum.org
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Feb  5 19:17:21 2002
+++ b/Makefile	Tue Feb  5 19:17:21 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 3
-EXTRAVERSION =
+SUBLEVEL = 4
+EXTRAVERSION =-pre1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -178,6 +178,8 @@
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+DRIVERS-$(CONFIG_GAMEPORT) += drivers/input/gameport/gamedrv.o
+DRIVERS-$(CONFIG_SERIO) += drivers/input/serio/seriodrv.o
 DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
diff -Nru a/arch/arm/mach-clps711x/dma.c b/arch/arm/mach-clps711x/dma.c
--- a/arch/arm/mach-clps711x/dma.c	Tue Feb  5 19:17:21 2002
+++ b/arch/arm/mach-clps711x/dma.c	Tue Feb  5 19:17:21 2002
@@ -18,7 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mman.h>
 #include <linux/init.h>
 
diff -Nru a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
--- a/arch/i386/boot/bootsect.S	Tue Feb  5 19:17:21 2002
+++ b/arch/i386/boot/bootsect.S	Tue Feb  5 19:17:21 2002
@@ -158,9 +158,7 @@
 	movw	$sread, %si		# the boot sector has already been read
 	movw	%ax, (%si)
 
-	xorw	%ax, %ax		# reset FDC
-	xorb	%dl, %dl
-	int	$0x13
+	call	kill_motor		# reset FDC
 	movw	$0x0200, %bx		# address = 512, in INITSEG
 next_step:
 	movb	setup_sects, %al
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Tue Feb  5 19:17:21 2002
+++ b/arch/i386/defconfig	Tue Feb  5 19:17:21 2002
@@ -404,7 +404,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -518,13 +517,23 @@
 # CONFIG_CD_NO_IDESCSI is not set
 
 #
-# Input core support
+# Input device support
 #
 # CONFIG_INPUT is not set
 # CONFIG_INPUT_KEYBDEV is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_GAMEPORT_PCIGAME is not set
+# CONFIG_GAMEPORT_FM801 is not set
+# CONFIG_GAMEPORT_CS461x is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_SERPORT is not set
 
 #
 # Character devices
@@ -551,19 +560,6 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -721,6 +717,7 @@
 # CONFIG_MIDI_VIA82CXXX is not set
 # CONFIG_SOUND_OSS is not set
 # CONFIG_SOUND_TVMIXER is not set
+CONFIG_INPUT_GAMEPORT=y
 
 #
 # USB support
diff -Nru a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
--- a/arch/sparc/kernel/rtrap.S	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc/kernel/rtrap.S	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.57 2001/07/17 16:17:33 anton Exp $
+/* $Id: rtrap.S,v 1.58 2002/01/31 03:30:05 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc/kernel/systbls.S	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.101 2001/10/18 08:27:05 davem Exp $
+/* $Id: systbls.S,v 1.102 2002/01/31 03:30:05 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -51,11 +51,11 @@
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 /*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-/*175*/	.long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-/*185*/	.long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+/*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
+/*185*/	.long sys_setpgid, sys_fremovexattr, sys_nis_syscall, sys_nis_syscall, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/entry.S	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.141 2001/12/05 23:56:32 davem Exp $
+/* $Id: entry.S,v 1.142 2002/01/31 03:30:06 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -1384,8 +1384,8 @@
 		 add		%o7, 1f-.-4, %o7
 		nop
 		.align		32
-1:		ldx		[%curptr + AOFF_task_ptrace], %l5
-		andcc		%l5, 0x02, %g0
+1:		ldub		[%curptr + AOFF_task_work + 1], %l5
+		andcc		%l5, 0xff, %g0
 		be,pt		%icc, rtrap
 		 clr		%l6
 		call		syscall_trace
@@ -1510,11 +1510,11 @@
 	mov		%i4, %o4				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 	srl		%i1, 0, %o1				! IEU0	Group
-	ldx		[%curptr + AOFF_task_ptrace], %l0	! Load
+	ldub		[%curptr + AOFF_task_work + 1], %l0	! Load
 
 	mov		%i5, %o5				! IEU1
 	srl		%i2, 0, %o2				! IEU0	Group
-	andcc		%l0, 0x02, %g0				! IEU0	Group
+	andcc		%l0, 0xff, %g0				! IEU0	Group
 	bne,pn		%icc, linux_syscall_trace32		! CTI
 	 mov		%i0, %l5				! IEU1
 	call		%l7					! CTI	Group brk forced
@@ -1538,11 +1538,11 @@
 	mov		%i1, %o1				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 4:	mov		%i2, %o2				! IEU0	Group
-	ldx		[%curptr + AOFF_task_ptrace], %l0	! Load
+	ldub		[%curptr + AOFF_task_work + 1], %l0	! Load
 
 	mov		%i3, %o3				! IEU1
 	mov		%i4, %o4				! IEU0	Group
-	andcc		%l0, 0x02, %g0				! IEU1	Group+1 bubble
+	andcc		%l0, 0xff, %g0				! IEU1	Group+1 bubble
 	bne,pn		%icc, linux_syscall_trace		! CTI	Group
 	 mov		%i0, %l5				! IEU0
 2:	call		%l7					! CTI	Group brk forced
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/process.c	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.129 2002/01/23 11:27:32 davem Exp $
+/*  $Id: process.c,v 1.130 2002/01/31 03:30:06 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/ptrace.c	Tue Feb  5 19:17:21 2002
@@ -538,10 +538,13 @@
 			child->thread.kregs->tnpc = ((addr + 4) & pc_mask);
 		}
 
-		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
-		else
-			child->ptrace &= ~PT_TRACESYS;
+		if (request == PTRACE_SYSCALL) {
+			child->ptrace |= PT_SYSCALLTRACE;
+			child->work.syscall_trace++;
+		} else {
+			child->ptrace &= ~PT_SYSCALLTRACE;
+			child->work.syscall_trace--;
+		}
 
 		child->exit_code = data;
 #ifdef DEBUG_PTRACE
@@ -621,8 +624,8 @@
 #ifdef DEBUG_PTRACE
 	printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
 #endif
-	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
-	    != (PT_PTRACED|PT_TRACESYS))
+	if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE))
+	    != (PT_PTRACED|PT_SYSCALLTRACE))
 		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
diff -Nru a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
--- a/arch/sparc64/kernel/rtrap.S	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/rtrap.S	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.59 2002/01/11 08:45:38 davem Exp $
+/* $Id: rtrap.S,v 1.60 2002/01/31 03:30:06 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -20,8 +20,8 @@
 
 		/* Register %l6 keeps track of whether we are returning
 		 * from a system call or not.  It is cleared if we call
-		 * do_signal, and it must not be otherwise modified until
-		 * we fully commit to returning to userspace.
+		 * do_notify_resume, and it must not be otherwise modified
+		 * until we fully commit to returning to userspace.
 		 */
 
 		.text
@@ -42,22 +42,26 @@
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		/* Redo sched+sig checks */
-#error		ldx			[%g6 + AOFF_task_need_resched], %l0
-		brz,pt			%l0, 1f
+		lduw			[%g6 + AOFF_task_work], %l0
+		srlx			%l0, 24, %o0
+
+		brz,pt			%o0, 1f
 		 nop
 		call			schedule
-
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-#error1:		lduw			[%g6 + AOFF_task_sigpending], %l0
-		brz,pt			%l0, __handle_user_windows_continue
+		lduw			[%g6 + AOFF_task_work], %l0
+
+1:		sllx			%l0, 48, %o0
+		brz,pt			%o0, __handle_user_windows_continue
 		 nop
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
-
 		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
-		call			do_signal
+		mov			%l0, %o4
+
+		call			do_notify_resume
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		clr			%l6
@@ -67,8 +71,8 @@
 		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 		sethi			%hi(0xf << 20), %l4
 		and			%l1, %l4, %l4
-
 		ba,pt			%xcc, __handle_user_windows_continue
+
 		 andn			%l1, %l4, %l1
 __handle_perfctrs:
 		call			update_perfctrs
@@ -77,27 +81,31 @@
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brz,pt			%o2, 1f
 		 nop
-
 		/* Redo userwin+sched+sig checks */
 		call			fault_in_user_windows
+
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-#error 1:		ldx			[%g6 + AOFF_task_need_resched], %l0
-		brz,pt			%l0, 1f
+		lduw			[%g6 + AOFF_task_work], %l0
+		srlx			%l0, 24, %o0
+		brz,pt			%o0, 1f
+
 		 nop
 		call			schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
-
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-#error 1:		lduw			[%g6 + AOFF_task_sigpending], %l0
-		brz,pt			%l0, __handle_perfctrs_continue
+		lduw			[%g6 + AOFF_task_work], %l0
+1:		sllx			%l0, 48, %o0
+
+		brz,pt			%o0, __handle_perfctrs_continue
 		 sethi			%hi(TSTATE_PEF), %o0
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
 		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		mov			%l0, %o4
+		call			do_notify_resume
 
-		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		clr			%l6
@@ -108,8 +116,8 @@
 		sethi			%hi(0xf << 20), %l4
 		and			%l1, %l4, %l4
 		andn			%l1, %l4, %l1
-
 		ba,pt			%xcc, __handle_perfctrs_continue
+
 		 sethi			%hi(TSTATE_PEF), %o0
 __handle_userfpu:
 		rd			%fprs, %l5
@@ -124,7 +132,8 @@
 		mov			%l5, %o2
 		mov			%l6, %o3
 		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
-		call			do_signal
+		mov			%l0, %o4
+		call			do_notify_resume
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		clr			%l6
@@ -173,13 +182,13 @@
 		 */
 to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 __handle_preemption_continue:
-#error		ldx			[%g6 + AOFF_task_need_resched], %l0
-		brnz,pn			%l0, __handle_preemption
-#error		 lduw			[%g6 + AOFF_task_sigpending], %l0
-		brnz,pn			%l0, __handle_signal
-		 nop
+		lduw			[%g6 + AOFF_task_work], %l0
+		srlx			%l0, 24, %o0
+		brnz,pn			%o0, __handle_preemption
+		 sllx			%l0, 48, %o0
+		brnz,pn			%o0, __handle_signal
 __handle_signal_continue:
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+		 ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brnz,pn			%o2, __handle_user_windows
 		 nop
 __handle_user_windows_continue:
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/signal.c	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.57 2001/12/11 04:55:51 davem Exp $
+/*  $Id: signal.c,v 1.58 2002/01/31 03:30:06 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -32,8 +32,8 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
-			 unsigned long orig_o0, int ret_from_syscall);
+static int do_signal(sigset_t *oldset, struct pt_regs * regs,
+		     unsigned long orig_o0, int ret_from_syscall);
 
 /* This turned off for production... */
 /* #define DEBUG_SIGNALS 1 */
@@ -688,8 +688,8 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
-			 unsigned long orig_i0, int restart_syscall)
+static int do_signal(sigset_t *oldset, struct pt_regs * regs,
+		     unsigned long orig_i0, int restart_syscall)
 {
 	unsigned long signr;
 	siginfo_t info;
@@ -700,8 +700,8 @@
 
 #ifdef CONFIG_SPARC32_COMPAT
 	if (current->thread.flags & SPARC_FLAG_32BIT) {
-		extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *,
-						  unsigned long, int);
+		extern int do_signal32(sigset_t *, struct pt_regs *,
+				       unsigned long, int);
 		return do_signal32(oldset, regs, orig_i0, restart_syscall);
 	}
 #endif	
@@ -829,4 +829,16 @@
 		regs->tnpc -= 4;
 	}
 	return 0;
+}
+
+void do_notify_resume(sigset_t *oldset, struct pt_regs *regs,
+		      unsigned long orig_i0, int restart_syscall,
+		      unsigned int work_pending)
+{
+	/* We don't pass in the task_work struct as a struct because
+	 * GCC always bounces that onto the stack due to the
+	 * ABI calling conventions.
+	 */
+	if (work_pending & 0x0000ff00)
+		do_signal(oldset, regs, orig_i0, restart_syscall);
 }
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/signal32.c	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.71 2001/12/11 04:55:51 davem Exp $
+/*  $Id: signal32.c,v 1.72 2002/01/31 03:30:06 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -30,8 +30,8 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs,
-			 unsigned long orig_o0, int ret_from_syscall);
+int do_signal32(sigset_t *oldset, struct pt_regs *regs,
+		unsigned long orig_o0, int ret_from_syscall);
 
 /* This turned off for production... */
 /* #define DEBUG_SIGNALS 1 */
@@ -1357,8 +1357,8 @@
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
-			   unsigned long orig_i0, int restart_syscall)
+int do_signal32(sigset_t *oldset, struct pt_regs * regs,
+		unsigned long orig_i0, int restart_syscall)
 {
 	unsigned long signr;
 	struct k_sigaction *ka;
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/smp.c	Tue Feb  5 19:17:21 2002
@@ -218,12 +218,8 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
-	init_idle();
-
 	while (!smp_threads_ready)
 		membar("#LoadLoad");
-
-	idle_startup_done();
 }
 
 void cpu_panic(void)
@@ -242,6 +238,8 @@
  */
 static struct task_struct *cpu_new_task = NULL;
 
+static void smp_tune_scheduling(void);
+
 void __init smp_boot_cpus(void)
 {
 	int cpucount = 0, i;
@@ -250,15 +248,17 @@
 	__sti();
 	smp_store_cpu_info(boot_cpu_id);
 
-	if (linux_num_cpus == 1)
+	if (linux_num_cpus == 1) {
+		smp_tune_scheduling();
 		return;
+	}
 
 	for (i = 0; i < NR_CPUS; i++) {
 		if (i == boot_cpu_id)
 			continue;
 
 		if ((cpucount + 1) == max_cpus)
-			break;
+			goto ignorecpu;
 		if (cpu_present_map & (1UL << i)) {
 			unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
 			unsigned long cookie = (unsigned long)(&cpu_new_task);
@@ -272,7 +272,7 @@
 
 			p = init_task.prev_task;
 
-			p->cpu = i;
+			init_idle(p, i);
 
 			unhash_process(p);
 
@@ -300,13 +300,15 @@
 			}
 		}
 		if (!callin_flag) {
+ignorecpu:
 			cpu_present_map &= ~(1UL << i);
 			__cpu_number_map[i] = -1;
 		}
 	}
 	cpu_new_task = NULL;
 	if (cpucount == 0) {
-		printk("Error: only one processor found.\n");
+		if (max_cpus != 1)
+			printk("Error: only one processor found.\n");
 		cpu_present_map = (1UL << smp_processor_id());
 	} else {
 		unsigned long bogosum = 0;
@@ -322,6 +324,12 @@
 		smp_activated = 1;
 		smp_num_cpus = cpucount + 1;
 	}
+
+	/* We want to run this with all the other cpus spinning
+	 * in the kernel.
+	 */
+	smp_tune_scheduling();
+
 	smp_processors_ready = 1;
 	membar("#StoreStore | #StoreLoad");
 }
@@ -1170,27 +1178,94 @@
 	prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
 }
 
-static inline unsigned long find_flush_base(unsigned long size)
+cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
+
+extern unsigned long cheetah_tune_scheduling(void);
+extern unsigned long timer_ticks_per_usec_quotient;
+
+static void __init smp_tune_scheduling(void)
 {
-	struct page *p = mem_map;
-	unsigned long found, base;
+	unsigned long orig_flush_base, flush_base, flags, *p;
+	unsigned int ecache_size, order;
+	cycles_t tick1, tick2, raw;
 
-	size = PAGE_ALIGN(size);
-	found = size;
-	base = (unsigned long) page_address(p);
-	while (found != 0) {
-		/* Failure. */
-		if (p >= (mem_map + max_mapnr))
-			return 0UL;
-		if (PageReserved(p)) {
-			found = size;
-			base = (unsigned long) page_address(p);
-		} else {
-			found -= PAGE_SIZE;
-		}
-		p++;
+	/* Approximate heuristic for SMP scheduling.  It is an
+	 * estimation of the time it takes to flush the L2 cache
+	 * on the local processor.
+	 *
+	 * The ia32 chooses to use the L1 cache flush time instead,
+	 * and I consider this complete nonsense.  The Ultra can service
+	 * a miss to the L1 with a hit to the L2 in 7 or 8 cycles, and
+	 * L2 misses are what create extra bus traffic (ie. the "cost"
+	 * of moving a process from one cpu to another).
+	 */
+	printk("SMP: Calibrating ecache flush... ");
+	if (tlb_type == cheetah) {
+		cacheflush_time = cheetah_tune_scheduling();
+		goto report;
+	}
+
+	ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
+					 "ecache-size", (512 * 1024));
+	if (ecache_size > (4 * 1024 * 1024))
+		ecache_size = (4 * 1024 * 1024);
+	orig_flush_base = flush_base =
+		__get_free_pages(GFP_KERNEL, order = get_order(ecache_size));
+
+	if (flush_base != 0UL) {
+		__save_and_cli(flags);
+
+		/* Scan twice the size once just to get the TLB entries
+		 * loaded and make sure the second scan measures pure misses.
+		 */
+		for (p = (unsigned long *)flush_base;
+		     ((unsigned long)p) < (flush_base + (ecache_size<<1));
+		     p += (64 / sizeof(unsigned long)))
+			*((volatile unsigned long *)p);
+
+		/* Now the real measurement. */
+		__asm__ __volatile__("
+		b,pt	%%xcc, 1f
+		 rd	%%tick, %0
+
+		.align	64
+1:		ldx	[%2 + 0x000], %%g1
+		ldx	[%2 + 0x040], %%g2
+		ldx	[%2 + 0x080], %%g3
+		ldx	[%2 + 0x0c0], %%g5
+		add	%2, 0x100, %2
+		cmp	%2, %4
+		bne,pt	%%xcc, 1b
+		 nop
+	
+		rd	%%tick, %1"
+		: "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
+		: "2" (flush_base), "r" (flush_base + ecache_size)
+		: "g1", "g2", "g3", "g5");
+
+		__restore_flags(flags);
+
+		raw = (tick2 - tick1);
+
+		/* Dampen it a little, considering two processes
+		 * sharing the cache and fitting.
+		 */
+		cacheflush_time = (raw - (raw >> 2));
+
+		free_pages(orig_flush_base, order);
+	} else {
+		cacheflush_time = ((ecache_size << 2) +
+				   (ecache_size << 1));
 	}
-	return base;
+report:
+	/* Convert cpu ticks to jiffie ticks. */
+	cache_decay_ticks = ((long)cacheflush_time * timer_ticks_per_usec_quotient);
+	cache_decay_ticks >>= 32UL;
+	cache_decay_ticks = (cache_decay_ticks * HZ) / 1000;
+
+	printk("Using heuristic of %ld cycles, %ld ticks.\n",
+	       cacheflush_time, cache_decay_ticks);
 }
 
 /* /proc/profile writes can call this, don't __init it please. */
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/systbls.S	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.79 2001/10/18 08:27:05 davem Exp $
+/* $Id: systbls.S,v 1.80 2002/01/31 03:30:06 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -52,11 +52,11 @@
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
@@ -111,11 +111,11 @@
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
-	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Tue Feb  5 19:17:21 2002
+++ b/arch/sparc64/kernel/traps.c	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.83 2002/01/11 08:45:38 davem Exp $
+/* $Id: traps.c,v 1.84 2002/01/30 01:39:56 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -526,6 +526,21 @@
 			     : "r" (physaddr), "r" (alias),
 			       "i" (ASI_PHYS_USE_EC));
 }
+
+#ifdef CONFIG_SMP
+unsigned long cheetah_tune_scheduling(void)
+{
+	unsigned long tick1, tick2, raw;
+
+	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick1));
+	cheetah_flush_ecache();
+	__asm__ __volatile__("rd %%tick, %0" : "=r" (tick2));
+
+	raw = (tick2 - tick1);
+
+	return (raw - (raw >> 2));
+}
+#endif
 
 /* Unfortunately, the diagnostic access to the I-cache tags we need to
  * use to clear the thing interferes with I-cache coherency transactions.
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Tue Feb  5 19:17:21 2002
+++ b/drivers/Makefile	Tue Feb  5 19:17:21 2002
@@ -8,7 +8,7 @@
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
-		fc4 net/hamradio i2c acpi bluetooth
+		fc4 net/hamradio i2c acpi bluetooth input/serio input/gameport
 
 subdir-y :=	base parport char block net sound misc media cdrom hotplug
 subdir-m :=	$(subdir-y)
@@ -27,6 +27,8 @@
 subdir-$(CONFIG_ALL_PPC)	+= macintosh
 subdir-$(CONFIG_USB)		+= usb
 subdir-$(CONFIG_INPUT)		+= input
+subdir-$(CONFIG_SERIO)		+= input/serio
+subdir-$(CONFIG_GAMEPORT)	+= input/gameport
 subdir-$(CONFIG_PHONE)		+= telephony
 subdir-$(CONFIG_SGI)		+= sgi
 subdir-$(CONFIG_IDE)		+= ide
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/base/core.c	Tue Feb  5 19:17:21 2002
@@ -7,7 +7,8 @@
 
 #include <linux/device.h>
 #include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
 
 #undef DEBUG
 
@@ -17,10 +18,7 @@
 # define DBG(x...)
 #endif
 
-static struct iobus device_root = {
-	bus_id: "root",
-	name:	"Logical System Root",
-};
+static struct device * device_root;
 
 int (*platform_notify)(struct device * dev) = NULL;
 int (*platform_notify_remove)(struct device * dev) = NULL;
@@ -28,9 +26,6 @@
 extern int device_make_dir(struct device * dev);
 extern void device_remove_dir(struct device * dev);
 
-extern int iobus_make_dir(struct iobus * iobus);
-extern void iobus_remove_dir(struct iobus * iobus);
-
 static spinlock_t device_lock;
 
 /**
@@ -47,19 +42,23 @@
 
 	if (!dev || !strlen(dev->bus_id))
 		return -EINVAL;
-	BUG_ON(!dev->parent);
 
 	spin_lock(&device_lock);
 	INIT_LIST_HEAD(&dev->node);
+	INIT_LIST_HEAD(&dev->children);
 	spin_lock_init(&dev->lock);
 	atomic_set(&dev->refcount,2);
 
-	get_iobus(dev->parent);
-	list_add_tail(&dev->node,&dev->parent->devices);
+	if (dev != device_root) {
+		if (!dev->parent)
+			dev->parent = device_root;
+		get_device(dev->parent);
+		list_add_tail(&dev->node,&dev->parent->children);
+	}
 	spin_unlock(&device_lock);
 
-	DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
-	    dev->bus_id, dev->name, parent->bus_id);
+	DBG("DEV: registering device: ID = '%s', name = %s\n",
+	    dev->bus_id, dev->name);
 
 	if ((error = device_make_dir(dev)))
 		goto register_done;
@@ -70,8 +69,8 @@
 
  register_done:
 	put_device(dev);
-	if (error)
-		put_iobus(dev->parent);
+	if (error && dev->parent)
+		put_device(dev->parent);
 	return error;
 }
 
@@ -100,9 +99,6 @@
 	/* remove the driverfs directory */
 	device_remove_dir(dev);
 
-	if (dev->subordinate)
-		iobus_remove_dir(dev->subordinate);
-
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
 	 */
@@ -116,73 +112,21 @@
 	if (dev->driver && dev->driver->remove)
 		dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
 
-	put_iobus(dev->parent);
-}
-
-int iobus_register(struct iobus *bus)
-{
-	int error;
-
-	if (!bus || !strlen(bus->bus_id))
-		return -EINVAL;
-	
-	spin_lock(&device_lock);
-	atomic_set(&bus->refcount,2);
-	spin_lock_init(&bus->lock);
-	INIT_LIST_HEAD(&bus->node);
-	INIT_LIST_HEAD(&bus->devices);
-	INIT_LIST_HEAD(&bus->children);
-
-	if (bus != &device_root) {
-		if (!bus->parent)
-			bus->parent = &device_root;
-		get_iobus(bus->parent);
-		list_add_tail(&bus->node,&bus->parent->children);
-	}
-	spin_unlock(&device_lock);
-
-	DBG("DEV: registering bus. ID = '%s' name = '%s' parent = %p\n",
-	    bus->bus_id,bus->name,bus->parent);
-
-	error = iobus_make_dir(bus);
-
-	put_iobus(bus);
-	if (error && bus->parent)
-		put_iobus(bus->parent);
-	return error;
-}
-
-/**
- * iobus_unregister - remove bus and children from device tree
- * @bus:	pointer to bus structure
- *
- * Remove device from parent's list of children and decrement
- * reference count on controlling device. That should take care of
- * the rest of the cleanup.
- */
-void put_iobus(struct iobus * iobus)
-{
-	if (!atomic_dec_and_lock(&iobus->refcount,&device_lock))
-		return;
-	list_del_init(&iobus->node);
-	spin_unlock(&device_lock);
-
-	if (!list_empty(&iobus->devices) ||
-	    !list_empty(&iobus->children))
-		BUG();
-
-	put_iobus(iobus->parent);
-	/* unregister itself */
-	put_device(iobus->self);
+	put_device(dev->parent);
 }
 
 static int __init device_init_root(void)
 {
-	/* initialize parent bus lists */
-	return iobus_register(&device_root);
+	device_root = kmalloc(sizeof(*device_root),GFP_KERNEL);
+	if (!device_root)
+		return -ENOMEM;
+	memset(device_root,0,sizeof(*device_root));
+	strcpy(device_root->bus_id,"root");
+	strcpy(device_root->name,"System Root");
+	return device_register(device_root);
 }
 
-int __init device_driver_init(void)
+static int __init device_driver_init(void)
 {
 	int error = 0;
 
@@ -207,8 +151,7 @@
 	return error;
 }
 
+subsys_initcall(device_driver_init);
+
 EXPORT_SYMBOL(device_register);
 EXPORT_SYMBOL(put_device);
-EXPORT_SYMBOL(iobus_register);
-EXPORT_SYMBOL(put_iobus);
-EXPORT_SYMBOL(device_driver_init);
diff -Nru a/drivers/base/fs.c b/drivers/base/fs.c
--- a/drivers/base/fs.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/base/fs.c	Tue Feb  5 19:17:21 2002
@@ -8,7 +8,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 
 extern struct driver_file_entry * device_default_files[];
 
@@ -102,28 +102,6 @@
 		}
 	}
 	return 0;
-}
-
-void iobus_remove_dir(struct iobus * iobus)
-{
-	if (iobus)
-		driverfs_remove_dir(&iobus->dir);
-}
-
-int iobus_make_dir(struct iobus * iobus)
-{
-	struct driver_dir_entry * parent = NULL;
-	int error;
-
-	INIT_LIST_HEAD(&iobus->dir.files);
-	iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
-	iobus->dir.name = iobus->bus_id;
-
-	if (iobus->parent)
-		parent = &iobus->parent->dir;
-
-	error = driverfs_create_dir(&iobus->dir,parent);
-	return error;
 }
 
 EXPORT_SYMBOL(device_create_file);
diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c
--- a/drivers/base/interface.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/base/interface.c	Tue Feb  5 19:17:21 2002
@@ -19,15 +19,7 @@
  */
 static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
 {
-	char *str = page;
-
-	if (off)
-		return 0;
-
-	str += sprintf(str,"Name:       %s\n",dev->name);
-	str += sprintf(str,"Bus ID:     %s\n",dev->bus_id);
-
-	return (str - page);
+	return off ? 0 : sprintf(page,"%s\n",dev->bus_id);
 }
 
 /**
@@ -84,17 +76,21 @@
 	store:		device_write_status,
 };
 
-static ssize_t
-device_read_power(struct device * dev, char * page, size_t count, loff_t off)
+static ssize_t device_read_name(struct device * dev, char * buf, size_t count, loff_t off)
 {
-	char	* str = page;
-
-	if (off)
-		return 0;
+	return off ? 0 : sprintf(buf,"%s\n",dev->name);
+}
 
-	str += sprintf(str,"State:      %d\n",dev->current_state);
+static struct driver_file_entry device_name_entry = {
+	name:	"name",
+	mode:	S_IRUGO,
+	show:	device_read_name,
+};
 
-	return (str - page);
+static ssize_t
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
+{
+	return off ? 0 : sprintf(page,"%d\n",dev->current_state);
 }
 
 static ssize_t
@@ -169,6 +165,7 @@
 
 struct driver_file_entry * device_default_files[] = {
 	&device_status_entry,
+	&device_name_entry,
 	&device_power_entry,
 	NULL,
 };
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/block/nbd.c	Tue Feb  5 19:17:21 2002
@@ -155,13 +155,14 @@
 	unsigned long size = req->nr_sectors << 9;
 
 	DEBUG("NBD: sending control, ");
+	
+	rw = rq_data_dir(req);
+	
 	request.magic = htonl(NBD_REQUEST_MAGIC);
-	request.type = htonl(req->flags);
+	request.type = htonl((rw & WRITE) ? 1 : 0);
 	request.from = cpu_to_be64( (u64) req->sector << 9);
 	request.len = htonl(size);
 	memcpy(request.handle, &req, sizeof(req));
-
-	rw = rq_data_dir(req);
 
 	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), rw & WRITE ? MSG_MORE : 0);
 	if (result <= 0)
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Tue Feb  5 19:17:21 2002
+++ b/drivers/char/Config.in	Tue Feb  5 19:17:21 2002
@@ -127,8 +127,6 @@
 fi
 endmenu
 
-source drivers/char/joystick/Config.in
-
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
 if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
    bool '  Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Tue Feb  5 19:17:21 2002
+++ b/drivers/char/Makefile	Tue Feb  5 19:17:21 2002
@@ -25,7 +25,7 @@
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o
 
-mod-subdirs	:=	joystick ftape drm pcmcia
+mod-subdirs	:=	ftape drm pcmcia
 
 list-multi	:=	
 
@@ -166,15 +166,10 @@
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 
 subdir-$(CONFIG_RIO) += rio
-subdir-$(CONFIG_INPUT) += joystick
 
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
-
-ifeq ($(CONFIG_INPUT),y)
-obj-y += joystick/js.o
-endif
 
 obj-$(CONFIG_BUSMOUSE) += busmouse.o
 obj-$(CONFIG_DTLK) += dtlk.o
diff -Nru a/drivers/char/joystick/Config.help b/drivers/char/joystick/Config.help
--- a/drivers/char/joystick/Config.help	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,300 +0,0 @@
-CONFIG_INPUT_GAMEPORT
-  Gameport support is for the standard 15-pin PC gameport.  If you
-  have a joystick, gamepad, gameport card, a soundcard with a gameport
-  or anything else that uses the gameport, say Y or M here and also to
-  at least one of the hardware specific drivers.
-  Please read the file <file:Documentation/input/joystick.txt> which
-  contains more information and the location of the joystick package
-  that you'll need if you use the gameport with a joystick.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called gameport.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_NS558
-  Say Y here if you have an ISA or PnP gameport.
-  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ns558.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_LIGHTNING
-  Say Y here if you have a PDPI Lightning 4 gamecard. For more
-  information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called lightning.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_CS461X
-  Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
-  PCI audio accelerator.  A product page for the CS4614 is at
-  <http://www.cirrus.com/design/products/overview/index.cfm?ProductID=40>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cs461x.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_PCIGAME
-  Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pcigame.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_EMU10K1
-  Say Y here if you have a SoundBlaster Live! card and want to use
-  its gameport.  For more information on how to use the driver
-  please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called emu10k1-gp.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_ANALOG
-  Say Y here if you have a controller that connects to the PC
-  gameport.  This supports many different types, including joysticks
-  with throttle control, with rudders, or with extensions like
-  additional hats and buttons compatible with CH Flightstick Pro,
-  ThrustMaster FCS, 6 and 8 button gamepads, or Saitek Cyborg
-  joysticks.  For more information on how to use the driver please
-  read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called analog.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_A3D
-  Say Y here if you have an FPGaming or MadCatz controller using the
-  A3D protocol over the PC gameport.  For more information on how to
-  use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called a3d.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_ADI
-  Say Y here if you have a Logitech controller using the ADI
-  protocol over the PC gameport. For more information on how to use
-  the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called adi.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_COBRA
-  Say Y here if you have a Creative Labs Blaster Cobra gamepad.
-  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cobra.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GF2K
-  Say Y here if you have a Genius Flight2000 or MaxFighter digitally
-  communicating joystick or gamepad.  For more information on how to
-  use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called gf2k.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GRIP
-  Say Y here if you have a Gravis controller using the GrIP protocol
-  over the PC gameport.  For more information on how to use the driver
-  please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called grip.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_INTERACT
-  Say Y hereif you have an InterAct gameport or joystick
-  communicating digitally over the gameport.  For more information on
-  how to use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called interact.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_TMDC
-  Say Y here if you have a ThrustMaster controller using the
-  DirectConnect (BSP) protocol over the PC gameport.  For more
-  information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tmdc.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SIDEWINDER
-  Say Y here if you have a Microsoft controller using the Digital
-  Overdrive protocol over PC gameport.  For more information on how to
-  use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called sidewinder.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SERIO
-  Say Y here and to the Serial port input line discipline option if
-  you plan to use a joystick that communicates over the serial (COM)
-  port.  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called sidewinder.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SERPORT
-  Say Y here if you plan to use a joystick that communicates over the
-  serial (COM) port.  For more information on how to use the driver
-  please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called serport.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_WARRIOR
-  Say Y here if you have a Logitech WingMan Warrior joystick connected
-  to your computer's serial port.  For more information on how to use
-  the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called warrior.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_MAGELLAN
-  Say Y here if you have a Magellan or Space Mouse 6DOF controller
-  connected to your computer's serial port.  For more information on
-  how to use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called magellan.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SPACEORB
-  Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
-  controller connected to your computer's serial port.  For more
-  information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called spaceorb.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SPACEBALL
-  Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller
-  connected to your computer's serial port.  For more information on
-  how to use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called spaceball.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_STINGER
-  Say Y here if you have a Gravis Stinger connected to one of your
-  serial ports.  For more information on how to use the driver please
-  read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called stinger.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_IFORCE_232
-  Say Y here if you have an I-Force joystick or steering wheel
-  connected to your serial (COM) port.  For more information on how
-  to use the driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called iforce.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_IFORCE_USB
-  Say Y here if you have an I-Force joystick or steering wheel
-  connected to your USB port.  For more information on how to use the
-  driver please read <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called iforce.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_DB9
-  Say Y here if you have a Sega Master System gamepad, Sega Genesis
-  gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
-  Commodore, Amstrad CPC joystick connected to your parallel port.
-  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt> and
-  <file:Documentation/input/joystick-parport.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called db9.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GAMECON
-  Say Y here if you have a Nintendo Entertainment System gamepad,
-  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
-  Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
-  Commodore, Amstrad CPC joystick connected to your parallel port.
-  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt> and
-  <file:Documentation/input/joystick-parport.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called gamecon.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_TURBOGRAFX
-  Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
-  and want to use it with Multisystem -- Atari, Amiga, Commodore,
-  Amstrad CPC joystick.  For more information on how to use the driver
-  please read <file:Documentation/input/joystick.txt> and
-  <file:Documentation/input/joystick-parport.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called turbografx.o.  If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_AMIJOY
-  Say Y here if you have an Amiga with a digital joystick connected
-  to it.  For more information on how to use the driver please read
-  <file:Documentation/input/joystick.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called joy-amiga.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
diff -Nru a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
--- a/drivers/char/joystick/Config.in	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-#
-# Joystick driver configuration
-#
-
-mainmenu_option next_comment
-comment 'Joysticks'
-
-if [ "$CONFIG_INPUT" != "n" ]; then
-   dep_tristate 'Game port support' CONFIG_INPUT_GAMEPORT $CONFIG_INPUT
-      dep_tristate '  Classic ISA/PnP gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X  $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  SoundBlaster Live! gameports' CONFIG_INPUT_EMU10K1 $CONFIG_INPUT_GAMEPORT
-   tristate 'Serial port device support' CONFIG_INPUT_SERIO
-      dep_tristate '  Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT_SERIO
-else
-   # Must explicitly set to n for drivers/sound/Config.in
-   define_tristate CONFIG_INPUT_GAMEPORT n
-   comment 'Input core support is needed for gameports'
-fi
-
-if [ "$CONFIG_INPUT" != "n" ]; then
-   comment 'Joysticks'
-
-   dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
-   dep_tristate '  I-Force USB joysticks and wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB
-   dep_tristate '  I-Force Serial joysticks and wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT $CONFIG_INPUT_SERIO
-   dep_tristate '  Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT
-   dep_tristate '  Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT
-   dep_tristate '  Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT
-
-   if [ "$CONFIG_AMIGA" = "y" ]; then
-      dep_tristate '  Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_INPUT
-   fi
-else
-   comment 'Input core support is needed for joysticks'
-fi
-
-endmenu
diff -Nru a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile
--- a/drivers/char/joystick/Makefile	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-#
-# Makefile for the joystick drivers.
-#
-
-O_TARGET	:= js.o
-
-# Objects that export symbols.
-
-export-objs	:= serio.o gameport.o
-
-# I-Force may need both USB and RS-232
-
-ifeq ($(CONFIG_INPUT_IFORCE_232),m)
-	ifeq ($(CONFIG_INPUT_IFORCE_USB),y)
-		CONFIG_INPUT_IFORCE_USB := m
-	endif
-endif
-ifeq ($(CONFIG_INPUT_IFORCE_USB),m)
-	ifeq ($(CONFIG_INPUT_IFORCE_232),y)
-		CONFIG_INPUT_IFORCE_232 := m
-	endif
-endif
-
-# Object file lists.
-
-obj-y	:=
-obj-m	:=
-obj-n	:=
-obj-	:=
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_INPUT_GAMEPORT)	+= gameport.o
-obj-$(CONFIG_INPUT_SERIO)	+= serio.o
-
-obj-$(CONFIG_INPUT_SERPORT)	+= serport.o
-
-obj-$(CONFIG_INPUT_NS558)	+= ns558.o
-obj-$(CONFIG_INPUT_LIGHTNING)	+= lightning.o
-obj-$(CONFIG_INPUT_PCIGAME)	+= pcigame.o
-obj-$(CONFIG_INPUT_CS461X)	+= cs461x.o
-obj-$(CONFIG_INPUT_EMU10K1)	+= emu10k1-gp.o
-
-obj-$(CONFIG_INPUT_WARRIOR)	+= warrior.o
-obj-$(CONFIG_INPUT_MAGELLAN)	+= magellan.o
-obj-$(CONFIG_INPUT_SPACEORB)	+= spaceorb.o
-obj-$(CONFIG_INPUT_SPACEBALL)	+= spaceball.o
-obj-$(CONFIG_INPUT_STINGER)	+= stinger.o
-obj-$(CONFIG_INPUT_IFORCE_232)	+= iforce.o
-obj-$(CONFIG_INPUT_IFORCE_USB)	+= iforce.o
-
-obj-$(CONFIG_INPUT_ANALOG)	+= analog.o
-obj-$(CONFIG_INPUT_A3D)		+= a3d.o
-obj-$(CONFIG_INPUT_ADI)		+= adi.o
-obj-$(CONFIG_INPUT_COBRA)	+= cobra.o
-obj-$(CONFIG_INPUT_GF2K)	+= gf2k.o
-obj-$(CONFIG_INPUT_GRIP)	+= grip.o
-obj-$(CONFIG_INPUT_INTERACT)	+= interact.o
-obj-$(CONFIG_INPUT_TMDC)	+= tmdc.o
-obj-$(CONFIG_INPUT_SIDEWINDER)	+= sidewinder.o
-
-obj-$(CONFIG_INPUT_DB9)		+= db9.o
-obj-$(CONFIG_INPUT_GAMECON)	+= gamecon.o
-obj-$(CONFIG_INPUT_TURBOGRAFX)	+= turbografx.o
-
-obj-$(CONFIG_INPUT_AMIJOY)	+= amijoy.o
-
-# The global Rules.make.
-
-include $(TOPDIR)/Rules.make
diff -Nru a/drivers/char/joystick/a3d.c b/drivers/char/joystick/a3d.c
--- a/drivers/char/joystick/a3d.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,388 +0,0 @@
-/*
- * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * FP-Gaming Assasin 3D joystick driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define A3D_MAX_START		400	/* 400 us */ 
-#define A3D_MAX_STROBE		60	/* 40 us */ 
-#define A3D_DELAY_READ		3	/* 3 ms */
-#define A3D_MAX_LENGTH		40	/* 40*3 bits */
-#define A3D_REFRESH_TIME	HZ/50	/* 20 ms */
-
-#define A3D_MODE_A3D		1	/* Assassin 3D */
-#define A3D_MODE_PAN		2	/* Panther */
-#define A3D_MODE_OEM		3	/* Panther OEM version */
-#define A3D_MODE_PXL		4	/* Panther XL */
-
-char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
-			"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
-
-struct a3d {
-	struct gameport *gameport;
-	struct gameport adc;
-	struct input_dev dev;
-	struct timer_list timer;
-	int axes[4];
-	int buttons;
-	int mode;
-	int length;
-	int used;
-	int reads;
-	int bads;
-};
-
-/*
- * a3d_read_packet() reads an Assassin 3D packet.
- */
-
-static int a3d_read_packet(struct gameport *gameport, int length, char *data)
-{
-	unsigned long flags;
-	unsigned char u, v;
-	unsigned int t, s;
-	int i;
-
-	i = 0;
-	t = gameport_time(gameport, A3D_MAX_START);
-	s = gameport_time(gameport, A3D_MAX_STROBE);
-
-	__save_flags(flags);
-	__cli();
-	gameport_trigger(gameport);
-	v = gameport_read(gameport);
-
-	while (t > 0 && i < length) {
-		t--;
-		u = v; v = gameport_read(gameport);
-		if (~v & u & 0x10) {
-			data[i++] = v >> 5;
-			t = s;
-		}
-	}
-
-	__restore_flags(flags);
-
-	return i;
-}
-
-/*
- * a3d_csum() computes checksum of triplet packet
- */
-
-static int a3d_csum(char *data, int count)
-{
-	int i, csum = 0;
-	for (i = 0; i < count - 2; i++) csum += data[i];
-	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
-}
-
-static void a3d_read(struct a3d *a3d, unsigned char *data)
-{
-	struct input_dev *dev = &a3d->dev;
-
-	switch (a3d->mode) {
-
-		case A3D_MODE_A3D:
-		case A3D_MODE_OEM:
-		case A3D_MODE_PAN:
-
-			input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
-			input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
-			
-			input_report_key(dev, BTN_RIGHT,  data[2] & 1);
-			input_report_key(dev, BTN_LEFT,   data[3] & 2);
-			input_report_key(dev, BTN_MIDDLE, data[3] & 4);
-
-			a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
-			a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
-			a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
-			a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
-
-			a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
-
-			return;
-
-		case A3D_MODE_PXL:
-
-			input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
-			input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
-
-			input_report_key(dev, BTN_RIGHT,  data[2] & 1);
-			input_report_key(dev, BTN_LEFT,   data[3] & 2);
-			input_report_key(dev, BTN_MIDDLE, data[3] & 4);
-			input_report_key(dev, BTN_SIDE,   data[7] & 2);
-			input_report_key(dev, BTN_EXTRA,  data[7] & 4);
-
-			input_report_abs(dev, ABS_X,        ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
-			input_report_abs(dev, ABS_Y,        ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
-			input_report_abs(dev, ABS_RUDDER,   ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
-			input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
-
-			input_report_abs(dev, ABS_HAT0X, ( data[5]       & 1) - ((data[5] >> 2) & 1));
-			input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
-			input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3]       & 1));
-			input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4]       & 1));
-
-			input_report_key(dev, BTN_TRIGGER, data[8] & 1);
-			input_report_key(dev, BTN_THUMB,   data[8] & 2);
-			input_report_key(dev, BTN_TOP,     data[8] & 4);
-			input_report_key(dev, BTN_PINKIE,  data[7] & 1);
-
-			return;
-	}
-}
-
-
-/*
- * a3d_timer() reads and analyzes A3D joystick data.
- */
-
-static void a3d_timer(unsigned long private)
-{
-	struct a3d *a3d = (void *) private;
-	unsigned char data[A3D_MAX_LENGTH];
-	a3d->reads++;
-	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
-		|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
-	 	a3d->bads++; else a3d_read(a3d, data);
-	mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
-}
-
-/*
- * a3d_adc_cooked_read() copies the acis and button data to the
- * callers arrays. It could do the read itself, but the caller could
- * call this more than 50 times a second, which would use too much CPU.
- */
-
-int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-	struct a3d *a3d = gameport->private;
-	int i;
-	for (i = 0; i < 4; i++)
-		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
-	*buttons = a3d->buttons; 
-	return 0;
-}
-
-/*
- * a3d_adc_open() is the gameport open routine. It refuses to serve
- * any but cooked data.
- */
-
-int a3d_adc_open(struct gameport *gameport, int mode)
-{
-	struct a3d *a3d = gameport->private;
-	if (mode != GAMEPORT_MODE_COOKED)
-		return -1;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
-	return 0;
-}
-
-/*
- * a3d_adc_close() is a callback from the input close routine.
- */
-
-static void a3d_adc_close(struct gameport *gameport)
-{
-	struct a3d *a3d = gameport->private;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
-}
-
-/*
- * a3d_open() is a callback from the input open routine.
- */
-
-static int a3d_open(struct input_dev *dev)
-{
-	struct a3d *a3d = dev->private;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
-	return 0;
-}
-
-/*
- * a3d_close() is a callback from the input close routine.
- */
-
-static void a3d_close(struct input_dev *dev)
-{
-	struct a3d *a3d = dev->private;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
-}
-
-/*
- * a3d_connect() probes for A3D joysticks.
- */
-
-static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct a3d *a3d;
-	unsigned char data[A3D_MAX_LENGTH];
-	int i;
-
-	if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
-		return;
-	memset(a3d, 0, sizeof(struct a3d));
-
-	gameport->private = a3d;
-
-	a3d->gameport = gameport;
-	init_timer(&a3d->timer);
-	a3d->timer.data = (long) a3d;
-	a3d->timer.function = a3d_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
-
-	if (!i || a3d_csum(data, i))
-		goto fail2;
-
-	a3d->mode = data[0];
-
-	if (!a3d->mode || a3d->mode > 5) {
-		printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
-			"(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
-		goto fail2;
-	}
-
-
-	if (a3d->mode == A3D_MODE_PXL) {
-
-		int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
-
-		a3d->length = 33;
-
-		a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
-		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
-		a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
-				   | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
-
-		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
-						 | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-
-		a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
-
-		a3d_read(a3d, data);
-
-		for (i = 0; i < 4; i++) {
-			if (i < 2) {
-				a3d->dev.absmin[axes[i]] = 48;
-				a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
-				a3d->dev.absflat[axes[i]] = 8;
-			} else {
-				a3d->dev.absmin[axes[i]] = 2;
-				a3d->dev.absmax[axes[i]] = 253;
-			}
-			a3d->dev.absmin[ABS_HAT0X + i] = -1;
-			a3d->dev.absmax[ABS_HAT0X + i] = 1;
-		}
-
-	} else {
-		a3d->length = 29;
-
-		a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
-		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
-		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
-
-		a3d->adc.private = a3d;
-		a3d->adc.open = a3d_adc_open;
-		a3d->adc.close = a3d_adc_close;
-		a3d->adc.cooked_read = a3d_adc_cooked_read;
-		a3d->adc.fuzz = 1; 
-
-		a3d_read(a3d, data);
-
-		gameport_register_port(&a3d->adc);
-		printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
-			a3d->adc.number, a3d_names[a3d->mode], gameport->number);
-	}
-
-	a3d->dev.private = a3d;
-	a3d->dev.open = a3d_open;
-	a3d->dev.close = a3d_close;
-
-	a3d->dev.name = a3d_names[a3d->mode];
-	a3d->dev.idbus = BUS_GAMEPORT;
-	a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
-	a3d->dev.idproduct = a3d->mode;
-	a3d->dev.idversion = 0x0100;
-
-	input_register_device(&a3d->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		a3d->dev.number, a3d_names[a3d->mode], gameport->number);
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:  kfree(a3d);
-}
-
-static void a3d_disconnect(struct gameport *gameport)
-{
-
-	struct a3d *a3d = gameport->private;
-	input_unregister_device(&a3d->dev);
-	if (a3d->mode < A3D_MODE_PXL)
-		gameport_unregister_port(&a3d->adc);
-	gameport_close(gameport);
-	kfree(a3d);
-}
-
-static struct gameport_dev a3d_dev = {
-	connect:	a3d_connect,
-	disconnect:	a3d_disconnect,
-};
-
-int __init a3d_init(void)
-{
-	gameport_register_device(&a3d_dev);
-	return 0;
-}
-
-void __exit a3d_exit(void)
-{
-	gameport_unregister_device(&a3d_dev);
-}
-
-module_init(a3d_init);
-module_exit(a3d_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/adi.c b/drivers/char/joystick/adi.c
--- a/drivers/char/joystick/adi.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,557 +0,0 @@
-/*
- * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Logitech ADI joystick family driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-#include <linux/init.h>
-
-/*
- * Times, array sizes, flags, ids.
- */
-
-#define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
-#define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
-#define ADI_REFRESH_TIME	HZ/50	/* How often to poll the joystick [20 ms] */
-#define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
-#define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
-
-#define ADI_MAX_LENGTH		256
-#define ADI_MIN_LENGTH		8
-#define ADI_MIN_LEN_LENGTH	10
-#define ADI_MIN_ID_LENGTH	66
-#define ADI_MAX_NAME_LENGTH	48
-#define ADI_MAX_CNAME_LENGTH	16
-
-#define ADI_FLAG_HAT		0x04
-#define ADI_FLAG_10BIT		0x08
-
-#define ADI_ID_TPD		0x01
-#define ADI_ID_WGP		0x06
-#define ADI_ID_WGPE		0x08
-#define ADI_ID_MAX		0x0a
-
-/*
- * Names, buttons, axes ...
- */
-
-static char *adi_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
-				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 
-				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 
-				"WingMan GamePad USB", "Unknown Device %#x" };
-
-static char adi_wmgpe_abs[] =	{ ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
-static char adi_wmi_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-static char adi_wmed3d_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
-static char adi_cm2_abs[] =	{ ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
-static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-
-static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = 	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
-static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
-static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
-
-static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
-			   adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
-
-static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
-			    adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
-
-/*
- * Hat to axis conversion arrays.
- */
-
-static struct {
-	int x;
-	int y;
-} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-/*
- * Per-port information.
- */
-
-struct adi {
-	struct input_dev dev;
-	int length;
-	int ret;
-	int idx;
-	unsigned char id;
-	char buttons;
-	char axes10;
-	char axes8;
-	signed char pad;
-	char hats;
-	char *abs;
-	short *key;
-	char name[ADI_MAX_NAME_LENGTH];
-	char cname[ADI_MAX_CNAME_LENGTH];
-	unsigned char data[ADI_MAX_LENGTH];
-};
-
-struct adi_port {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct adi adi[2];
-	int bad;
-	int reads;
-	int used;
-};
-
-/*
- * adi_read_packet() reads a Logitech ADI packet.
- */
-
-static void adi_read_packet(struct adi_port *port)
-{
-	struct adi *adi = port->adi;
-	struct gameport *gameport = port->gameport;
-	unsigned char u, v, w, x, z;
-	int t[2], s[2], i;
-	unsigned long flags;
-
-	for (i = 0; i < 2; i++) {
-		adi[i].ret = -1;
-		t[i] = gameport_time(gameport, ADI_MAX_START);
-		s[i] = 0;
-	}
-
-	__save_flags(flags);
-	__cli();
-
-	gameport_trigger(gameport);
-	v = z = gameport_read(gameport);
-
-	do {
-		u = v;
-		w = u ^ (v = x = gameport_read(gameport));
-		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
-			t[i]--;
-			if ((w & 0x30) && s[i]) {
-				if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
-					adi[i].data[++adi[i].ret] = w;
-					t[i] = gameport_time(gameport, ADI_MAX_STROBE);
-				} else t[i] = 0;
-			} else if (!(x & 0x30)) s[i] = 1;
-		}
-	} while (t[0] > 0 || t[1] > 0);
-
-	__restore_flags(flags);
-
-	return;
-}
-
-/*
- * adi_move_bits() detects a possible 2-stream mode, and moves
- * the bits accordingly. 
- */
-
-static void adi_move_bits(struct adi_port *port, int length)
-{
-	int i;
-	struct adi *adi = port->adi;
-
- 	adi[0].idx = adi[1].idx = 0;
-
-	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
-	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
-
-	for (i = 1; i <= adi[1].ret; i++)
-		adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
-
-	adi[0].ret += adi[1].ret;
-	adi[1].ret = -1;
-}
-
-/*
- * adi_get_bits() gathers bits from the data packet.
- */
-
-static inline int adi_get_bits(struct adi *adi, int count)
-{
-	int bits = 0;
-	int i;
-	if ((adi->idx += count) > adi->ret) return 0;
-	for (i = 0; i < count; i++)
-		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; 
-	return bits;
-}
-
-/*
- * adi_decode() decodes Logitech joystick data into input events.
- */
-
-static int adi_decode(struct adi *adi)
-{
-	struct input_dev *dev = &adi->dev;
-	char *abs = adi->abs;
-	short *key = adi->key;
-	int i, t;
-
-	if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
-		return -1;	
-
-	for (i = 0; i < adi->axes10; i++) 
-		input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
-
-	for (i = 0; i < adi->axes8; i++) 
-		input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
-
-	for (i = 0; i < adi->buttons && i < 63; i++) {
-		if (i == adi->pad) {
-			t = adi_get_bits(adi, 4);
-			input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t       & 1));
-			input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
-		}
-		input_report_key(dev, *key++, adi_get_bits(adi, 1));
-	}
-
-	for (i = 0; i < adi->hats; i++) {
-		if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
-		input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
-		input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
-	}
-
-	for (i = 63; i < adi->buttons; i++)
-		input_report_key(dev, *key++, adi_get_bits(adi, 1));
-
-	return 0;
-}
-
-/*
- * adi_read() reads the data packet and decodes it.
- */
-
-static int adi_read(struct adi_port *port)
-{
-	int i;
-	int result = 0;
-
-	adi_read_packet(port);
-	adi_move_bits(port, port->adi[0].length);
-
-	for (i = 0; i < 2; i++)
-		if (port->adi[i].length)
-			 result |= adi_decode(port->adi + i);
-
-	return result;
-}
-
-/*
- * adi_timer() repeatedly polls the Logitech joysticks.
- */
-
-static void adi_timer(unsigned long data)
-{
-	struct adi_port *port = (void *) data;
-	port->bad -= adi_read(port);
-	port->reads++;
-	mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
-}
-
-/*
- * adi_open() is a callback from the input open routine.
- */
-
-static int adi_open(struct input_dev *dev)
-{
-	struct adi_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);	
-	return 0;
-}
-
-/*
- * adi_close() is a callback from the input close routine.
- */
-
-static void adi_close(struct input_dev *dev)
-{
-	struct adi_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
-}
-
-/*
- * adi_init_digital() sends a trigger & delay sequence
- * to reset and initialize a Logitech joystick into digital mode.
- */
-
-static void adi_init_digital(struct gameport *gameport)
-{
-	int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
-	int i;
-
-	for (i = 0; seq[i]; i++) {
-		gameport_trigger(gameport);
-		if (seq[i] > 0) wait_ms(seq[i]);
-		if (seq[i] < 0) mdelay(-seq[i]);
-	}
-}
-
-static void adi_id_decode(struct adi *adi, struct adi_port *port)
-{
-	int i, t;
-
-	if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
-		return;
-
-	if (adi->ret < (t = adi_get_bits(adi, 10))) {
-		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); 
-		return;
-	}
-
-	adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
-
-	if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
-
-	adi->length = adi_get_bits(adi, 10);
-
-	if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
-		printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
-		adi->length = 0;
-		return;
-	}
-
-	adi->axes8 = adi_get_bits(adi, 4);
-	adi->buttons = adi_get_bits(adi, 6);
-
-	if (adi_get_bits(adi, 6) != 8 && adi->hats) {
-		printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
-		adi->length = 0;
-		return;
-	}
-
-	adi->buttons += adi_get_bits(adi, 6);
-	adi->hats += adi_get_bits(adi, 4);
-
-	i = adi_get_bits(adi, 4);
-
-	if (t & ADI_FLAG_10BIT) {
-		adi->axes10 = adi->axes8 - i;
-		adi->axes8 = i;
-	}
-
-	t = adi_get_bits(adi, 4);
-
-	for (i = 0; i < t; i++)
-		adi->cname[i] = adi_get_bits(adi, 8);
-	adi->cname[i] = 0;
-
-	t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
-	if (adi->length != t && adi->length != t + (t & 1)) {
-		printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
-		adi->length = 0;
-		return;
-	}
-
-	switch (adi->id) {
-		case ADI_ID_TPD:
-			adi->pad = 4;
-			adi->buttons -= 4;
-			break;
-		case ADI_ID_WGP:
-			adi->pad = 0;
-			adi->buttons -= 4;
-			break;
-		default:
-			adi->pad = -1;
-			break;
-	}
-}
-
-static void adi_init_input(struct adi *adi, struct adi_port *port)
-{
-	int i, t;
-	char buf[ADI_MAX_NAME_LENGTH];
-
-	if (!adi->length) return;
-
-	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
-
-	sprintf(buf, adi_names[t], adi->id);
-	sprintf(adi->name, "Logitech %s", buf);
-
-	adi->abs = adi_abs[t];
-	adi->key = adi_key[t];
-
-	adi->dev.open = adi_open;
-	adi->dev.close = adi_close;
-
-	adi->dev.name = adi->name;
-	adi->dev.idbus = BUS_GAMEPORT;
-	adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
-	adi->dev.idproduct = adi->id;
-	adi->dev.idversion = 0x0100;
-
-	adi->dev.private = port;
-	adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
-		set_bit(adi->abs[i], &adi->dev.absbit);
-
-	for (i = 0; i < adi->buttons; i++)
-		set_bit(adi->key[i], &adi->dev.keybit);
-}
-
-static void adi_init_center(struct adi *adi)
-{
-	int i, t, x;
-
-	if (!adi->length) return;
-
-	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
-
-		t = adi->abs[i];
-		x = adi->dev.abs[t];
-
-		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
-			if (i < adi->axes10) x = 512; else x = 128;
-		}
-
-		if (i < adi->axes10) {
-			adi->dev.absmax[t] = x * 2 - 64;
-			adi->dev.absmin[t] = 64;
-			adi->dev.absfuzz[t] = 2;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
-
-		if (i < adi->axes10 + adi->axes8) {
-			adi->dev.absmax[t] = x * 2 - 48;
-			adi->dev.absmin[t] = 48;
-			adi->dev.absfuzz[t] = 1;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
-
-		adi->dev.absmax[t] = 1;
-		adi->dev.absmin[t] = -1;
-	}
-}
-
-/*
- * adi_connect() probes for Logitech ADI joysticks.
- */
-
-static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct adi_port *port;
-	int i;
-
-	if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct adi_port));
-
-	gameport->private = port;
-
-	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = adi_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
-		kfree(port);
-		return;
-	}
-
-	adi_init_digital(gameport);
-	adi_read_packet(port);
-	
-	if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
-		adi_move_bits(port, adi_get_bits(port->adi, 10));
-
-	for (i = 0; i < 2; i++) {
-		adi_id_decode(port->adi + i, port);
-		adi_init_input(port->adi + i, port);
-	}
-
-	if (!port->adi[0].length && !port->adi[1].length) {
-		gameport_close(gameport);
-		kfree(port);
-		return;
-	}
-
-	wait_ms(ADI_INIT_DELAY);
-	if (adi_read(port)) {
-		wait_ms(ADI_DATA_DELAY);
-		adi_read(port);
-	}
-
-	for (i = 0; i < 2; i++)
-		if (port->adi[i].length > 0) {
-			adi_init_center(port->adi + i);
-			input_register_device(&port->adi[i].dev);
-			printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
-				port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
-		}
-}
-
-static void adi_disconnect(struct gameport *gameport)
-{
-	int i;
-
-	struct adi_port *port = gameport->private;
-	for (i = 0; i < 2; i++)
-		if (port->adi[i].length > 0)
-			input_unregister_device(&port->adi[i].dev);
-	gameport_close(gameport);
-	kfree(port);
-}
-
-/*
- * The gameport device structure.
- */
-
-static struct gameport_dev adi_dev = {
-	connect:	adi_connect,
-	disconnect:	adi_disconnect,
-};
-
-int __init adi_init(void)
-{
-	gameport_register_device(&adi_dev);
-	return 0;
-}
-
-void __exit adi_exit(void)
-{
-	gameport_unregister_device(&adi_dev);
-}
-
-module_init(adi_init);
-module_exit(adi_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/amijoy.c b/drivers/char/joystick/amijoy.c
--- a/drivers/char/joystick/amijoy.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,161 +0,0 @@
-/*
- * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Driver for Amiga joysticks for Linux/m68k
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-
-#include <asm/system.h>
-#include <asm/amigahw.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(amijoy, "1-2i");
-MODULE_LICENSE("GPL");
-
-static int amijoy[2] = { 0, 1 };
-static int amijoy_used[2] = { 0, 0 };
-static struct input_dev amijoy_dev[2];
-
-static char *amijoy_name = "Amiga joystick";
-
-static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-	int i, data = 0, button = 0;
-
-	for (i = 0; i < 2; i++)
-		if (amijoy[i]) {
-
-			switch (i) {
-				case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
-				case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
-			}
-
-			input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
-
-			input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
-			data = ~(data ^ (data << 1));
-			input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
-		}
-}
-
-static int amijoy_open(struct input_dev *dev)
-{
-	int *used = dev->private;
-
-	if ((*used)++)
-		return 0;
-	
-	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
-		(*used)--;
-		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
-		return -EBUSY;
-	}
-		
-	return 0;
-}
-
-static void amijoy_close(struct input_dev *dev)
-{
-	int *used = dev->private;
-
-	if (!--(*used))
-		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
-}
-
-static int __init amijoy_setup(char *str)
-{
-	int i;
-	int ints[4]
-        str = get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
-	return 1;
-}
-__setup("amijoy=", amijoy_setup);
-
-static int __init amijoy_init(void)
-{
-	int i, j;
-
-	init_timer(amijoy_timer);
-	port->timer.function = amijoy_timer;
-
-	for (i = 0; i < 2; i++)
-		if (amijoy[i]) {
-			if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
-						"amijoy [Denise]")) {
-				if (i == 1 && amijoy[0]) {
-					input_unregister_device(amijoy_dev);
-					release_mem_region(CUSTOM_PHYSADDR+10, 2);
-				}
-				return -EBUSY;
-			}
-
-			amijoy_dev[i].open = amijoy_open;
-			amijoy_dev[i].close = amijoy_close;
-			amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-			amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-			amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-			for (j = 0; j < 2; j++) {
-				amijoy_dev[i].absmin[ABS_X + j] = -1;
-				amijoy_dev[i].absmax[ABS_X + j] = 1;
-			}
-
-			amijoy->dev[i].name = amijoy_name;
-			amijoy->dev[i].idbus = BUS_AMIGA;
-			amijoy->dev[i].idvendor = 0x0001;
-			amijoy->dev[i].idproduct = 0x0003;
-			amijoy->dev[i].version = 0x0100;
-
-			amijoy_dev[i].private = amijoy_used + i;
-
-			input_register_device(amijoy_dev + i);
-			printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
-		}
-	return 0;
-}
-
-static void _exit amijoy_exit(void)
-{
-	int i;
-
-	for (i = 0; i < 2; i++)
-		if (amijoy[i]) {
-			input_unregister_device(amijoy_dev + i);
-			release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
-		}
-}
-
-module_init(amijoy_init);
-module_exit(amijoy_exit);
diff -Nru a/drivers/char/joystick/analog.c b/drivers/char/joystick/analog.c
--- a/drivers/char/joystick/analog.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,761 +0,0 @@
-/*
- * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
- *
- *  Copyright (c) 1996-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Analog joystick and gamepad driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-#include <asm/timex.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
-MODULE_LICENSE("GPL");
-
-/*
- * Option parsing.
- */
-
-#define ANALOG_PORTS		16
-
-static char *js[ANALOG_PORTS];
-static int analog_options[ANALOG_PORTS];
-MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
-MODULE_PARM_DESC(js, "Analog joystick options");
-
-/*
- * Times, feature definitions.
- */
-
-#define ANALOG_RUDDER		0x00004
-#define ANALOG_THROTTLE		0x00008
-#define ANALOG_AXES_STD		0x0000f
-#define ANALOG_BTNS_STD		0x000f0
-
-#define ANALOG_BTNS_CHF		0x00100
-#define ANALOG_HAT1_CHF		0x00200
-#define ANALOG_HAT2_CHF		0x00400
-#define ANALOG_HAT_FCS		0x00800
-#define ANALOG_HATS_ALL		0x00e00
-#define ANALOG_BTN_TL		0x01000
-#define ANALOG_BTN_TR		0x02000
-#define ANALOG_BTN_TL2		0x04000
-#define ANALOG_BTN_TR2		0x08000
-#define ANALOG_BTNS_TLR		0x03000
-#define ANALOG_BTNS_TLR2	0x0c000
-#define ANALOG_BTNS_GAMEPAD	0x0f000
-
-#define ANALOG_HBTN_CHF		0x10000
-#define ANALOG_ANY_CHF		0x10700
-#define ANALOG_SAITEK		0x20000
-#define ANALOG_EXTENSIONS	0x7ff00
-#define ANALOG_GAMEPAD		0x80000
-
-#define ANALOG_MAX_TIME		3	/* 3 ms */
-#define ANALOG_LOOP_TIME	2000	/* 2 * loop */
-#define ANALOG_REFRESH_TIME	HZ/100	/* 10 ms */
-#define ANALOG_SAITEK_DELAY	200	/* 200 us */
-#define ANALOG_SAITEK_TIME	2000	/* 2000 us */
-#define ANALOG_AXIS_TIME	2	/* 2 * refresh */
-#define ANALOG_INIT_RETRIES	8	/* 8 times */
-#define ANALOG_FUZZ_BITS	2	/* 2 bit more */
-#define ANALOG_FUZZ_MAGIC	36	/* 36 u*ms/loop */
-
-#define ANALOG_MAX_NAME_LENGTH  128
-
-static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
-static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
-static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
-static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
-static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
-				  BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
-
-static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
-
-struct analog {
-	struct input_dev dev;
-	int mask;
-	short *buttons;
-	char name[ANALOG_MAX_NAME_LENGTH];
-};
-
-struct analog_port {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct analog analog[2];
-	unsigned char mask;
-	char saitek;
-	char cooked;
-	int bads;
-	int reads;
-	int speed;
-	int loop;
-	int fuzz;
-	int axes[4];
-	int buttons;
-	int initial[4];
-	int used;
-	int axtime;
-};
-
-/*
- * Time macros.
- */
-
-#ifdef __i386__
-#define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
-#define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
-#define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
-#elif __x86_64__
-#define GET_TIME(x)	rdtscl(x)
-#define DELTA(x,y)	((y)-(x))
-#define TIME_NAME	"TSC"
-#elif __alpha__
-#define GET_TIME(x)	((x) = get_cycles())
-#define DELTA(x,y)	((y)-(x))
-#define TIME_NAME	"PCC"
-#else
-#define FAKE_TIME
-static unsigned long analog_faketime = 0;
-#define GET_TIME(x)     do { x = analog_faketime++; } while(0)
-#define DELTA(x,y)	((y)-(x))
-#define TIME_NAME	"Unreliable"
-#warning Precise timer not defined for this architecture.
-#endif
-
-/*
- * analog_decode() decodes analog joystick data and reports input events.
- */
-
-static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
-{
-	struct input_dev *dev = &analog->dev;
-	int i, j;
-
-	if (analog->mask & ANALOG_HAT_FCS)
-		for (i = 0; i < 4; i++)
-			if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
-				buttons |= 1 << (i + 14);
-				break;
-			}
-
-	for (i = j = 0; i < 6; i++)
-		if (analog->mask & (0x10 << i))
-			input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
-
-	if (analog->mask & ANALOG_HBTN_CHF)
-		for (i = 0; i < 4; i++)
-			input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
-
-	if (analog->mask & ANALOG_BTN_TL)
-		input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
-	if (analog->mask & ANALOG_BTN_TR)
-		input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
-	if (analog->mask & ANALOG_BTN_TL2)
-		input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
-	if (analog->mask & ANALOG_BTN_TR2)
-		input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
-
-	for (i = j = 0; i < 4; i++)
-		if (analog->mask & (1 << i))
-			input_report_abs(dev, analog_axes[j++], axes[i]);
-
-	for (i = j = 0; i < 3; i++)
-		if (analog->mask & analog_exts[i]) {
-			input_report_abs(dev, analog_hats[j++],
-				((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
-			input_report_abs(dev, analog_hats[j++],
-				((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
-		}
-}
-
-/*
- * analog_cooked_read() reads analog joystick data.
- */
-
-static int analog_cooked_read(struct analog_port *port)
-{
-	struct gameport *gameport = port->gameport;
-	unsigned int time[4], start, loop, now, loopout, timeout;
-	unsigned char data[4], this, last;
-	unsigned long flags;
-	int i, j;
-
-	loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
-	timeout = ANALOG_MAX_TIME * port->speed;
-	
-	__save_flags(flags);
-	__cli();
-	gameport_trigger(gameport);
-	GET_TIME(now);
-	__restore_flags(flags);
-
-	start = now;
-	this = port->mask;
-	i = 0;
-
-	do {
-		loop = now;
-		last = this;
-
-		__cli();
-		this = gameport_read(gameport) & port->mask;
-		GET_TIME(now);
-		__restore_flags(flags);
-
-		if ((last ^ this) && (DELTA(loop, now) < loopout)) {
-			data[i] = last ^ this;
-			time[i] = now;
-			i++;
-		}
-
-	} while (this && (i < 4) && (DELTA(start, now) < timeout));
-
-	this <<= 4;
-
-	for (--i; i >= 0; i--) {
-		this |= data[i];
-		for (j = 0; j < 4; j++)
-			if (data[i] & (1 << j))
-				port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
-	}
-
-	return -(this != port->mask);
-}
-
-static int analog_button_read(struct analog_port *port, char saitek, char chf)
-{
-	unsigned char u;
-	int t = 1, i = 0;
-	int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
-
-	u = gameport_read(port->gameport);
-
-	if (!chf) { 
-		port->buttons = (~u >> 4) & 0xf;
-		return 0;
-	}
-
-	port->buttons = 0;
-
-	while ((~u & 0xf0) && (i < 16) && t) {
-		port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
-		if (!saitek) return 0;
-		udelay(ANALOG_SAITEK_DELAY);
-		t = strobe;
-		gameport_trigger(port->gameport);
-		while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
-		i++;
-	}
-
-	return -(!t || (i == 16));
-}
-
-/*
- * analog_timer() repeatedly polls the Analog joysticks.
- */
-
-static void analog_timer(unsigned long data)
-{
-	struct analog_port *port = (void *) data;
-	int i;
-
-	char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
-	char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
-
-	if (port->cooked) {
-		port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
-		if (chf)
-			port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
-		port->reads++;
-	} else {
-		if (!port->axtime--) {
-			port->bads -= analog_cooked_read(port);
-			port->bads -= analog_button_read(port, saitek, chf);
-			port->reads++;
-			port->axtime = ANALOG_AXIS_TIME - 1;
-		} else {
-			if (!saitek)
-				analog_button_read(port, saitek, chf);
-		}
-	}
-
-	for (i = 0; i < 2; i++) 
-		if (port->analog[i].mask)
-			analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
-
-	mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
-}
-
-/*
- * analog_open() is a callback from the input open routine.
- */
-
-static int analog_open(struct input_dev *dev)
-{
-	struct analog_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);	
-	return 0;
-}
-
-/*
- * analog_close() is a callback from the input close routine.
- */
-
-static void analog_close(struct input_dev *dev)
-{
-	struct analog_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
-}
-
-/*
- * analog_calibrate_timer() calibrates the timer and computes loop
- * and timeout values for a joystick port.
- */
-
-static void analog_calibrate_timer(struct analog_port *port)
-{
-	struct gameport *gameport = port->gameport;
-	unsigned int i, t, tx, t1, t2, t3;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	GET_TIME(t1);
-#ifdef FAKE_TIME
-	analog_faketime += 830;
-#endif
-	udelay(1000);
-	GET_TIME(t2);
-	GET_TIME(t3);
-	restore_flags(flags);
-
-	port->speed = DELTA(t1, t2) - DELTA(t2, t3);
-
-	tx = ~0;
-
-	for (i = 0; i < 50; i++) {
-		save_flags(flags);
-		cli();
-		GET_TIME(t1);
-		for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
-		GET_TIME(t3);
-		restore_flags(flags);
-		udelay(i);
-		t = DELTA(t1, t2) - DELTA(t2, t3);
-		if (t < tx) tx = t;
-	}
-
-        port->loop = tx / 50;
-}
-
-/*
- * analog_name() constructs a name for an analog joystick.
- */
-
-static void analog_name(struct analog *analog)
-{
-	sprintf(analog->name, "Analog %d-axis %d-button", 
-		hweight8(analog->mask & ANALOG_AXES_STD),
-		hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
-		hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
-
-	if (analog->mask & ANALOG_HATS_ALL)
-		sprintf(analog->name, "%s %d-hat",
-			analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
-
-	if (analog->mask & ANALOG_HAT_FCS)
-			strcat(analog->name, " FCS");
-	if (analog->mask & ANALOG_ANY_CHF)
-			strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
-
-	strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
-}
-
-/*
- * analog_init_device()
- */
-
-static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
-{
-	int i, j, t, v, w, x, y, z;
-
-	analog_name(analog);
-
-	analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
-
-	analog->dev.name = analog->name;
-	analog->dev.idbus = BUS_GAMEPORT;
-	analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
-	analog->dev.idproduct = analog->mask >> 4;
-	analog->dev.idversion = 0x0100;
-
-	analog->dev.open = analog_open;
-	analog->dev.close = analog_close;
-	analog->dev.private = port;
-	analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	
-	for (i = j = 0; i < 4; i++)
-		if (analog->mask & (1 << i)) {
-			
-			t = analog_axes[j];
-			x = port->axes[i];
-			y = (port->axes[0] + port->axes[1]) >> 1;
-			z = y - port->axes[i];
-			z = z > 0 ? z : -z;
-			v = (x >> 3);
-			w = (x >> 3);
-
-			set_bit(t, analog->dev.absbit);
-
-			if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
-				x = y;
-
-			if (analog->mask & ANALOG_SAITEK) {
-				if (i == 2) x = port->axes[i];
-				v = x - (x >> 2);
-				w = (x >> 4);
-			}
-
-			analog->dev.absmax[t] = (x << 1) - v;
-			analog->dev.absmin[t] = v;
-			analog->dev.absfuzz[t] = port->fuzz;
-			analog->dev.absflat[t] = w;
-
-			j++;
-		}
-
-	for (i = j = 0; i < 3; i++) 
-		if (analog->mask & analog_exts[i]) 
-			for (x = 0; x < 2; x++) {
-				t = analog_hats[j++];
-				set_bit(t, analog->dev.absbit);
-				analog->dev.absmax[t] = 1;
-				analog->dev.absmin[t] = -1;
-			}
-
-	for (i = j = 0; i < 4; i++)
-		if (analog->mask & (0x10 << i))
-			set_bit(analog->buttons[j++], analog->dev.keybit);
-
-	if (analog->mask & ANALOG_BTNS_CHF)
-		for (i = 0; i < 2; i++)
-			set_bit(analog->buttons[j++], analog->dev.keybit);
-
-	if (analog->mask & ANALOG_HBTN_CHF)
-		for (i = 0; i < 4; i++)
-			set_bit(analog->buttons[j++], analog->dev.keybit);
-
-	for (i = 0; i < 4; i++)
-		if (analog->mask & (ANALOG_BTN_TL << i))
-			set_bit(analog_pads[i], analog->dev.keybit);
-
-	analog_decode(analog, port->axes, port->initial, port->buttons);
-
-	input_register_device(&analog->dev);
-
-	printk(KERN_INFO "input%d: %s at gameport%d.%d",
-		analog->dev.number, analog->name, port->gameport->number, index);
-
-	if (port->cooked)
-		printk(" [ADC port]\n");
-	else
-		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
-		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-		port->speed > 10000 ? "M" : "k",
-		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
-				    : (port->loop * 1000000) / port->speed);
-}
-
-/*
- * analog_init_devices() sets up device-specific values and registers the input devices.
- */
-
-static int analog_init_masks(struct analog_port *port)
-{
-	int i;
-	struct analog *analog = port->analog;
-	int max[4];
-
-	if (!port->mask)
-		return -1;
-
-	if ((port->mask & 3) != 3 && port->mask != 0xc) {
-		printk(KERN_WARNING "analog.c: Unknown joystick device found  "
-			"(data=%#x, gameport%d), probably not analog joystick.\n",
-			port->mask, port->gameport->number);
-		return -1;
-	}
-
-	i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
-
-	analog[0].mask = i & 0xfffff;
-
-	analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
-			| port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
-			| ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
-
-	analog[0].mask &= ~(ANALOG_HAT2_CHF)
-			| ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
-
-	analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
-			| ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
-			| ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
-			| ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
-
-	analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
-			| (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
-			&  ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
-
-	analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
-
-	analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
-			: (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
-
-	if (port->cooked) {
-
-		for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
-
-		if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
-		if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
-		if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
-		if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
-		if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
-
-		gameport_calibrate(port->gameport, port->axes, max);
-	}
-		
-	for (i = 0; i < 4; i++) 
-		port->initial[i] = port->axes[i];
-
-	return -!(analog[0].mask || analog[1].mask);	
-}
-
-static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
-{
-	int i, t, u, v;
-
-	gameport->private = port;
-	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = analog_timer;
-
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
-
-		analog_calibrate_timer(port);
-
-		gameport_trigger(gameport);
-		t = gameport_read(gameport);
-		wait_ms(ANALOG_MAX_TIME);
-		port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
-		port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
-	
-		for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
-			if (!analog_cooked_read(port)) break;
-			wait_ms(ANALOG_MAX_TIME);
-		}
-
-		u = v = 0;
-
-		wait_ms(ANALOG_MAX_TIME);
-		t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
-		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; 
-		udelay(ANALOG_SAITEK_DELAY);
-		t = gameport_time(gameport, ANALOG_SAITEK_TIME);
-		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; 
-
-		if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
-			analog_options[port->gameport->number] |=
-				ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
-			return 0;
-		}
-
-		gameport_close(gameport);
-	}
-
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
-
-		for (i = 0; i < ANALOG_INIT_RETRIES; i++)
-			if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
-				break;
-		for (i = 0; i < 4; i++)
-			if (port->axes[i] != -1) port->mask |= 1 << i;
-
-		port->fuzz = gameport->fuzz;
-		port->cooked = 1;
-		return 0;
-	}
-
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		return 0;
-
-	return -1;
-}
-
-static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct analog_port *port;
-	int i;
-
-	if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct analog_port));
-
-	if (analog_init_port(gameport, dev, port)) {
-		kfree(port);
-		return;
-	}
-
-	if (analog_init_masks(port)) {
-		gameport_close(gameport);
-		kfree(port);
-		return;
-	}
-
-	for (i = 0; i < 2; i++)
-		if (port->analog[i].mask)
-			analog_init_device(port, port->analog + i, i);
-}
-
-static void analog_disconnect(struct gameport *gameport)
-{
-	int i;
-
-	struct analog_port *port = gameport->private;
-	for (i = 0; i < 2; i++)
-		if (port->analog[i].mask)
-			input_unregister_device(&port->analog[i].dev);
-	gameport_close(gameport);
-	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
-		port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
-		port->gameport->number);
-	kfree(port);
-}
-
-struct analog_types {
-	char *name;
-	int value;
-};
-
-struct analog_types analog_types[] = {
-	{ "none",	0x00000000 },
-	{ "auto",	0x000000ff },
-	{ "2btn",	0x0000003f },
-	{ "y-joy",	0x0cc00033 },
-	{ "y-pad",	0x8cc80033 },
-	{ "fcs",	0x000008f7 },
-	{ "chf",	0x000002ff },
-	{ "fullchf",	0x000007ff },
-	{ "gamepad",	0x000830f3 },
-	{ "gamepad8",	0x0008f0f3 },
-	{ NULL, 0 }
-};
-
-static void analog_parse_options(void)
-{
-	int i, j;
-	char *end;
-
-	for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
-
-		for (j = 0; analog_types[j].name; j++)
-			if (!strcmp(analog_types[j].name, js[i])) {
-				analog_options[i] = analog_types[j].value;
-				break;
-			} 
-		if (analog_types[j].name) continue;
-
-		analog_options[i] = simple_strtoul(js[i], &end, 0);
-		if (end != js[i]) continue;
-
-		analog_options[i] = 0xff;
-		if (!strlen(js[i])) continue;
-
-		printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
-	}
-
-	for (; i < ANALOG_PORTS; i++)
-		analog_options[i] = 0xff;
-}
-
-/*
- * The gameport device structure.
- */
-
-static struct gameport_dev analog_dev = {
-	connect:	analog_connect,
-	disconnect:	analog_disconnect,
-};
-
-#ifndef MODULE
-static int __init analog_setup(char *str)
-{
-	char *s = str;
-	int i = 0;
-
-	if (!str || !*str) return 0;
-
-	while ((str = s) && (i < ANALOG_PORTS)) {
-		if ((s = strchr(str,','))) *s++ = 0;
-		js[i++] = str;
-	}
-
-	return 1;
-}
-__setup("js=", analog_setup);
-#endif
-
-int __init analog_init(void)
-{
-	analog_parse_options();
-	gameport_register_device(&analog_dev);
-	return 0;
-}
-
-void __exit analog_exit(void)
-{
-	gameport_unregister_device(&analog_dev);
-}
-
-module_init(analog_init);
-module_exit(analog_exit);
diff -Nru a/drivers/char/joystick/cobra.c b/drivers/char/joystick/cobra.c
--- a/drivers/char/joystick/cobra.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,252 +0,0 @@
-/*
- * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Creative Labd Blaster GamePad Cobra driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
-#define COBRA_REFRESH_TIME	HZ/50	/* 20 ms between reads */
-#define COBRA_LENGTH		36
-
-static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
-
-static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
-
-struct cobra {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct input_dev dev[2];
-	int used;
-	int reads;
-	int bads;
-	unsigned char exists;
-};
-
-static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
-{
-	unsigned long flags;
-	unsigned char u, v, w;
-	__u64 buf[2];
-	int r[2], t[2];
-	int i, j, ret;
-
-	int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
-
-	for (i = 0; i < 2; i++) {
-		r[i] = buf[i] = 0;
-		t[i] = COBRA_MAX_STROBE;
-	}
-	
-	__save_flags(flags);
-	__cli();
-
-	u = gameport_read(gameport);
-
-	do {
-		t[0]--; t[1]--;
-		v = gameport_read(gameport);
-		for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
-			if (w & 0x30) {
-				if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
-					buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
-					t[i] = strobe;
-					u = v;
-				} else t[i] = 0;
-			}
-	} while (t[0] > 0 || t[1] > 0);
-
-	__restore_flags(flags);
-
-	ret = 0;
-
-	for (i = 0; i < 2; i++) {
-
-		if (r[i] != COBRA_LENGTH) continue;
-
-		for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
-			buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
-
-		if (j < COBRA_LENGTH) ret |= (1 << i);
-
-		data[i] = ((buf[i] >>  7) & 0x000001f) | ((buf[i] >>  8) & 0x00003e0)
-			| ((buf[i] >>  9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
-			| ((buf[i] >> 11) & 0x1f00000);
-
-	}
-
-	return ret;
-}
-
-static void cobra_timer(unsigned long private)
-{
-	struct cobra *cobra = (void *) private;
-	struct input_dev *dev;
-	unsigned int data[2];
-	int i, j, r;
-
-	cobra->reads++;
-
-	if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
-		cobra->bads++;
-
-	for (i = 0; i < 2; i++)
-		if (cobra->exists & r & (1 << i)) {
-
-			dev = cobra->dev + i;
-
-			input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
-			input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
-
-			for (j = 0; cobra_btn[j]; j++)
-				input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
-
-		}
-
-	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
-}
-
-static int cobra_open(struct input_dev *dev)
-{
-	struct cobra *cobra = dev->private;
-	if (!cobra->used++)
-		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
-	return 0;
-}
-
-static void cobra_close(struct input_dev *dev)
-{
-	struct cobra *cobra = dev->private;
-	if (!--cobra->used)
-		del_timer(&cobra->timer);
-}
-
-static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct cobra *cobra;
-	unsigned int data[2];
-	int i, j;
-
-	if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
-		return;
-	memset(cobra, 0, sizeof(struct cobra));
-
-	gameport->private = cobra;
-
-	cobra->gameport = gameport;
-	init_timer(&cobra->timer);
-	cobra->timer.data = (long) cobra;
-	cobra->timer.function = cobra_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	cobra->exists = cobra_read_packet(gameport, data);
-
-	for (i = 0; i < 2; i++) 
-		if ((cobra->exists >> i) & data[i] & 1) {
-			printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
-				" Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
-			cobra->exists &= ~(1 << i);
-		}
-
-	if (!cobra->exists)
-		goto fail2;
-
-	for (i = 0; i < 2; i++)
-		if ((cobra->exists >> i) & 1) {
-
-			cobra->dev[i].private = cobra;
-			cobra->dev[i].open = cobra_open;
-			cobra->dev[i].close = cobra_close;
-
-			cobra->dev[i].name = cobra_name;
-			cobra->dev[i].idbus = BUS_GAMEPORT;
-			cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
-			cobra->dev[i].idproduct = 0x0008;
-			cobra->dev[i].idversion = 0x0100;
-		
-			cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-			cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
-			for (j = 0; cobra_btn[j]; j++)
-				set_bit(cobra_btn[j], cobra->dev[i].keybit);
-
-			cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
-			cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
-
-			input_register_device(cobra->dev + i);
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				cobra->dev[i].number, cobra_name, gameport->number, i);
-		}
-
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:	kfree(cobra);
-}
-
-static void cobra_disconnect(struct gameport *gameport)
-{
-	int i;
-
-	struct cobra *cobra = gameport->private;
-	for (i = 0; i < 2; i++)
-		if ((cobra->exists >> i) & 1)
-			input_unregister_device(cobra->dev + i);
-	gameport_close(gameport);
-	kfree(cobra);
-}
-
-static struct gameport_dev cobra_dev = {
-	connect:	cobra_connect,
-	disconnect:	cobra_disconnect,
-};
-
-int __init cobra_init(void)
-{
-	gameport_register_device(&cobra_dev);
-	return 0;
-}
-
-void __exit cobra_exit(void)
-{
-	gameport_unregister_device(&cobra_dev);
-}
-
-module_init(cobra_init);
-module_exit(cobra_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/cs461x.c b/drivers/char/joystick/cs461x.c
--- a/drivers/char/joystick/cs461x.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,331 +0,0 @@
-/*
-	The all defines and part of code (such as cs461x_*) are 
-	contributed from ALSA 0.5.8 sources. 
-	See http://www.alsa-project.org/ for sources
-	
-	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
-MODULE_LICENSE("GPL");
-
-/*
-	These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-#define COOKED_MODE
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS            0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT                                0x00000480
-#define BA0_JSCTL                               0x00000484
-#define BA0_JSC1                                0x00000488
-#define BA0_JSC2                                0x0000048C
-#define BA0_JSIO                                0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX                                0x00000001
-#define JSPT_CAY                                0x00000002
-#define JSPT_CBX                                0x00000004
-#define JSPT_CBY                                0x00000008
-#define JSPT_BA1                                0x00000010
-#define JSPT_BA2                                0x00000020
-#define JSPT_BB1                                0x00000040
-#define JSPT_BB2                                0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK                           0x00000003
-#define JSCTL_SP_SLOW                           0x00000000
-#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
-#define JSCTL_SP_MEDIUM_FAST                    0x00000002
-#define JSCTL_SP_FAST                           0x00000003
-#define JSCTL_ARE                               0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK                           0x0000FFFF
-#define JSC1_X1V_MASK                           0xFFFF0000
-#define JSC1_Y1V_SHIFT                          0
-#define JSC1_X1V_SHIFT                          16
-#define JSC2_Y2V_MASK                           0x0000FFFF
-#define JSC2_X2V_MASK                           0xFFFF0000
-#define JSC2_Y2V_SHIFT                          0
-#define JSC2_X2V_SHIFT                          16
-
-/* JS GPIO */
-
-#define JSIO_DAX                                0x00000001
-#define JSIO_DAY                                0x00000002
-#define JSIO_DBX                                0x00000004
-#define JSIO_DBY                                0x00000008
-#define JSIO_AXOE                               0x00000010
-#define JSIO_AYOE                               0x00000020
-#define JSIO_BXOE                               0x00000040
-#define JSIO_BYOE                               0x00000080
-
-/* 
-   The card initialization code is obfuscated; the module cs461x 
-   need to be loaded after ALSA modules initialized and something
-   played on the CS 4610 chip (see sources for details of CS4610
-   initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE         0x2000
-#define CS461X_BA1_DATA0_SIZE   0x3000
-#define CS461X_BA1_DATA1_SIZE   0x3800
-#define CS461X_BA1_PRG_SIZE     0x7000
-#define CS461X_BA1_REG_SIZE     0x0100
-
-#define BA1_SP_DMEM0                            0x00000000
-#define BA1_SP_DMEM1                            0x00010000
-#define BA1_SP_PMEM                             0x00020000
-#define BA1_SP_REG                              0x00030000
-
-#define BA1_DWORD_SIZE          (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT        3
-
-/* 
-   Only one CS461x card is still suppoted; the code requires
-   redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
-        struct {
-                unsigned int *data0;
-                unsigned int *data1;
-                unsigned int *pmem;
-                unsigned int *reg;
-        } name;
-        unsigned int *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
-        ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
-        return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
-        ba0[reg >> 2] = val;
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
-        return ba0[reg >> 2];
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
-	struct gameport *port = pci_get_drvdata(pdev);
-	if(port){
-	    gameport_unregister_port(port);
-	    kfree(port);
-	}    
-	if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
-	if (ba1.name.data0) iounmap(ba1.name.data0);
-	if (ba1.name.data1) iounmap(ba1.name.data1);
-	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
-	if (ba1.name.reg)   iounmap(ba1.name.reg);
-#endif
-	return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
-	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
-	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-	unsigned js1, js2, jst;
-	
-	js1 = cs461x_peekBA0(BA0_JSC1);
-	js2 = cs461x_peekBA0(BA0_JSC2);
-	jst = cs461x_peekBA0(BA0_JSPT);
-	
-	*buttons = (~jst >> 4) & 0x0F; 
-	
-	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
-	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
-	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
-	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
-	for(jst=0;jst<4;++jst)
-		if(axes[jst]==0xFFFF) axes[jst] = -1;
-	return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
-	switch (mode) {
-#ifdef COOKED_MODE
-	case GAMEPORT_MODE_COOKED:
-		return 0;
-#endif
-	case GAMEPORT_MODE_RAW:
-		return 0;
-	default:
-		return -1;
-	}
-	return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
-	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
-	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
-	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int rc;
-	struct gameport* port;
-	
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
-			pdev->bus->number, pdev->devfn, rc);
-		return rc;
-	}
-
-	ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
-	ba1_addr = pci_resource_start(pdev, 1);
-#endif
-	if (ba0_addr == 0 || ba0_addr == ~0 
-#ifdef CS461X_FULL_MAP
-            || ba1_addr == 0 || ba1_addr == ~0
-#endif
-	    ) {
-                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
-                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
-		cs461x_free(pdev);
-                return -ENOMEM;
-        }
-
-	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
-	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
-	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
-	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
-	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
-	if (ba0 == NULL || ba1.name.data0 == NULL ||
-            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
-            ba1.name.reg == NULL) {
-		cs461x_free(pdev);
-                return -ENOMEM;
-        }
-#else
-	if (ba0 == NULL){
-		cs461x_free(pdev);
-		return -ENOMEM;
-	}
-#endif
-	printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
-	    ba0_addr, CS461X_BA0_SIZE);
-        
-	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
-		cs461x_free(pdev);
-		return -ENOMEM;
-	}
-	memset(port, 0, sizeof(struct gameport));
-
-	pci_set_drvdata(pdev, port);
-	
-	port->open = cs461x_gameport_open;
-	port->read = cs461x_gameport_read;
-	port->trigger = cs461x_gameport_trigger;
-#ifdef COOKED_MODE
-	port->cooked_read = cs461x_gameport_cooked_read;
-#endif
-
-	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
-	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
-	gameport_register_port(port);
-
-	printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
-		port->number, port->speed);
-
-	return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
-	cs461x_free(pdev);
-}
-	
-static struct pci_driver cs461x_pci_driver = {
-        name:           "PCI Gameport",
-        id_table:       cs461x_pci_tbl,
-        probe:          cs461x_pci_probe,
-        remove:         cs461x_pci_remove,
-};
-
-int __init js_cs461x_init(void)
-{
-        return pci_module_init(&cs461x_pci_driver);
-}
-
-void __exit js_cs461x_exit(void)
-{
-        pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(js_cs461x_init);
-module_exit(js_cs461x_exit);
-
diff -Nru a/drivers/char/joystick/db9.c b/drivers/char/joystick/db9.c
--- a/drivers/char/joystick/db9.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,424 +0,0 @@
-/*
- * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $
- *
- *  Copyright (c) 1999 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Andree Borrmann		Mats Sjövall
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(db9, "2i");
-MODULE_PARM(db9_2, "2i");
-MODULE_PARM(db9_3, "2i");
-
-#define DB9_MULTI_STICK		0x01
-#define DB9_MULTI2_STICK	0x02
-#define DB9_GENESIS_PAD		0x03
-#define DB9_GENESIS5_PAD	0x05
-#define DB9_GENESIS6_PAD	0x06
-#define DB9_SATURN_PAD		0x07
-#define DB9_MULTI_0802		0x08
-#define DB9_MULTI_0802_2	0x09
-#define DB9_CD32_PAD		0x0A
-#define DB9_MAX_PAD		0x0B
-
-#define DB9_UP			0x01
-#define DB9_DOWN		0x02
-#define DB9_LEFT		0x04
-#define DB9_RIGHT		0x08
-#define DB9_FIRE1		0x10
-#define DB9_FIRE2		0x20
-#define DB9_FIRE3		0x40
-#define DB9_FIRE4		0x80
-
-#define DB9_NORMAL		0x0a
-#define DB9_NOSELECT		0x08
-
-#define DB9_SATURN0		0x00
-#define DB9_SATURN1		0x02
-#define DB9_SATURN2		0x04
-#define DB9_SATURN3		0x06
-
-#define DB9_GENESIS6_DELAY	14
-#define DB9_REFRESH_TIME	HZ/100
-
-static int db9[] __initdata = { -1, 0 };
-static int db9_2[] __initdata = { -1, 0 };
-static int db9_3[] __initdata = { -1, 0 };
-
-struct db9 {
-	struct input_dev dev[2];
-	struct timer_list timer;
-	struct pardevice *pd;	
-	int mode;
-	int used;
-};
-
-static struct db9 *db9_base[3];
-
-static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
-static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
-static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
-
-static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
-static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
-					db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
-static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
-				      NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
-				     "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
-
-static void db9_timer(unsigned long private)
-{
-	struct db9 *db9 = (void *) private;
-	struct parport *port = db9->pd->port;
-	struct input_dev *dev = db9->dev;
-	int data, i;
-
-	switch(db9->mode) {
-		case DB9_MULTI_0802_2:
-
-			data = parport_read_data(port) >> 3;
-
-			input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
-
-		case DB9_MULTI_0802:
-
-			data = parport_read_status(port) >> 3;
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
-			break;
-
-		case DB9_MULTI_STICK:
-
-			data = parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
-			break;
-
-		case DB9_MULTI2_STICK:
-
-			data = parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_THUMB,   ~data & DB9_FIRE2);
-			break;
-
-		case DB9_GENESIS_PAD:
-
-			parport_write_control(port, DB9_NOSELECT);
-			data = parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
-			parport_write_control(port, DB9_NORMAL);
-			data=parport_read_data(port);
-
-			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
-			break;
-
-		case DB9_GENESIS5_PAD:
-
-			parport_write_control(port, DB9_NOSELECT);
-			data=parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
-			parport_write_control(port, DB9_NORMAL);
-			data=parport_read_data(port);
-
-			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_X,     ~data & DB9_FIRE2);
-			input_report_key(dev, BTN_Y,     ~data & DB9_LEFT);
-			input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
-			break;
-
-		case DB9_GENESIS6_PAD:
-
-			parport_write_control(port, DB9_NOSELECT); /* 1 */
-			udelay(DB9_GENESIS6_DELAY);
-			data=parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
-			parport_write_control(port, DB9_NORMAL);
-			udelay(DB9_GENESIS6_DELAY);
-			data=parport_read_data(port);
-
-			input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
-			input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
-
-			parport_write_control(port, DB9_NOSELECT); /* 2 */
-			udelay(DB9_GENESIS6_DELAY);
-			parport_write_control(port, DB9_NORMAL);
-			udelay(DB9_GENESIS6_DELAY);
-			parport_write_control(port, DB9_NOSELECT); /* 3 */
-			udelay(DB9_GENESIS6_DELAY);
-			data=parport_read_data(port);
-
-			input_report_key(dev, BTN_Y,     ~data & DB9_LEFT);
-			input_report_key(dev, BTN_Z,     ~data & DB9_DOWN);
-			input_report_key(dev, BTN_MODE,  ~data & DB9_UP);
-			input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
-
-			parport_write_control(port, DB9_NORMAL);
-			udelay(DB9_GENESIS6_DELAY);
-			parport_write_control(port, DB9_NOSELECT); /* 4 */
-			udelay(DB9_GENESIS6_DELAY);
-			parport_write_control(port, DB9_NORMAL);
-			break;
-
-		case DB9_SATURN_PAD:
-
-			parport_write_control(port, DB9_SATURN0);
-			data = parport_read_data(port);
-
-			input_report_key(dev, BTN_Y,  ~data & DB9_LEFT);
-			input_report_key(dev, BTN_Z,  ~data & DB9_DOWN);
-			input_report_key(dev, BTN_TL, ~data & DB9_UP);
-			input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
-
-			parport_write_control(port, DB9_SATURN2);
-			data = parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-			
-			parport_write_control(port, DB9_NORMAL);
-			data = parport_read_data(port);
-
-			input_report_key(dev, BTN_A, ~data & DB9_LEFT);
-			input_report_key(dev, BTN_B, ~data & DB9_UP);
-			input_report_key(dev, BTN_C, ~data & DB9_DOWN);
-			input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
-			break;
-
-		case DB9_CD32_PAD:
-
-			data=parport_read_data(port);
-
-			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
-			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
-
-			parport_write_control(port, 0x0a); 
-
-			for (i = 0; i < 7; i++) { 
-				data = parport_read_data(port);
-				parport_write_control(port, 0x02); 
-				parport_write_control(port, 0x0a); 
-				input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
-				}
-
-			parport_write_control(port, 0x00); 
-			break;
-		}
-
-	mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
-}
-
-static int db9_open(struct input_dev *dev)
-{
-	struct db9 *db9 = dev->private;
-	struct parport *port = db9->pd->port;
-
-	if (!db9->used++) {
-		parport_claim(db9->pd);
-		parport_write_data(port, 0xff);
-		parport_data_reverse(port);
-		parport_write_control(port, DB9_NORMAL);
-		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
-	}
-
-	return 0;
-}
-
-static void db9_close(struct input_dev *dev)
-{
-	struct db9 *db9 = dev->private;
-	struct parport *port = db9->pd->port;
-
-	if (!--db9->used) {
-		del_timer(&db9->timer);
-		parport_write_control(port, 0x00);
-		parport_data_forward(port);
-		parport_release(db9->pd);
-	}
-}
-
-static struct db9 __init *db9_probe(int *config)
-{
-	struct db9 *db9;
-	struct parport *pp;
-	int i, j;
-
-	if (config[0] < 0)
-		return NULL;
-	if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
-		printk(KERN_ERR "db9.c: bad config\n");
-		return NULL;
-	}
-
-	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
-		config[0]--;
-
-	if (!pp) {
-		printk(KERN_ERR "db9.c: no such parport\n");
-		return NULL;
-	}
-
-	if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
-		printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
-		return NULL;
-	}
-	
-	if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
-		return NULL;
-	memset(db9, 0, sizeof(struct db9));
-
-	db9->mode = config[1];
-	init_timer(&db9->timer);
-	db9->timer.data = (long) db9;
-	db9->timer.function = db9_timer;
-
-	db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
-	if (!db9->pd) {
-		printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
-		kfree(db9);
-		return NULL;
-	}
-
-	for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
-
-		db9->dev[i].private = db9;
-		db9->dev[i].open = db9_open;
-		db9->dev[i].close = db9_close;
-
-		db9->dev[i].name = db9_name[db9->mode];
-		db9->dev[i].idbus = BUS_PARPORT;
-		db9->dev[i].idvendor = 0x0002;
-		db9->dev[i].idproduct = config[1];
-		db9->dev[i].idversion = 0x0100;
-
-		db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-		db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
-		for (j = 0; j < db9_buttons[db9->mode]; j++)
-			set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); 
-
-		db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
-		db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
-
-		input_register_device(db9->dev + i);
-		printk(KERN_INFO "input%d: %s on %s\n",
-			db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
-	}
-
-	return db9;
-}
-
-#ifndef MODULE
-int __init db9_setup(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
-	return 1;
-}
-int __init db9_setup_2(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
-	return 1;
-}
-int __init db9_setup_3(char *str)
-{
-	int i, ints[3];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
-	return 1;
-}
-__setup("db9=", db9_setup);
-__setup("db9_2=", db9_setup_2);
-__setup("db9_3=", db9_setup_3);
-#endif
-
-int __init db9_init(void)
-{
-	db9_base[0] = db9_probe(db9);
-	db9_base[1] = db9_probe(db9_2);
-	db9_base[2] = db9_probe(db9_3);
-
-	if (db9_base[0] || db9_base[1] || db9_base[2])
-		return 0;
-
-	return -ENODEV;
-}
-
-void __exit db9_exit(void)
-{
-	int i, j;
-
-	for (i = 0; i < 3; i++) 
-		if (db9_base[i]) {
-			for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
-				input_unregister_device(db9_base[i]->dev + j);
-		parport_unregister_device(db9_base[i]->pd);
-	}
-}
-
-module_init(db9_init);
-module_exit(db9_exit);
diff -Nru a/drivers/char/joystick/emu10k1-gp.c b/drivers/char/joystick/emu10k1-gp.c
--- a/drivers/char/joystick/emu10k1-gp.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,125 +0,0 @@
-/*
- * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
- *
- *  Copyright (c) 2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * EMU10k1 - SB Live! - gameport driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-struct emu {
-	struct pci_dev *dev;
-	struct emu *next;
-	struct gameport gameport;
-	int size;
-};
-	
-static struct pci_device_id emu_tbl[] __devinitdata = {
-	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, emu_tbl);
-
-static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int ioport, iolen;
-	int rc;
-	struct emu *port;
-        
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
-			pdev->bus->number, pdev->devfn, rc);
-		return rc;
-	}
-
-	ioport = pci_resource_start(pdev, 0);
-	iolen = pci_resource_len(pdev, 0);
-
-	if (!request_region(ioport, iolen, "emu10k1-gp"))
-		return -EBUSY;
-
-	if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
-		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
-		release_region(ioport, iolen);
-		return -ENOMEM;
-	}
-	memset(port, 0, sizeof(struct emu));
-
-	port->gameport.io = ioport;
-	port->size = iolen;
-	port->dev = pdev;
-	pci_set_drvdata(pdev, port);
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
-		port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
-
-	return 0;
-}
-
-static void __devexit emu_remove(struct pci_dev *pdev)
-{
-	struct emu *port = pci_get_drvdata(pdev);
-	gameport_unregister_port(&port->gameport);
-	release_region(port->gameport.io, port->size);
-	kfree(port);
-}
-
-static struct pci_driver emu_driver = {
-        name:           "Emu10k1 Gameport",
-        id_table:       emu_tbl,
-        probe:          emu_probe,
-        remove:         emu_remove,
-};
-
-int __init emu_init(void)
-{
-	return pci_module_init(&emu_driver);
-}
-
-void __exit emu_exit(void)
-{
-	pci_unregister_driver(&emu_driver);
-}
-
-module_init(emu_init);
-module_exit(emu_exit);
diff -Nru a/drivers/char/joystick/gamecon.c b/drivers/char/joystick/gamecon.c
--- a/drivers/char/joystick/gamecon.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,670 +0,0 @@
-/*
- * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *  	Andree Borrmann		John Dahlstrom
- *  	David Kuder		Nathan Hand
- *
- *  Sponsored by SuSE
- */
-
-/*
- * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(gc, "2-6i");
-MODULE_PARM(gc_2,"2-6i");
-MODULE_PARM(gc_3,"2-6i");
-
-#define GC_SNES		1
-#define GC_NES		2
-#define GC_NES4		3
-#define GC_MULTI	4
-#define GC_MULTI2	5
-#define GC_N64		6	
-#define GC_PSX		7
-
-#define GC_MAX		7
-
-#define GC_REFRESH_TIME	HZ/100
- 
-struct gc {
-	struct pardevice *pd;
-	struct input_dev dev[5];
-	struct timer_list timer;
-	unsigned char pads[GC_MAX + 1];
-	int used;
-};
-
-static struct gc *gc_base[3];
-
-static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
-
-static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
-
-static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
-				"Multisystem 2-button joystick", "N64 controller", "PSX controller" };
-/*
- * N64 support.
- */
-
-static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
-static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
-
-#define GC_N64_LENGTH		32		/* N64 bit length, not including stop bit */
-#define GC_N64_REQUEST_LENGTH	37		/* transmit request sequence is 9 bits long */
-#define GC_N64_DELAY		133		/* delay between transmit request, and response ready (us) */
-#define GC_N64_REQUEST		0x1dd1111111ULL /* the request data command (encoded for 000000011) */
-#define GC_N64_DWS		3		/* delay between write segments (required for sound playback because of ISA DMA) */
-						/* GC_N64_DWS > 24 is known to fail */ 
-#define GC_N64_POWER_W		0xe2		/* power during write (transmit request) */
-#define GC_N64_POWER_R		0xfd		/* power during read */
-#define GC_N64_OUT		0x1d		/* output bits to the 4 pads */
-						/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
-						/* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
-						/* than 123 us */
-#define GC_N64_CLOCK		0x02		/* clock bits for read */
-
-/* 
- * gc_n64_read_packet() reads an N64 packet. 
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
- */
-
-static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
-{
-	int i;
-	unsigned long flags;
-
-/*
- * Request the pad to transmit data
- */
-
-	__save_flags(flags);
-	__cli();
-	for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
-		parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
-		udelay(GC_N64_DWS);
-	}
-	__restore_flags(flags);
-
-/*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
- */
-
-	udelay(GC_N64_DELAY);
-
-/*
- * Grab data (ignoring the last bit, which is a stop bit)
- */
-
-	for (i = 0; i < GC_N64_LENGTH; i++) {
-		parport_write_data(gc->pd->port, GC_N64_POWER_R);
-		data[i] = parport_read_status(gc->pd->port);
-		parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
-	 }
-
-/*
- * We must wait 200 ms here for the controller to reinitialize before the next read request.
- * No worries as long as gc_read is polled less frequently than this.
- */
-
-}
-
-/*
- * NES/SNES support.
- */
-
-#define GC_NES_DELAY	6	/* Delay between bits - 6us */
-#define GC_NES_LENGTH	8	/* The NES pads use 8 bits of data */
-#define GC_SNES_LENGTH	12	/* The SNES true length is 16, but the last 4 bits are unused */
-
-#define GC_NES_POWER	0xfc
-#define GC_NES_CLOCK	0x01
-#define GC_NES_LATCH	0x02
-
-static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
-static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
-static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
-
-/*
- * gc_nes_read_packet() reads a NES/SNES packet.
- * Each pad uses one bit per byte. So all pads connected to
- * this port are read in parallel.
- */
-
-static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
-{
-	int i;
-
-	parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
-	udelay(GC_NES_DELAY * 2);
-	parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
-
-	for (i = 0; i < length; i++) {
-		udelay(GC_NES_DELAY);
-		parport_write_data(gc->pd->port, GC_NES_POWER);
-		data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
-		udelay(GC_NES_DELAY);
-		parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
-	}
-}
-
-/*
- * Multisystem joystick support
- */
-
-#define GC_MULTI_LENGTH		5	/* Multi system joystick packet length is 5 */
-#define GC_MULTI2_LENGTH	6	/* One more bit for one more button */
-
-/*
- * gc_multi_read_packet() reads a Multisystem joystick packet.
- */
-
-static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
-{
-	int i;
-
-	for (i = 0; i < length; i++) {
-		parport_write_data(gc->pd->port, ~(1 << i));
-		data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
-	}
-}
-
-/*
- * PSX support
- *
- * See documentation at:
- *	http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
- *	http://www.gamesx.com/controldata/psxcont/psxcont.htm
- *	ftp://milano.usal.es/pablo/
- *	
- */
-
-#define GC_PSX_DELAY	60		/* 60 usec */
-#define GC_PSX_LENGTH	8		/* talk to the controller in bytes */
-
-#define GC_PSX_MOUSE	1		/* Mouse */
-#define GC_PSX_NEGCON	2		/* NegCon */
-#define GC_PSX_NORMAL	4		/* Digital / Analog or Rumble in Digital mode  */
-#define GC_PSX_ANALOG	5		/* Analog in Analog mode / Rumble in Green mode */
-#define GC_PSX_RUMBLE	7		/* Rumble in Red mode */
-
-#define GC_PSX_CLOCK	0x04		/* Pin 4 */
-#define GC_PSX_COMMAND	0x01		/* Pin 1 */
-#define GC_PSX_POWER	0xf8		/* Pins 5-9 */
-#define GC_PSX_SELECT	0x02		/* Pin 3 */
-
-#define GC_PSX_ID(x)	((x) >> 4)	/* High nibble is device type */
-#define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
-
-static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
-static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
-				BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
-
-/*
- * gc_psx_command() writes 8bit command and reads 8bit data from
- * the psx pad.
- */
-
-static int gc_psx_command(struct gc *gc, int b)
-{
-	int i, cmd, data = 0;
-
-	for (i = 0; i < 8; i++, b >>= 1) {
-		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
-		parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
-		udelay(GC_PSX_DELAY);
-		data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
-		parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
-		udelay(GC_PSX_DELAY);
-	}
-	return data;
-}
-
-/*
- * gc_psx_read_packet() reads a whole psx packet and returns
- * device identifier code.
- */
-
-static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
-{
-	int i, id;
-	unsigned long flags;
-
-	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);	/* Select pad */
-	udelay(GC_PSX_DELAY * 2);
-	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);			/* Deselect, begin command */
-	udelay(GC_PSX_DELAY * 2);
-
-	__save_flags(flags);
-	__cli();
-
-	gc_psx_command(gc, 0x01);							/* Access pad */
-	id = gc_psx_command(gc, 0x42);							/* Get device id */
-	if (gc_psx_command(gc, 0) == 0x5a) {						/* Okay? */
-		for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
-			data[i] = gc_psx_command(gc, 0);
-	} else id = 0;
-
-	__restore_flags(flags);
-
-	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
-
-	return GC_PSX_ID(id);
-}
-
-/*
- * gc_timer() reads and analyzes console pads data.
- */
-
-#define GC_MAX_LENGTH GC_N64_LENGTH
-
-static void gc_timer(unsigned long private)
-{
-	struct gc *gc = (void *) private;
-	struct input_dev *dev = gc->dev;
-	unsigned char data[GC_MAX_LENGTH];
-	int i, j, s;
-
-/*
- * N64 pads - must be read first, any read confuses them for 200 us
- */
-
-	if (gc->pads[GC_N64]) {
-
-		gc_n64_read_packet(gc, data);
-
-		for (i = 0; i < 5; i++) {
-
-			s = gc_status_bit[i];
-
-			if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
-	
-				signed char axes[2];
-				axes[0] = axes[1] = 0;
-
-				for (j = 0; j < 8; j++) {
-					if (data[23 - j] & s) axes[0] |= 1 << j; 
-					if (data[31 - j] & s) axes[1] |= 1 << j; 
-				}
-
-				input_report_abs(dev + i, ABS_X,  axes[0]);
-				input_report_abs(dev + i, ABS_Y, -axes[1]);
-
-				input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
-				input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
-
-				for (j = 0; j < 10; j++)
-					input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
-			}
-		}
-	}
-
-/*
- * NES and SNES pads
- */
-
-	if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
-
-		gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
-
-		for (i = 0; i < 5; i++) {
-
-			s = gc_status_bit[i];
-
-			if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
-				input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
-				input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
-			}
-
-			if (s & gc->pads[GC_NES])
-				for (j = 0; j < 4; j++)
-					input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
-
-			if (s & gc->pads[GC_SNES])
-				for (j = 0; j < 8; j++)
-					input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
-		}
-	}
-
-/*
- * Multi and Multi2 joysticks
- */
-
-	if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
-
-		gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
-
-		for (i = 0; i < 5; i++) {
-
-			s = gc_status_bit[i];
-
-			if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
-				input_report_abs(dev + i, ABS_X,  !(s & data[2]) - !(s & data[3]));
-				input_report_abs(dev + i, ABS_Y,  !(s & data[0]) - !(s & data[1]));
-				input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
-			}
-
-			if (s & gc->pads[GC_MULTI2])
-				input_report_key(dev + i, BTN_THUMB, s & data[5]);
-		}
-	}
-
-/*
- * PSX controllers
- */
-
-	if (gc->pads[GC_PSX]) {
-
-		for (i = 0; i < 5; i++)
-	       		if (gc->pads[GC_PSX] & gc_status_bit[i])
-				break;
-
- 		switch (gc_psx_read_packet(gc, data)) {
-
-			case GC_PSX_RUMBLE:
-
-				input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
-				input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
-
-			case GC_PSX_NEGCON:
-			case GC_PSX_ANALOG:
-
-				for (j = 0; j < 4; j++)
-					input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
-
-				input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
-				input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
-
-				for (j = 0; j < 8; j++)
-					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
-
-				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
-				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
-
-				break;
-
-			case GC_PSX_NORMAL:
-
-				input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
-				input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
-
-				for (j = 0; j < 8; j++)
-					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
-
-				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
-				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
-
-				break;
-		}
-	}
-
-	mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
-}
-
-static int gc_open(struct input_dev *dev)
-{
-	struct gc *gc = dev->private;
-	if (!gc->used++) {
-		parport_claim(gc->pd);
-		parport_write_control(gc->pd->port, 0x04);
-		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
-	}
-	return 0;
-}
-
-static void gc_close(struct input_dev *dev)
-{
-	struct gc *gc = dev->private;
-	if (!--gc->used) {
-		del_timer(&gc->timer);
-		parport_write_control(gc->pd->port, 0x00);
-		parport_release(gc->pd);
-	}
-}
-
-static struct gc __init *gc_probe(int *config)
-{
-	struct gc *gc;
-	struct parport *pp;
-	int i, j, psx;
-	unsigned char data[32];
-
-	if (config[0] < 0)
-		return NULL;
-
-	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
-		config[0]--;
-
-	if (!pp) {
-		printk(KERN_ERR "gamecon.c: no such parport\n");
-		return NULL;
-	}
-
-	if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
-		return NULL;
-	memset(gc, 0, sizeof(struct gc));
-
-	gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
-	if (!gc->pd) {
-		printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
-		kfree(gc);
-		return NULL;
-	}
-
-	parport_claim(gc->pd);
-
-	init_timer(&gc->timer);
-	gc->timer.data = (long) gc;
-	gc->timer.function = gc_timer;
-
-	for (i = 0; i < 5; i++) {
-
-		if (!config[i + 1])
-			continue;
-
-		if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
-			printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
-			continue;
-		}
-
-                gc->dev[i].private = gc;
-                gc->dev[i].open = gc_open;
-                gc->dev[i].close = gc_close;
-
-                gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-		for (j = 0; j < 2; j++) {
-			set_bit(ABS_X + j, gc->dev[i].absbit);
-			gc->dev[i].absmin[ABS_X + j] = -1;
-			gc->dev[i].absmax[ABS_X + j] =  1;
-		}
-
-		gc->pads[0] |= gc_status_bit[i];
-		gc->pads[config[i + 1]] |= gc_status_bit[i];
-
-		switch(config[i + 1]) {
-
-			case GC_N64:
-				for (j = 0; j < 10; j++)
-					set_bit(gc_n64_btn[j], gc->dev[i].keybit);
-
-				for (j = 0; j < 2; j++) {
-					set_bit(ABS_X + j, gc->dev[i].absbit);
-					gc->dev[i].absmin[ABS_X + j] = -127;
-					gc->dev[i].absmax[ABS_X + j] =  126;
-					gc->dev[i].absflat[ABS_X + j] = 2;
-					set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
-					gc->dev[i].absmin[ABS_HAT0X + j] = -1;
-					gc->dev[i].absmax[ABS_HAT0X + j] =  1;
-				}
-
-				break;
-
-			case GC_SNES:
-				for (j = 4; j < 8; j++)
-					set_bit(gc_snes_btn[j], gc->dev[i].keybit);
-			case GC_NES:
-				for (j = 0; j < 4; j++)
-					set_bit(gc_snes_btn[j], gc->dev[i].keybit);
-				break;
-
-			case GC_MULTI2:
-				set_bit(BTN_THUMB, gc->dev[i].keybit);
-			case GC_MULTI:
-				set_bit(BTN_TRIGGER, gc->dev[i].keybit);
-				break;
-
-			case GC_PSX:
-				
-				psx = gc_psx_read_packet(gc, data);
-
-				switch(psx) {
-					case GC_PSX_NEGCON:
-					case GC_PSX_NORMAL:
-					case GC_PSX_ANALOG:
-					case GC_PSX_RUMBLE:
-
-						for (j = 0; j < 6; j++) {
-							psx = gc_psx_abs[j];
-							set_bit(psx, gc->dev[i].absbit);
-							if (j < 4) {
-								gc->dev[i].absmin[psx] = 4;
-								gc->dev[i].absmax[psx] = 252;
-								gc->dev[i].absflat[psx] = 2;
-							} else {
-								gc->dev[i].absmin[psx] = -1;
-								gc->dev[i].absmax[psx] = 1;
-							}
-						}
-
-						for (j = 0; j < 12; j++)
-							set_bit(gc_psx_btn[j], gc->dev[i].keybit);
-
-						break;
-
-					case 0:
-						gc->pads[GC_PSX] &= ~gc_status_bit[i];
-						printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
-						break;
-
-					default:
-						gc->pads[GC_PSX] &= ~gc_status_bit[i];
-						printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
-							" please report to <vojtech@suse.cz>.\n", psx);
-				}
-				break;
-		}
-
-                gc->dev[i].name = gc_names[config[i + 1]];
-                gc->dev[i].idbus = BUS_PARPORT;
-                gc->dev[i].idvendor = 0x0001;
-                gc->dev[i].idproduct = config[i + 1];
-                gc->dev[i].idversion = 0x0100;
-	}
-
-	parport_release(gc->pd);
-
-	if (!gc->pads[0]) {
-		parport_unregister_device(gc->pd);
-		kfree(gc);
-		return NULL;
-	}
-
-	for (i = 0; i < 5; i++) 
-		if (gc->pads[0] & gc_status_bit[i]) {
-			input_register_device(gc->dev + i);
-			printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
-		}
-
-	return gc;
-}
-
-#ifndef MODULE
-int __init gc_setup(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
-	return 1;
-}
-int __init gc_setup_2(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
-	return 1;
-}
-int __init gc_setup_3(char *str)
-{
-	int i, ints[7];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
-	return 1;
-}
-__setup("gc=", gc_setup);
-__setup("gc_2=", gc_setup_2);
-__setup("gc_3=", gc_setup_3);
-#endif
-
-int __init gc_init(void)
-{
-	gc_base[0] = gc_probe(gc);
-	gc_base[1] = gc_probe(gc_2);
-	gc_base[2] = gc_probe(gc_3);
-
-	if (gc_base[0] || gc_base[1] || gc_base[2])
-		return 0;
-
-	return -ENODEV;
-}
-
-void __exit gc_exit(void)
-{
-	int i, j;
-
-	for (i = 0; i < 3; i++)
-		if (gc_base[i]) {
-			for (j = 0; j < 5; j++)
-				if (gc_base[i]->pads[0] & gc_status_bit[j])
-					input_unregister_device(gc_base[i]->dev + j); 
-			parport_unregister_device(gc_base[i]->pd);
-		}
-}
-
-module_init(gc_init);
-module_exit(gc_exit);
diff -Nru a/drivers/char/joystick/gameport.c b/drivers/char/joystick/gameport.c
--- a/drivers/char/joystick/gameport.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,199 +0,0 @@
-/*
- * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Generic gameport layer
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/isapnp.h>
-#include <linux/stddef.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(gameport_register_port);
-EXPORT_SYMBOL(gameport_unregister_port);
-EXPORT_SYMBOL(gameport_register_device);
-EXPORT_SYMBOL(gameport_unregister_device);
-EXPORT_SYMBOL(gameport_open);
-EXPORT_SYMBOL(gameport_close);
-EXPORT_SYMBOL(gameport_rescan);
-EXPORT_SYMBOL(gameport_cooked_read);
-
-static struct gameport *gameport_list;
-static struct gameport_dev *gameport_dev;
-static int gameport_number;
-
-/*
- * gameport_measure_speed() measures the gameport i/o speed.
- */
-
-static int gameport_measure_speed(struct gameport *gameport)
-{
-#if defined(__i386__) || defined(__x86_64__)
-
-#define GET_TIME(x)     do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
-#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193180L/HZ:0))
-
-	unsigned int i, t, t1, t2, t3, tx;
-	unsigned long flags;
-
-	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
-		return 0;
-
-	tx = 1 << 30;
-
-	for(i = 0; i < 50; i++) {
-		save_flags(flags);	/* Yes, all CPUs */
-		cli();
-		GET_TIME(t1);
-		for(t = 0; t < 50; t++) gameport_read(gameport);
-		GET_TIME(t2);
-		GET_TIME(t3);
-		restore_flags(flags);
-		udelay(i * 10);
-		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
-	}
-
-	return 59659 / (tx < 1 ? 1 : tx);
-
-#else
-
-	unsigned int j, t = 0;
-
-	j = jiffies; while (j == jiffies);
-	j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
-
-	return t * HZ / 1000;
-
-#endif
-
-	gameport_close(gameport);
-}
-
-static void gameport_find_dev(struct gameport *gameport)
-{
-        struct gameport_dev *dev = gameport_dev;
-
-        while (dev && !gameport->dev) {
-		if (dev->connect)
-                	dev->connect(gameport, dev);
-                dev = dev->next;
-        }
-}
-
-void gameport_rescan(struct gameport *gameport)
-{
-	gameport_close(gameport);
-	gameport_find_dev(gameport);
-}
-
-void gameport_register_port(struct gameport *gameport)
-{
-	gameport->number = gameport_number++;
-	gameport->next = gameport_list;	
-	gameport_list = gameport;
-
-	gameport->speed = gameport_measure_speed(gameport);
-
-	gameport_find_dev(gameport);
-}
-
-void gameport_unregister_port(struct gameport *gameport)
-{
-        struct gameport **gameportptr = &gameport_list;
-
-        while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
-        *gameportptr = (*gameportptr)->next;
-
-	if (gameport->dev && gameport->dev->disconnect)
-		gameport->dev->disconnect(gameport);
-
-	gameport_number--;
-}
-
-void gameport_register_device(struct gameport_dev *dev)
-{
-	struct gameport *gameport = gameport_list;
-
-	dev->next = gameport_dev;	
-	gameport_dev = dev;
-
-	while (gameport) {
-		if (!gameport->dev && dev->connect)
-			dev->connect(gameport, dev);
-		gameport = gameport->next;
-	}
-}
-
-void gameport_unregister_device(struct gameport_dev *dev)
-{
-        struct gameport_dev **devptr = &gameport_dev;
-	struct gameport *gameport = gameport_list;
-
-        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
-        *devptr = (*devptr)->next;
-
-	while (gameport) {
-		if (gameport->dev == dev && dev->disconnect)
-			dev->disconnect(gameport);
-		gameport_find_dev(gameport);
-		gameport = gameport->next;
-	}
-}
-
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
-{
-	if (gameport->open) {
-		if (gameport->open(gameport, mode))
-			return -1;
-	} else {
-		if (mode != GAMEPORT_MODE_RAW)
-			return -1;
-	}
-
-	if (gameport->dev)
-		return -1;
-
-	gameport->dev = dev;
-	
-	return 0;
-}
-
-void gameport_close(struct gameport *gameport)
-{
-	gameport->dev = NULL;
-	if (gameport->close) gameport->close(gameport);
-}
diff -Nru a/drivers/char/joystick/gf2k.c b/drivers/char/joystick/gf2k.c
--- a/drivers/char/joystick/gf2k.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,361 +0,0 @@
-/*
- * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Genius Flight 2000 joystick driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-
-#define GF2K_START		400	/* The time we wait for the first bit [400 us] */
-#define GF2K_STROBE		40	/* The time we wait for the first bit [40 us] */
-#define GF2K_TIMEOUT		4	/* Wait for everything to settle [4 ms] */
-#define GF2K_LENGTH		80	/* Max number of triplets in a packet */
-#define GF2K_REFRESH		HZ/50	/* Time between joystick polls [20 ms] */
-
-/*
- * Genius joystick ids ...
- */
-
-#define GF2K_ID_G09		1
-#define GF2K_ID_F30D		2
-#define GF2K_ID_F30		3
-#define GF2K_ID_F31D		4
-#define GF2K_ID_F305		5
-#define GF2K_ID_F23P		6
-#define GF2K_ID_F31		7
-#define GF2K_ID_MAX		7
-
-static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
-static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
-				"Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
-static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
-static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
-static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
-static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
-static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
-
-static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
-static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
-static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
-
-
-static short gf2k_seq_reset[] = { 240, 340, 0 };
-static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
-
-struct gf2k {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct input_dev dev;
-	int reads;
-	int bads;
-	int used;
-	unsigned char id;
-	unsigned char length;
-};
-
-/*
- * gf2k_read_packet() reads a Genius Flight2000 packet.
- */
-
-static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
-{
-	unsigned char u, v;
-	int i;
-	unsigned int t, p;
-	unsigned long flags;
-
-	t = gameport_time(gameport, GF2K_START);
-	p = gameport_time(gameport, GF2K_STROBE);
-
-	i = 0;
-
-	__save_flags(flags);
-	__cli();
-
-	gameport_trigger(gameport);
-	v = gameport_read(gameport);;
-
-	while (t > 0 && i < length) {
-		t--; u = v;
-		v = gameport_read(gameport);
-		if (v & ~u & 0x10) {
-			data[i++] = v >> 5;
-			t = p;
-		}
-	}
-
-	__restore_flags(flags);
-
-	return i;
-}
-
-/*
- * gf2k_trigger_seq() initializes a Genius Flight2000 joystick
- * into digital mode.
- */
-
-static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
-{
-
-	unsigned long flags;
-	int i, t;
-
-        __save_flags(flags);
-        __cli();
-
-	i = 0;
-        do {
-		gameport_trigger(gameport);
-		t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
-		while ((gameport_read(gameport) & 1) && t) t--;
-                udelay(seq[i]);
-        } while (seq[++i]);
-
-	gameport_trigger(gameport);
-
-	__restore_flags(flags);
-}
-
-/*
- * js_sw_get_bits() composes bits from the triplet buffer into a __u64.
- * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
- * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
- * is number of bits per triplet.
- */
-
-#define GB(p,n,s)	gf2k_get_bits(data, p, n, s)
-
-static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
-{
-	__u64 data = 0;
-	int i;
-
-	for (i = 0; i < num / 3 + 2; i++)
-		data |= buf[pos / 3 + i] << (i * 3);
-	data >>= pos % 3;
-	data &= (1 << num) - 1;
-	data <<= shift;
-
-	return data;
-}
-
-static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
-{
-	struct input_dev *dev = &gf2k->dev;
-	int i, t;
-
-	for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
-		input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
-
-	for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
-		input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
-
-	t = GB(40,4,0);
-
-	for (i = 0; i < gf2k_hats[gf2k->id]; i++)
-		input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
-
-	t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
-
-	for (i = 0; i < gf2k_joys[gf2k->id]; i++)
-		input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
-
-	for (i = 0; i < gf2k_pads[gf2k->id]; i++)
-		input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
-}
-
-/*
- * gf2k_timer() reads and analyzes Genius joystick data.
- */
-
-static void gf2k_timer(unsigned long private)
-{
-	struct gf2k *gf2k = (void *) private;
-	unsigned char data[GF2K_LENGTH];
-
-	gf2k->reads++;
-
-	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
-		gf2k->bads++;
-	} else gf2k_read(gf2k, data);
-
-	mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
-}
-
-static int gf2k_open(struct input_dev *dev)
-{
-	struct gf2k *gf2k = dev->private;
-	if (!gf2k->used++)
-		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);	
-	return 0;
-}
-
-static void gf2k_close(struct input_dev *dev)
-{
-	struct gf2k *gf2k = dev->private;
-	if (!--gf2k->used)
-		del_timer(&gf2k->timer);
-}
-
-/*
- * gf2k_connect() probes for Genius id joysticks.
- */
-
-static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct gf2k *gf2k;
-	unsigned char data[GF2K_LENGTH];
-	int i;
-
-	if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
-		return;
-	memset(gf2k, 0, sizeof(struct gf2k));
-
-	gameport->private = gf2k;
-
-	gf2k->gameport = gameport;
-	init_timer(&gf2k->timer);
-	gf2k->timer.data = (long) gf2k;
-	gf2k->timer.function = gf2k_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	gf2k_trigger_seq(gameport, gf2k_seq_reset);
-
-	wait_ms(GF2K_TIMEOUT);
-
-	gf2k_trigger_seq(gameport, gf2k_seq_digital);
-
-	wait_ms(GF2K_TIMEOUT);
-
-	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
-		goto fail2;
-
-	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
-		goto fail2;
-
-#ifdef RESET_WORKS
-	if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
-	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
-		goto fail2;
-#else
-	gf2k->id = 6;
-#endif
-
-	if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
-		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
-			gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
-		goto fail2;
-	}
-
-	gf2k->length = gf2k_lens[gf2k->id];
-
-	gf2k->dev.private = gf2k;
-	gf2k->dev.open = gf2k_open;
-	gf2k->dev.close = gf2k_close;
-	gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-	gf2k->dev.name = gf2k_names[gf2k->id];
-	gf2k->dev.idbus = BUS_GAMEPORT;
-	gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
-	gf2k->dev.idproduct = gf2k->id;
-	gf2k->dev.idversion = 0x0100;
-
-	for (i = 0; i < gf2k_axes[gf2k->id]; i++)
-		set_bit(gf2k_abs[i], gf2k->dev.absbit);
-
-	for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
-		set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
-		gf2k->dev.absmin[ABS_HAT0X + i] = -1;
-		gf2k->dev.absmax[ABS_HAT0X + i] = 1;
-	}
-
-	for (i = 0; i < gf2k_joys[gf2k->id]; i++)
-		set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
-
-	for (i = 0; i < gf2k_pads[gf2k->id]; i++)
-		set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
-
-	gf2k_read_packet(gameport, gf2k->length, data);
-	gf2k_read(gf2k, data);
-
-	for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
-		gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
-	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; 
-		gf2k->dev.absmin[gf2k_abs[i]] = 32;
-		gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
-		gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
-	}
-
-	input_register_device(&gf2k->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:	kfree(gf2k);
-}
-
-static void gf2k_disconnect(struct gameport *gameport)
-{
-	struct gf2k *gf2k = gameport->private;
-	input_unregister_device(&gf2k->dev);
-	gameport_close(gameport);
-	kfree(gf2k);
-}
-
-static struct gameport_dev gf2k_dev = {
-	connect:	gf2k_connect,
-	disconnect:	gf2k_disconnect,
-};
-
-int __init gf2k_init(void)
-{
-	gameport_register_device(&gf2k_dev);
-	return 0;
-}
-
-void __exit gf2k_exit(void)
-{
-	gameport_unregister_device(&gf2k_dev);
-}
-
-module_init(gf2k_init);
-module_exit(gf2k_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/grip.c b/drivers/char/joystick/grip.c
--- a/drivers/char/joystick/grip.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,425 +0,0 @@
-/*
- * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define GRIP_MODE_GPP		1
-#define GRIP_MODE_BD		2
-#define GRIP_MODE_XT		3
-#define GRIP_MODE_DC		4
-
-#define GRIP_LENGTH_GPP		24
-#define GRIP_STROBE_GPP		200	/* 200 us */
-#define GRIP_LENGTH_XT		4
-#define GRIP_STROBE_XT		64	/* 64 us */
-#define GRIP_MAX_CHUNKS_XT	10	
-#define GRIP_MAX_BITS_XT	30	
-
-#define GRIP_REFRESH_TIME	HZ/50	/* 20 ms */
-
-struct grip {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct input_dev dev[2];
-	unsigned char mode[2];
-	int used;
-	int reads;
-	int bads;
-};
-
-static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
-static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
-static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
-static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
-
-static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
-static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
-static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-
-static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
-				"Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
-static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
-static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
-static char grip_anx[] = { 0, 0, 3, 5, 5 };
-static char grip_cen[] = { 0, 0, 2, 2, 4 };
-
-/*
- * grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
- */
-
-static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
-{
-	unsigned long flags;
-	unsigned char u, v;
-	unsigned int t;
-	int i;
-
-	int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
-
-	data[0] = 0;
-	t = strobe;
-	i = 0;
-
-	__save_flags(flags);
-	__cli();
-
-	v = gameport_read(gameport) >> shift;
-
-	do {
-		t--;
-		u = v; v = (gameport_read(gameport) >> shift) & 3;
-		if (~v & u & 1) {
-			data[0] |= (v >> 1) << i++;
-			t = strobe;
-		}
-	} while (i < GRIP_LENGTH_GPP && t > 0);
-
-	__restore_flags(flags);
-
-	if (i < GRIP_LENGTH_GPP) return -1;
-
-	for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
-		data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
-
-	return -(i == GRIP_LENGTH_GPP);
-}
-
-/*
- * grip_xt_read_packet() reads a Gravis Xterminator packet.
- */
-
-static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
-{
-	unsigned int i, j, buf, crc;
-	unsigned char u, v, w;
-	unsigned long flags;
-	unsigned int t;
-	char status;
-
-	int strobe = gameport_time(gameport, GRIP_STROBE_XT);
-
-	data[0] = data[1] = data[2] = data[3] = 0;
-	status = buf = i = j = 0;
-	t = strobe;
-
-	__save_flags(flags);
-	__cli();
-
-	v = w = (gameport_read(gameport) >> shift) & 3;
-
-	do {
-		t--;
-		u = (gameport_read(gameport) >> shift) & 3;
-
-		if (u ^ v) {
-
-			if ((u ^ v) & 1) {
-				buf = (buf << 1) | (u >> 1);
-				t = strobe;
-				i++;
-			} else 
-
-			if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
-				if (i == 20) {
-					crc = buf ^ (buf >> 7) ^ (buf >> 14);
-					if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
-						data[buf >> 18] = buf >> 4;
-						status |= 1 << (buf >> 18);
-					}
-					j++;
-				}
-				t = strobe;
-				buf = 0;
-				i = 0;
-			}
-			w = v;
-			v = u;
-		}
-
-	} while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
-
-	__restore_flags(flags);
-
-	return -(status != 0xf);
-}
-
-/*
- * grip_timer() repeatedly polls the joysticks and generates events.
- */
-
-static void grip_timer(unsigned long private)
-{
-	struct grip *grip = (void*) private;
-	unsigned int data[GRIP_LENGTH_XT];
-	struct input_dev *dev;
-	int i, j;
-
-	for (i = 0; i < 2; i++) {
-
-		dev = grip->dev + i;
-		grip->reads++;
-
-		switch (grip->mode[i]) {
-
-			case GRIP_MODE_GPP:
-
-				if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
-					grip->bads++;
-					break;
-				}
-
-				input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
-				input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
-
-				for (j = 0; j < 12; j++)
-					if (grip_btn_gpp[j])
-						input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
-
-				break;
-
-			case GRIP_MODE_BD:
-
-				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
-					grip->bads++;
-					break;
-				}
-
-				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
-				input_report_abs(dev, ABS_Y,  63 - ((data[0] >> 8) & 0x3f));
-				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
-				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
-				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
-
-				for (j = 0; j < 5; j++)
-					input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
-
-				break;
-
-			case GRIP_MODE_XT:
-
-				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
-					grip->bads++;
-					break;
-				}
-
-				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
-				input_report_abs(dev, ABS_Y,  63 - ((data[0] >> 8) & 0x3f));
-				input_report_abs(dev, ABS_BRAKE,    (data[1] >> 2) & 0x3f);
-				input_report_abs(dev, ABS_GAS,	    (data[1] >> 8) & 0x3f);
-				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
-				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
-				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
-				input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
-				input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
-
-				for (j = 0; j < 11; j++)
-					input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
-				break;
-
-			case GRIP_MODE_DC:
-
-				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
-					grip->bads++;
-					break;
-				}
-
-				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
-				input_report_abs(dev, ABS_Y,        (data[0] >> 8) & 0x3f);
-				input_report_abs(dev, ABS_RX,       (data[1] >> 2) & 0x3f);
-				input_report_abs(dev, ABS_RY,	    (data[1] >> 8) & 0x3f);
-				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
-				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
-				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
-
-				for (j = 0; j < 9; j++)
-					input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
-				break;
-
-
-		}
-	}
-
-	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
-}
-
-static int grip_open(struct input_dev *dev)
-{
-	struct grip *grip = dev->private;
-	if (!grip->used++)
-		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
-	return 0;
-}
-
-static void grip_close(struct input_dev *dev)
-{
-	struct grip *grip = dev->private;
-	if (!--grip->used)
-		del_timer(&grip->timer);
-}
-
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct grip *grip;
-	unsigned int data[GRIP_LENGTH_XT];
-	int i, j, t;
-
-	if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
-		return;
-	memset(grip, 0, sizeof(struct grip));
-
-	gameport->private = grip;
-
-	grip->gameport = gameport;
-	init_timer(&grip->timer);
-	grip->timer.data = (long) grip;
-	grip->timer.function = grip_timer;
-
-	 if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	for (i = 0; i < 2; i++) {
-		if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
-			grip->mode[i] = GRIP_MODE_GPP;
-			continue;
-		}
-		if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
-			if (!(data[3] & 7)) {
-				grip->mode[i] = GRIP_MODE_BD;
-				continue;
-			}
-			if (!(data[2] & 0xf0)) {
-				grip->mode[i] = GRIP_MODE_XT;
-				continue;
-			}
-			grip->mode[i] = GRIP_MODE_DC;
-			continue;
-		}
-	}
-
-	if (!grip->mode[0] && !grip->mode[1])
-		goto fail2;
-
-	for (i = 0; i < 2; i++)
-		if (grip->mode[i]) {
-
-			grip->dev[i].private = grip;
-
-			grip->dev[i].open = grip_open;
-			grip->dev[i].close = grip_close;
-
-			grip->dev[i].name = grip_name[grip->mode[i]];
-			grip->dev[i].idbus = BUS_GAMEPORT;
-			grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
-			grip->dev[i].idproduct = grip->mode[i];
-			grip->dev[i].idversion = 0x0100;
-
-			grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-			for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
-
-				set_bit(t, grip->dev[i].absbit);
-
-				if (j < grip_cen[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 14;
-					grip->dev[i].absmax[t] = 52;
-					grip->dev[i].absfuzz[t] = 1;
-					grip->dev[i].absflat[t] = 2;
-					continue;
-				}
-
-				if (j < grip_anx[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 3;
-					grip->dev[i].absmax[t] = 57;
-					grip->dev[i].absfuzz[t] = 1;
-					continue;
-				}
-
-				grip->dev[i].absmin[t] = -1;
-				grip->dev[i].absmax[t] = 1;
-			}
-
-			for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
-				if (t > 0)
-					set_bit(t, grip->dev[i].keybit);
-
-			input_register_device(grip->dev + i);
-
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
-		}
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:	kfree(grip);
-}
-
-static void grip_disconnect(struct gameport *gameport)
-{
-	int i;
-
-	struct grip *grip = gameport->private;
-	for (i = 0; i < 2; i++)
-		if (grip->mode[i])
-			input_unregister_device(grip->dev + i);
-	gameport_close(gameport);
-	kfree(grip);
-}
-
-static struct gameport_dev grip_dev = {
-	connect:	grip_connect,
-	disconnect:	grip_disconnect,
-};
-
-int __init grip_init(void)
-{
-	gameport_register_device(&grip_dev);
-	return 0;
-}
-
-void __exit grip_exit(void)
-{
-	gameport_unregister_device(&grip_dev);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/iforce.c b/drivers/char/joystick/iforce.c
--- a/drivers/char/joystick/iforce.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1224 +0,0 @@
-/*
- * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
- *
- *  USB/RS232 I-Force joysticks and wheels.
- *
- *  Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
-#include <linux/config.h>
-
-/* FF: This module provides arbitrary resource management routines.
- * I use it to manage the device's memory.
- * Despite the name of this module, I am *not* going to access the ioports.
- */
-#include <linux/ioport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
-MODULE_LICENSE("GPL");
-
-#define IFORCE_MAX_LENGTH	16
-
-#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)
-#define IFORCE_232	1
-#endif
-#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)
-#define IFORCE_USB	2
-#endif
-
-#define FF_EFFECTS_MAX	32
-
-/* Each force feedback effect is made of one core effect, which can be
- * associated to at most to effect modifiers
- */
-#define FF_MOD1_IS_USED		0
-#define FF_MOD2_IS_USED		1
-#define FF_CORE_IS_USED		2
-#define FF_CORE_IS_PLAYED	3
-#define FF_MODCORE_MAX		3
-
-struct iforce_core_effect {
-	/* Information about where modifiers are stored in the device's memory */
-	struct resource mod1_chunk;
-	struct resource mod2_chunk;
-	unsigned long flags[NBITS(FF_MODCORE_MAX)];
-};
-
-#define FF_CMD_EFFECT		0x010e
-#define FF_CMD_SHAPE		0x0208
-#define FF_CMD_MAGNITUDE	0x0303
-#define FF_CMD_PERIOD		0x0407
-#define FF_CMD_INTERACT		0x050a
-
-#define FF_CMD_AUTOCENTER	0x4002
-#define FF_CMD_PLAY		0x4103
-#define FF_CMD_ENABLE		0x4201
-#define FF_CMD_GAIN		0x4301
-
-#define FF_CMD_QUERY		0xff01
-
-static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
-	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
-static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
-	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
-static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
-	FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
-
-static struct iforce_device {
-	u16 idvendor;
-	u16 idproduct;
-	char *name;
-	signed short *btn;
-	signed short *abs;
-	signed short *ff;
-} iforce_device[] = {
-	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },
-	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
-	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },
-	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
-	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
-	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
-};
-
-struct iforce {
-	struct input_dev dev;		/* Input device interface */
-	struct iforce_device *type;
-	char name[64];
-	int open;
-	int bus;
-
-	unsigned char data[IFORCE_MAX_LENGTH];
-	unsigned char edata[IFORCE_MAX_LENGTH];
-	u16 ecmd;
-	u16 expect_packet;
-
-#ifdef IFORCE_232
-	struct serio *serio;		/* RS232 transfer */
-	int idx, pkt, len, id;
-	unsigned char csum;
-#endif
-#ifdef IFORCE_USB
-	struct usb_device *usbdev;	/* USB transfer */
-	struct urb *irq, *out, *ctrl;
-	struct usb_ctrlrequest dr;
-#endif
-					/* Force Feedback */
-	wait_queue_head_t wait;
-	struct resource device_memory;
-	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
-};
-
-static struct {
-	__s32 x;
-	__s32 y;
-} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a)	((unsigned char)((a) >> 8))
-#define LO(a)	((unsigned char)((a) & 0xff))
-
-/* Encode a time value */
-#define TIME_SCALE(a)	((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
-
-static void dump_packet(char *msg, u16 cmd, unsigned char *data)
-{
-	int i;
-
-	printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
-	for (i = 0; i < LO(cmd); i++)
-		printk("%02x ", data[i]);
-	printk(")\n");
-}
-
-/*
- * Send a packet of bytes to the device
- */
-static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
-{
-	switch (iforce->bus) {
-
-#ifdef IFORCE_232
-		case IFORCE_232: {
-
-			int i;
-			unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
-
-			serio_write(iforce->serio, 0x2b);
-			serio_write(iforce->serio, HI(cmd));
-			serio_write(iforce->serio, LO(cmd));
-
-			for (i = 0; i < LO(cmd); i++) {
-				serio_write(iforce->serio, data[i]);
-				csum = csum ^ data[i];
-			}
-
-			serio_write(iforce->serio, csum);
-			return;
-		}
-#endif
-#ifdef IFORCE_USB
-		case IFORCE_USB: {
-
-			DECLARE_WAITQUEUE(wait, current);
-			int timeout = HZ; /* 1 second */
-
-			memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
-			((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
-			iforce->out->transfer_buffer_length = LO(cmd) + 2;
-			iforce->out->dev = iforce->usbdev;
-
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&iforce->wait, &wait);
-
-			if (usb_submit_urb(iforce->out)) {
-				set_current_state(TASK_RUNNING);
-				remove_wait_queue(&iforce->wait, &wait);
-				return;
-			}
-
-			while (timeout && iforce->out->status == -EINPROGRESS)
-				timeout = schedule_timeout(timeout);
-
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&iforce->wait, &wait);
-
-			if (!timeout)
-				usb_unlink_urb(iforce->out);
-
-			return;
-		}
-#endif
-	}
-}
-
-static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
-{
-	struct input_dev *dev = &iforce->dev;
-	int i;
-
-#ifdef IFORCE_232
-	if (HI(iforce->expect_packet) == HI(cmd)) {
-		iforce->expect_packet = 0;
-		iforce->ecmd = cmd;
-		memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
-		if (waitqueue_active(&iforce->wait))
-			wake_up(&iforce->wait);
-	}
-#endif
-
-	if (!iforce->type)
-		return;
-
-	switch (HI(cmd)) {
-
-		case 0x01:	/* joystick position data */
-		case 0x03:	/* wheel position data */
-
-			if (HI(cmd) == 1) {
-				input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
-				input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
-				input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
-			} else {
-				input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
-				input_report_abs(dev, ABS_GAS,   255 - data[2]);
-				input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
-			}
-
-			input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
-			input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
-			for (i = 0; iforce->type->btn[i] >= 0; i++)
-				input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
-
-			break;
-
-		case 0x02:	/* status report */
-
-			input_report_key(dev, BTN_DEAD, data[0] & 0x02);
-			break;
-	}
-}
-
-static int get_id_packet(struct iforce *iforce, char *packet)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int timeout = HZ; /* 1 second */
-
-	switch (iforce->bus) {
-
-#ifdef IFORCE_USB
-		case IFORCE_USB:
-
-			iforce->dr.bRequest = packet[0];
-			iforce->ctrl->dev = iforce->usbdev;
-
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&iforce->wait, &wait);
-
-			if (usb_submit_urb(iforce->ctrl)) {
-				set_current_state(TASK_RUNNING);
-				remove_wait_queue(&iforce->wait, &wait);
-				return -1;
-			}
-
-			while (timeout && iforce->ctrl->status == -EINPROGRESS)
-				timeout = schedule_timeout(timeout);
-
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&iforce->wait, &wait);
-
-			if (!timeout) {
-				usb_unlink_urb(iforce->ctrl);
-				return -1;
-			}
-
-			break;
-#endif
-#ifdef IFORCE_232
-		case IFORCE_232:
-
-			iforce->expect_packet = FF_CMD_QUERY;
-			send_packet(iforce, FF_CMD_QUERY, packet);
-
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&iforce->wait, &wait);
-
-			while (timeout && iforce->expect_packet)
-				timeout = schedule_timeout(timeout);
-
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&iforce->wait, &wait);
-
-			if (!timeout) {
-				iforce->expect_packet = 0;
-				return -1;
-			}
-
-			break;
-#endif
-	}
-
-	return -(iforce->edata[0] != packet[0]);
-}
-
-static int iforce_open(struct input_dev *dev)
-{
-	struct iforce *iforce = dev->private;
-
-	switch (iforce->bus) {
-#ifdef IFORCE_USB
-		case IFORCE_USB:
-			if (iforce->open++)
-				break;
-			iforce->irq->dev = iforce->usbdev;
-			if (usb_submit_urb(iforce->irq))
-					return -EIO;
-			break;
-#endif
-	}
-	return 0;
-}
-
-static void iforce_close(struct input_dev *dev)
-{
-	struct iforce *iforce = dev->private;
-
-	switch (iforce->bus) {
-#ifdef IFORCE_USB
-		case IFORCE_USB:
-			if (!--iforce->open)
-				usb_unlink_urb(iforce->irq);
-			break;
-#endif
-	}
-}
-
-/*
- * Start or stop playing an effect
- */
-
-static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	struct iforce* iforce = (struct iforce*)(dev->private);
-	unsigned char data[3];
-
-	printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
-
-	if (type != EV_FF)
-		return -1;
-
-	switch (code) {
-
-		case FF_GAIN:
-
-			data[0] = value >> 9;
-			send_packet(iforce, FF_CMD_GAIN, data);
-
-			return 0;
-
-		case FF_AUTOCENTER:
-
-			data[0] = 0x03;
-			data[1] = value >> 9;
-			send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
-			data[0] = 0x04;
-			data[1] = 0x01;
-			send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
-			return 0;
-
-		default: /* Play an effect */
-
-			if (code >= iforce->dev.ff_effects_max)
-				return -1;
-
-			data[0] = LO(code);
-			data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
-			data[2] = LO(value);
-			send_packet(iforce, FF_CMD_PLAY, data);
-
-			return 0;
-	}
-
-	return -1;
-}
-
-/*
- * Set the magnitude of a constant force effect
- * Return error code
- *
- * Note: caller must ensure exclusive access to device
- */
-
-static int make_magnitude_modifier(struct iforce* iforce,
-	struct resource* mod_chunk, __s16 level)
-{
-	unsigned char data[3];
-
-	if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
-		iforce->device_memory.start, iforce->device_memory.end, 2L,
-		NULL, NULL)) {
-		return -ENOMEM;
-	}
-
-	data[0] = LO(mod_chunk->start);
-	data[1] = HI(mod_chunk->start);
-	data[2] = HI(level);
-
-	send_packet(iforce, FF_CMD_MAGNITUDE, data);
-
-	return 0;
-}
-
-/*
- * Upload the component of an effect dealing with the period, phase and magnitude
- */
-
-static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk,
-	__s16 magnitude, __s16 offset, u16 period, u16 phase)
-{
-	unsigned char data[7];
-
-	period = TIME_SCALE(period);
-
-	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
-		iforce->device_memory.start, iforce->device_memory.end, 2L,
-		NULL, NULL)) {
-		return -ENOMEM;
-	}
-
-	data[0] = LO(mod_chunk->start);
-	data[1] = HI(mod_chunk->start);
-
-	data[2] = HI(magnitude);
-	data[3] = HI(offset);
-	data[4] = HI(phase);
-
-	data[5] = LO(period);
-	data[6] = HI(period);
-
-	send_packet(iforce, FF_CMD_PERIOD, data);
-
-	return 0;
-}
-
-/*
- * Uploads the part of an effect setting the shape of the force
- */
-
-static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
-	u16 attack_duration, __s16 initial_level,
-	u16 fade_duration, __s16 final_level)
-{
-	unsigned char data[8];
-
-	attack_duration = TIME_SCALE(attack_duration);
-	fade_duration = TIME_SCALE(fade_duration);
-
-	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
-		iforce->device_memory.start, iforce->device_memory.end, 2L,
-		NULL, NULL)) {
-		return -ENOMEM;
-	}
-
-	data[0] = LO(mod_chunk->start);
-	data[1] = HI(mod_chunk->start);
-
-	data[2] = LO(attack_duration);
-	data[3] = HI(attack_duration);
-	data[4] = HI(initial_level);
-
-	data[5] = LO(fade_duration);
-	data[6] = HI(fade_duration);
-	data[7] = HI(final_level);
-
-	send_packet(iforce, FF_CMD_SHAPE, data);
-
-	return 0;
-}
-
-/*
- * Component of spring, friction, inertia... effects
- */
-
-static int make_interactive_modifier(struct iforce* iforce,
-	struct resource* mod_chunk,
-	__s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
-{
-	unsigned char data[10];
-
-	if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
-		iforce->device_memory.start, iforce->device_memory.end, 2L,
-		NULL, NULL)) {
-		return -ENOMEM;
-	}
-
-	data[0] = LO(mod_chunk->start);
-	data[1] = HI(mod_chunk->start);
-
-	data[2] = HI(rk);
-	data[3] = HI(lk);
-
-	data[4] = LO(center);
-	data[5] = HI(center);
-
-	data[6] = LO(db);
-	data[7] = HI(db);
-
-	data[8] = HI(rsat);
-	data[9] = HI(lsat);
-
-	send_packet(iforce, FF_CMD_INTERACT, data);
-
-	return 0;
-}
-
-static unsigned char find_button(struct iforce *iforce, signed short button)
-{
-	int i;
-	for (i = 1; iforce->type->btn[i] >= 0; i++)
-		if (iforce->type->btn[i] == button)
-			return i + 1;
-	return 0;
-}
-
-/*
- * Send the part common to all effects to the device
- */
-
-static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
-	u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,
-	u16 interval, u16 direction)
-{
-	unsigned char data[14];
-
-	duration = TIME_SCALE(duration);
-	delay    = TIME_SCALE(delay);
-	interval = TIME_SCALE(interval);
-
-	data[0]  = LO(id);
-	data[1]  = effect_type;
-	data[2]  = LO(axes) | find_button(iforce, button);
-
-	data[3]  = LO(duration);
-	data[4]  = HI(duration);
-
-	data[5]  = HI(direction);
-
-	data[6]  = LO(interval);
-	data[7]  = HI(interval);
-
-	data[8]  = LO(mod_id1);
-	data[9]  = HI(mod_id1);
-	data[10] = LO(mod_id2);
-	data[11] = HI(mod_id2);
-
-	data[12] = LO(delay);
-	data[13] = HI(delay);
-
-	send_packet(iforce, FF_CMD_EFFECT, data);
-
-	return 0;
-}
-
-/*
- * Upload a periodic effect to the device
- */
-
-static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
-{
-	u8 wave_code;
-	int core_id = effect->id;
-	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
-	struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
-	struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
-	int err = 0;
-
-	err = make_period_modifier(iforce, mod1_chunk,
-		effect->u.periodic.magnitude, effect->u.periodic.offset,
-		effect->u.periodic.period, effect->u.periodic.phase);
-	if (err) return err;
-	set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
-	err = make_shape_modifier(iforce, mod2_chunk,
-		effect->u.periodic.shape.attack_length,
-		effect->u.periodic.shape.attack_level,
-		effect->u.periodic.shape.fade_length,
-		effect->u.periodic.shape.fade_level);
-	if (err) return err;
-	set_bit(FF_MOD2_IS_USED, core_effect->flags);
-
-	switch (effect->u.periodic.waveform) {
-		case FF_SQUARE:		wave_code = 0x20; break;
-		case FF_TRIANGLE:	wave_code = 0x21; break;
-		case FF_SINE:		wave_code = 0x22; break;
-		case FF_SAW_UP:		wave_code = 0x23; break;
-		case FF_SAW_DOWN:	wave_code = 0x24; break;
-		default:		wave_code = 0x20; break;
-	}
-
-	err = make_core(iforce, effect->id,
-		mod1_chunk->start,
-		mod2_chunk->start,
-		wave_code,
-		0x20,
-		effect->replay.length,
-		effect->replay.delay,
-		effect->trigger.button,
-		effect->trigger.interval,
-		effect->u.periodic.direction);
-
-	return err;
-}
-
-/*
- * Upload a constant force effect
- */
-static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
-{
-	int core_id = effect->id;
-	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
-	struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
-	struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
-	int err = 0;
-
-	printk(KERN_DEBUG "iforce.c: make constant effect\n");
-
-	err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
-	if (err) return err;
-	set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
-	err = make_shape_modifier(iforce, mod2_chunk,
-		effect->u.constant.shape.attack_length,
-		effect->u.constant.shape.attack_level,
-		effect->u.constant.shape.fade_length,
-		effect->u.constant.shape.fade_level);
-	if (err) return err;
-	set_bit(FF_MOD2_IS_USED, core_effect->flags);
-
-	err = make_core(iforce, effect->id,
-		mod1_chunk->start,
-		mod2_chunk->start,
-		0x00,
-		0x20,
-		effect->replay.length,
-		effect->replay.delay,
-		effect->trigger.button,
-		effect->trigger.interval,
-		effect->u.constant.direction);
-
-	return err;
-}
-
-/*
- * Upload an interactive effect. Those are for example friction, inertia, springs...
- */
-static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
-{
-	int core_id = effect->id;
-	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
-	struct resource* mod_chunk = &(core_effect->mod1_chunk);
-	u8 type, axes;
-	u16 mod1, mod2, direction;
-	int err = 0;
-
-	printk(KERN_DEBUG "iforce.c: make interactive effect\n");
-
-	switch (effect->type) {
-		case FF_SPRING:		type = 0x40; break;
-		case FF_FRICTION:	type = 0x41; break;
-		default: return -1;
-	}
-
-	err = make_interactive_modifier(iforce, mod_chunk,
-		effect->u.interactive.right_saturation,
-		effect->u.interactive.left_saturation,
-		effect->u.interactive.right_coeff,
-		effect->u.interactive.left_coeff,
-		effect->u.interactive.deadband,
-		effect->u.interactive.center);
-	if (err) return err;
-	set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
-	switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
-		test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
-		(!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
-
-		case 0: /* Only one axis, choose orientation */
-			mod1 = mod_chunk->start;
-			mod2 = 0xffff;
-			direction = effect->u.interactive.direction;
-			axes = 0x20;
-			break;
-
-		case 1:	/* Only X axis */
-			mod1 = mod_chunk->start;
-			mod2 = 0xffff;
-			direction = 0x5a00;
-			axes = 0x40;
-			break;
-
-		case 2: /* Only Y axis */
-			mod1 = 0xffff;
-			mod2 = mod_chunk->start;
-			direction = 0xb400;
-			axes = 0x80;
-			break;
-
-		case 3:	/* Both X and Y axes */
-			/* TODO: same setting for both axes is not mandatory */
-			mod1 = mod_chunk->start;
-			mod2 = mod_chunk->start;
-			direction = 0x6000;
-			axes = 0xc0;
-			break;
-
-		default:
-			return -1;
-	}
-
-	err = make_core(iforce, effect->id,
-		mod1, mod2,
-		type, axes,
-		effect->replay.length, effect->replay.delay,
-		effect->trigger.button, effect->trigger.interval,
-		direction);
-
-	return err;
-}
-
-/*
- * Function called when an ioctl is performed on the event dev entry.
- * It uploads an effect to the device
- */
-static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-{
-	struct iforce* iforce = (struct iforce*)(dev->private);
-	int id;
-
-	printk(KERN_DEBUG "iforce.c: upload effect\n");
-
-/*
- * Get a free id
- */
-
-	for (id=0; id < FF_EFFECTS_MAX; ++id)
-		if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break;
-
-	if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max)
-		return -ENOMEM;
-
-	effect->id = id;
-	set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
-
-/*
- * Upload the effect
- */
-
-	switch (effect->type) {
-
-		case FF_PERIODIC:
-			return iforce_upload_periodic(iforce, effect);
-
-		case FF_CONSTANT:
-			return iforce_upload_constant(iforce, effect);
-
-		case FF_SPRING:
-		case FF_FRICTION:
-			return iforce_upload_interactive(iforce, effect);
-
-		default:
-			return -1;
-	}
-}
-
-/*
- * Erases an effect: it frees the effect id and mark as unused the memory
- * allocated for the parameters
- */
-static int iforce_erase_effect(struct input_dev *dev, int effect_id)
-{
-	struct iforce* iforce = (struct iforce*)(dev->private);
-	int err = 0;
-	struct iforce_core_effect* core_effect;
-
-	printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
-
-	if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
-		return -EINVAL;
-
-	core_effect = iforce->core_effects + effect_id;
-
-	if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
-		err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
-
-	if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
-		err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
-
-	/*TODO: remember to change that if more FF_MOD* bits are added */
-	core_effect->flags[0] = 0;
-
-	return err;
-}
-static int iforce_init_device(struct iforce *iforce)
-{
-	unsigned char c[] = "CEOV";
-	int i;
-
-	init_waitqueue_head(&iforce->wait);
-	iforce->dev.ff_effects_max = 10;
-
-/*
- * Input device fields.
- */
-
-	iforce->dev.idbus = BUS_USB;
-	iforce->dev.private = iforce;
-	iforce->dev.name = iforce->name;
-	iforce->dev.open = iforce_open;
-	iforce->dev.close = iforce_close;
-	iforce->dev.event = iforce_input_event;
-	iforce->dev.upload_effect = iforce_upload_effect;
-	iforce->dev.erase_effect = iforce_erase_effect;
-
-/*
- * On-device memory allocation.
- */
-
-	iforce->device_memory.name = "I-Force device effect memory";
-	iforce->device_memory.start = 0;
-	iforce->device_memory.end = 200;
-	iforce->device_memory.flags = IORESOURCE_MEM;
-	iforce->device_memory.parent = NULL;
-	iforce->device_memory.child = NULL;
-	iforce->device_memory.sibling = NULL;
-
-/*
- * Wait until device ready - until it sends its first response.
- */
-
-	for (i = 0; i < 20; i++)
-		if (!get_id_packet(iforce, "O"))
-			break;
-
-	if (i == 20) { /* 5 seconds */
-		printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
-		iforce_close(&iforce->dev);
-		return -1;
-	}
-
-/*
- * Get device info.
- */
-
-	if (!get_id_packet(iforce, "M"))
-		iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
-	if (!get_id_packet(iforce, "P"))
-		iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
-	if (!get_id_packet(iforce, "B"))
-		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
-	if (!get_id_packet(iforce, "N"))
-		iforce->dev.ff_effects_max = iforce->edata[1];
-
-/*
- * Display additional info.
- */
-
-	for (i = 0; c[i]; i++)
-		if (!get_id_packet(iforce, c + i))
-			dump_packet("info", iforce->ecmd, iforce->edata);
-
-/*
- * Disable spring, enable force feedback.
- * FIXME: We should use iforce_set_autocenter() et al here.
- */
-
-	send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
-	send_packet(iforce, FF_CMD_ENABLE, "\004");
-
-/*
- * Find appropriate device entry
- */
-
-	for (i = 0; iforce_device[i].idvendor; i++)
-		if (iforce_device[i].idvendor == iforce->dev.idvendor &&
-		    iforce_device[i].idproduct == iforce->dev.idproduct)
-			break;
-
-	iforce->type = iforce_device + i;
-
-	sprintf(iforce->name, iforce->type->name,
-		iforce->dev.idproduct, iforce->dev.idvendor);
-
-/*
- * Set input device bitfields and ranges.
- */
-
-	iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
-
-	for (i = 0; iforce->type->btn[i] >= 0; i++) {
-		signed short t = iforce->type->btn[i];
-		set_bit(t, iforce->dev.keybit);
-		if (t != BTN_DEAD)
-			set_bit(FF_BTN(t), iforce->dev.ffbit);
-	}
-
-	for (i = 0; iforce->type->abs[i] >= 0; i++) {
-
-		signed short t = iforce->type->abs[i];
-		set_bit(t, iforce->dev.absbit);
-
-		switch (t) {
-
-			case ABS_X:
-			case ABS_Y:
-			case ABS_WHEEL:
-
-				iforce->dev.absmax[t] =  1920;
-				iforce->dev.absmin[t] = -1920;
-				iforce->dev.absflat[t] = 128;
-				iforce->dev.absfuzz[t] = 16;
-
-				set_bit(FF_ABS(t), iforce->dev.ffbit);
-				break;
-
-			case ABS_THROTTLE:
-			case ABS_GAS:
-			case ABS_BRAKE:
-
-				iforce->dev.absmax[t] = 255;
-				iforce->dev.absmin[t] = 0;
-				break;
-
-			case ABS_HAT0X:
-			case ABS_HAT0Y:
-				iforce->dev.absmax[t] =  1;
-				iforce->dev.absmin[t] = -1;
-				break;
-		}
-	}
-
-	for (i = 0; iforce->type->ff[i] >= 0; i++)
-		set_bit(iforce->type->ff[i], iforce->dev.ffbit);
-
-/*
- * Register input device.
- */
-
-	input_register_device(&iforce->dev);
-
-	return 0;
-}
-
-#ifdef IFORCE_USB
-
-static void iforce_usb_irq(struct urb *urb)
-{
-	struct iforce *iforce = urb->context;
-	if (urb->status) return;
-	iforce_process_packet(iforce,
-		(iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
-}
-
-static void iforce_usb_out(struct urb *urb)
-{
-	struct iforce *iforce = urb->context;
-	if (urb->status) return;
-	if (waitqueue_active(&iforce->wait))
-		wake_up(&iforce->wait);
-}
-
-static void iforce_usb_ctrl(struct urb *urb)
-{
-	struct iforce *iforce = urb->context;
-	if (urb->status) return;
-	iforce->ecmd = 0xff00 | urb->actual_length;
-	if (waitqueue_active(&iforce->wait))
-		wake_up(&iforce->wait);
-}
-
-static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
-				const struct usb_device_id *id)
-{
-	struct usb_endpoint_descriptor *epirq, *epout;
-	struct iforce *iforce;
-
-	epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
-	epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
-
-	if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
-	memset(iforce, 0, sizeof(struct iforce));
-
-	iforce->irq = usb_alloc_urb(0);
-	if (!iforce->irq) {
-		kfree(iforce);
-		return NULL;
-	}
-	iforce->out = usb_alloc_urb(0);
-	if (!iforce->out) {
-		usb_free_urb(iforce->irq);
-		kfree(iforce);
-		return NULL;
-	}
-	iforce->ctrl = usb_alloc_urb(0);
-	if (!iforce->ctrl) {
-		usb_free_urb(iforce->out);
-		usb_free_urb(iforce->irq);
-		kfree(iforce);
-		return NULL;
-	}
-
-	iforce->bus = IFORCE_USB;
-	iforce->usbdev = dev;
-
-	iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
-	iforce->dr.wIndex = 0;
-	iforce->dr.wLength = 16;
-
-	FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
-			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
-
-	FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
-			iforce + 1, 32, iforce_usb_out, iforce);
-
-	FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
-			(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
-
-	if (iforce_init_device(iforce)) {
-		usb_free_urb(iforce->ctrl);
-		usb_free_urb(iforce->out);
-		usb_free_urb(iforce->irq);
-		kfree(iforce);
-		return NULL;
-	}
-
-	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
-		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
-		iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
-
-	return iforce;
-}
-
-static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct iforce *iforce = ptr;
-	usb_unlink_urb(iforce->irq);
-	input_unregister_device(&iforce->dev);
-	usb_free_urb(iforce->ctrl);
-	usb_free_urb(iforce->out);
-	usb_free_urb(iforce->irq);
-	kfree(iforce);
-}
-
-static struct usb_device_id iforce_usb_ids [] = {
-	{ USB_DEVICE(0x046d, 0xc281) },		/* Logitech WingMan Force */
-	{ USB_DEVICE(0x046d, 0xc291) },		/* Logitech WingMan Formula Force */
-	{ USB_DEVICE(0x05ef, 0x020a) },		/* AVB Top Shot Pegasus */
-	{ USB_DEVICE(0x05ef, 0x8884) },		/* AVB Mag Turbo Force */
-	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
-	{ }					/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
-
-static struct usb_driver iforce_usb_driver = {
-	name:		"iforce",
-	probe:		iforce_usb_probe,
-	disconnect:	iforce_usb_disconnect,
-	id_table:	iforce_usb_ids,
-};
-
-#endif
-
-#ifdef IFORCE_232
-
-static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct iforce* iforce = serio->private;
-
-	if (!iforce->pkt) {
-		if (data != 0x2b) {
-			return;
-		}
-		iforce->pkt = 1;
-		return;
-	}
-
-	if (!iforce->id) {
-		if (data > 3 && data != 0xff) {
-			iforce->pkt = 0;
-			return;
-		}
-		iforce->id = data;
-		return;
-	}
-
-	if (!iforce->len) {
-		if (data > IFORCE_MAX_LENGTH) {
-			iforce->pkt = 0;
-			iforce->id = 0;
-			return;
-		}
-		iforce->len = data;
-		return;
-	}
-
-	if (iforce->idx < iforce->len) {
-		iforce->csum += iforce->data[iforce->idx++] = data;
-		return;
-	}
-
-	if (iforce->idx == iforce->len) {
-		iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
-		iforce->pkt = 0;
-		iforce->id  = 0;
-		iforce->len = 0;
-		iforce->idx = 0;
-		iforce->csum = 0;
-	}
-}
-
-static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct iforce *iforce;
-	if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
-		return;
-
-	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
-	memset(iforce, 0, sizeof(struct iforce));
-
-	iforce->bus = IFORCE_232;
-	iforce->serio = serio;
-	serio->private = iforce;
-
-	if (serio_open(serio, dev)) {
-		kfree(iforce);
-		return;
-	}
-
-	if (iforce_init_device(iforce)) {
-		serio_close(serio);
-		kfree(iforce);
-		return;
-	}
-
-	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
-		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
-		iforce->device_memory.end, serio->number);
-}
-
-static void iforce_serio_disconnect(struct serio *serio)
-{
-	struct iforce* iforce = serio->private;
-
-	input_unregister_device(&iforce->dev);
-	serio_close(serio);
-	kfree(iforce);
-}
-
-static struct serio_dev iforce_serio_dev = {
-	interrupt:	iforce_serio_irq,
-	connect:	iforce_serio_connect,
-	disconnect:	iforce_serio_disconnect,
-};
-
-#endif
-
-static int __init iforce_init(void)
-{
-#ifdef IFORCE_USB
-	usb_register(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
-	serio_register_device(&iforce_serio_dev);
-#endif
-	return 0;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef IFORCE_USB
-	usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
-	serio_unregister_device(&iforce_serio_dev);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
diff -Nru a/drivers/char/joystick/interact.c b/drivers/char/joystick/interact.c
--- a/drivers/char/joystick/interact.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,308 +0,0 @@
-/*
- * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
- *
- *  Copyright (c) 2000 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Toby Deshane
- *
- *  Sponsored by SuSE
- */
-
-/*
- * InterAct digital gamepad/joystick driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define INTERACT_MAX_START	400	/* 400 us */
-#define INTERACT_MAX_STROBE	40	/* 40 us */
-#define INTERACT_MAX_LENGTH	32	/* 32 bits */
-#define INTERACT_REFRESH_TIME	HZ/50	/* 20 ms */
-
-#define INTERACT_TYPE_HHFX	0	/* HammerHead/FX */
-#define INTERACT_TYPE_PP8D	1	/* ProPad 8 */
-
-struct interact {
-	struct gameport *gameport;
-	struct input_dev dev;
-	struct timer_list timer;
-	int used;
-	int bads;
-	int reads;
-	unsigned char type;
-	unsigned char length;
-};
-
-static short interact_abs_hhfx[] = 
-	{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
-static short interact_abs_pp8d[] =
-	{ ABS_X, ABS_Y, -1 };
-
-static short interact_btn_hhfx[] =
-	{ BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
-static short interact_btn_pp8d[] =
-	{ BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
-
-struct interact_type {
-	int id;
-	short *abs;
-	short *btn;
-	char *name;
-	unsigned char length;
-	unsigned char b8;
-};
-
-static struct interact_type interact_type[] = {
-	{ 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX",    32, 4 },
-	{ 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
-	{ 0 }};
-
-/*
- * interact_read_packet() reads and InterAct joystick data.
- */
-
-static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
-{
-	unsigned long flags;
-	unsigned char u, v;
-	unsigned int t, s;
-	int i;
-
-	i = 0;
-	data[0] = data[1] = data[2] = 0;
-	t = gameport_time(gameport, INTERACT_MAX_START);
-	s = gameport_time(gameport, INTERACT_MAX_STROBE);
-
-	__save_flags(flags);
-	__cli();
-	gameport_trigger(gameport);
-	v = gameport_read(gameport);
-
-	while (t > 0 && i < length) {
-		t--;
-		u = v; v = gameport_read(gameport);
-		if (v & ~u & 0x40) {
-			data[0] = (data[0] << 1) | ((v >> 4) & 1);
-			data[1] = (data[1] << 1) | ((v >> 5) & 1);
-			data[2] = (data[2] << 1) | ((v >> 7) & 1);
-			i++;
-			t = s;
-		}
-	}
-
-	__restore_flags(flags);
-
-	return i;
-}
-
-/*
- * interact_timer() reads and analyzes InterAct joystick data.
- */
-
-static void interact_timer(unsigned long private)
-{
-	struct interact *interact = (struct interact *) private;
-	struct input_dev *dev = &interact->dev;
-	u32 data[3];
-	int i;
-
-	interact->reads++;
-
-	if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
-		interact->bads++;
-	} else
-
-	for (i = 0; i < 3; i++)
-		data[i] <<= INTERACT_MAX_LENGTH - interact->length;
-
-	switch (interact->type) {
-
-		case INTERACT_TYPE_HHFX:
-
-			for (i = 0; i < 4; i++)
-				input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
-
-			for (i = 0; i < 2; i++)
-				input_report_abs(dev, ABS_HAT0Y - i,
-					((data[1] >> ((i << 1) + 17)) & 1)  - ((data[1] >> ((i << 1) + 16)) & 1));
-
-			for (i = 0; i < 8; i++)
-				input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
-
-			for (i = 0; i < 4; i++)
-				input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
-
-			break;
-
-		case INTERACT_TYPE_PP8D:
-
-			for (i = 0; i < 2; i++)
-				input_report_abs(dev, interact_abs_pp8d[i], 
-					((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
-
-			for (i = 0; i < 8; i++)
-				input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
-
-			break;
-	}
-
-	mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
-
-}
-
-/*
- * interact_open() is a callback from the input open routine.
- */
-
-static int interact_open(struct input_dev *dev)
-{
-	struct interact *interact = dev->private;
-	if (!interact->used++)
-		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);	
-	return 0;
-}
-
-/*
- * interact_close() is a callback from the input close routine.
- */
-
-static void interact_close(struct input_dev *dev)
-{
-	struct interact *interact = dev->private;
-	if (!--interact->used)
-		del_timer(&interact->timer);
-}
-
-/*
- * interact_connect() probes for InterAct joysticks.
- */
-
-static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct interact *interact;
-	__u32 data[3];
-	int i, t;
-
-	if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
-		return;
-	memset(interact, 0, sizeof(struct interact));
-
-	gameport->private = interact;
-
-	interact->gameport = gameport;
-	init_timer(&interact->timer);
-	interact->timer.data = (long) interact;
-	interact->timer.function = interact_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
-
-	if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
-		goto fail2;
-	}
-
-	for (i = 0; interact_type[i].length; i++)
-		if (interact_type[i].id == (data[2] >> 16))
-			break;
-
-	if (!interact_type[i].length) {
-		printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
-			gameport->number, i, data[0], data[1], data[2]);
-		goto fail2;	
-	}
-
-	interact->type = i;
-	interact->length = interact_type[i].length;
-
-	interact->dev.private = interact;
-	interact->dev.open = interact_open;
-	interact->dev.close = interact_close;
-
-	interact->dev.name = interact_type[i].name;
-	interact->dev.idbus = BUS_GAMEPORT;
-	interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
-	interact->dev.idproduct = interact_type[i].id;
-	interact->dev.idversion = 0x0100;
-
-	interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-	for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
-		set_bit(t, interact->dev.absbit);
-		if (i < interact_type[interact->type].b8) {
-			interact->dev.absmin[t] = 0;
-			interact->dev.absmax[t] = 255;
-		} else {
-			interact->dev.absmin[t] = -1;
-			interact->dev.absmax[t] = 1;
-		}
-	}
-
-	for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
-		set_bit(t, interact->dev.keybit);
-
-	input_register_device(&interact->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		interact->dev.number, interact_type[interact->type].name, gameport->number);
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:  kfree(interact);
-}
-
-static void interact_disconnect(struct gameport *gameport)
-{
-	struct interact *interact = gameport->private;
-	input_unregister_device(&interact->dev);
-	gameport_close(gameport);
-	kfree(interact);
-}
-
-static struct gameport_dev interact_dev = {
-	connect:	interact_connect,
-	disconnect:	interact_disconnect,
-};
-
-int __init interact_init(void)
-{
-	gameport_register_device(&interact_dev);
-	return 0;
-}
-
-void __exit interact_exit(void)
-{
-	gameport_unregister_device(&interact_dev);
-}
-
-module_init(interact_init);
-module_exit(interact_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/lightning.c b/drivers/char/joystick/lightning.c
--- a/drivers/char/joystick/lightning.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,298 +0,0 @@
-/*
- * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * PDPI Lightning 4 gamecard driver for Linux.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-
-#define L4_PORT			0x201
-#define L4_SELECT_ANALOG	0xa4
-#define L4_SELECT_DIGITAL	0xa5
-#define L4_SELECT_SECONDARY	0xa6
-#define L4_CMD_ID		0x80
-#define L4_CMD_GETCAL		0x92
-#define L4_CMD_SETCAL		0x93
-#define L4_ID			0x04
-#define L4_BUSY			0x01
-#define L4_TIMEOUT		80	/* 80 us */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-
-struct l4 {
-	struct gameport gameport;
-	unsigned char port;
-} *l4_port[8];
-
-/*
- * l4_wait_ready() waits for the L4 to become ready.
- */
-
-static int l4_wait_ready(void)
-{
-	unsigned int t;
-	t = L4_TIMEOUT;
-	while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
-	return -(t<=0);
-}
-
-/*
- * l4_cooked_read() reads data from the Lightning 4.
- */
-
-static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-	struct l4 *l4 = gameport->private;
-	unsigned char status;
-	int i, result = -1;
-
-	outb(L4_SELECT_ANALOG, L4_PORT);
-	outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
-
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
-	outb(l4->port & 3, L4_PORT);
-
-	if (l4_wait_ready()) goto fail;
-	status = inb(L4_PORT);
-
-	for (i = 0; i < 4; i++)
-		if (status & (1 << i)) {
-			if (l4_wait_ready()) goto fail;
-			axes[i] = inb(L4_PORT);
-			if (axes[i] > 252) axes[i] = -1;
-		}
-
-	if (status & 0x10) {
-		if (l4_wait_ready()) goto fail;
-		*buttons = inb(L4_PORT) & 0x0f;
-	}
-
-	result = 0;
-
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);	
-	return result;
-}
-
-static int l4_open(struct gameport *gameport, int mode)
-{
-	struct l4 *l4 = gameport->private;
-        if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
-		return -1;
-	outb(L4_SELECT_ANALOG, L4_PORT);
-	return 0;
-}
-
-/*
- * l4_getcal() reads the L4 with calibration values.
- */
-
-static int l4_getcal(int port, int *cal)
-{
-	int i, result = -1;
-	
-	outb(L4_SELECT_ANALOG, L4_PORT);
-	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
-
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
-	outb(L4_CMD_GETCAL, L4_PORT);
-
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
-
-	if (l4_wait_ready()) goto fail;
-        outb(port & 3, L4_PORT);
-
-	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
-		cal[i] = inb(L4_PORT);
-	}
-
-	result = 0;
-
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
-	return result;
-}
-
-/*
- * l4_setcal() programs the L4 with calibration values.
- */
-
-static int l4_setcal(int port, int *cal)
-{
-	int i, result = -1;
-
-	outb(L4_SELECT_ANALOG, L4_PORT);
-	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
-
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
-	outb(L4_CMD_SETCAL, L4_PORT);
-
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
-
-	if (l4_wait_ready()) goto fail;
-        outb(port & 3, L4_PORT);
-
-	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
-		outb(cal[i], L4_PORT);
-	}
-
-	result = 0;
-
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
-	return result;
-}
-
-/*
- * l4_calibrate() calibrates the L4 for the attached device, so
- * that the device's resistance fits into the L4's 8-bit range.
- */
-
-static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
-{
-	int i, t;
-	int cal[4];
-	struct l4 *l4 = gameport->private;
-
-	if (l4_getcal(l4->port, cal))
-		return -1;
-
-	for (i = 0; i < 4; i++) {
-		t = (max[i] * cal[i]) / 200;
-		t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
-		axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
-		axes[i] = (axes[i] > 252) ? 252 : axes[i];
-		cal[i] = t;
-	}
-
-	if (l4_setcal(l4->port, cal))
-		return -1;
-
-	return 0;
-}
-	
-int __init l4_init(void)
-{
-	int cal[4] = {255,255,255,255};
-	int i, j, rev, cards = 0;
-	struct gameport *gameport;
-	struct l4 *l4;
-
-	if (!request_region(L4_PORT, 1, "lightning"))
-		return -1;
-
-	for (i = 0; i < 2; i++) {
-
-		outb(L4_SELECT_ANALOG, L4_PORT);
-		outb(L4_SELECT_DIGITAL + i, L4_PORT);
-
-		if (inb(L4_PORT) & L4_BUSY) continue;
-		outb(L4_CMD_ID, L4_PORT);
-
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
-
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_ID) continue;
-
-		if (l4_wait_ready()) continue;
-		rev = inb(L4_PORT);
-
-		if (!rev) continue;
-
-		if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
-			printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
-			continue;
-		}
-		memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
-
-		for (j = 0; j < 4; j++) {
-
-			l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
-			l4->port = i * 4 + j;
-
-			gameport = &l4->gameport;
-			gameport->private = l4;
-			gameport->open = l4_open;
-			gameport->cooked_read = l4_cooked_read;
-			gameport->calibrate = l4_calibrate;
-
-			if (!i && !j)
-				gameport->io = L4_PORT;
-
-			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
-				l4_setcal(l4->port, cal);
-			
-			gameport_register_port(gameport);
-		}
-
-		printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
-			l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number, 
-			l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number, 
-			i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
-
-		cards++;
-	}
-
-	outb(L4_SELECT_ANALOG, L4_PORT);
-
-	if (!cards) {
-		release_region(L4_PORT, 1);
-		return -1;
-	}
-
-	return 0;
-}
-
-void __init l4_exit(void)
-{
-	int i;
-	int cal[4] = {59, 59, 59, 59};
-
-	for (i = 0; i < 8; i++)
-		if (l4_port[i]) {
-			l4_setcal(l4_port[i]->port, cal);
-			gameport_unregister_port(&l4_port[i]->gameport);
-		}
-	outb(L4_SELECT_ANALOG, L4_PORT);
-	release_region(L4_PORT, 1);
-}
-
-module_init(l4_init);
-module_exit(l4_exit);
diff -Nru a/drivers/char/joystick/magellan.c b/drivers/char/joystick/magellan.c
--- a/drivers/char/joystick/magellan.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,212 +0,0 @@
-/*
- * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Magellan and Space Mouse 6dof controller driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Definitions & global arrays.
- */
-
-#define	MAGELLAN_MAX_LENGTH	32
-
-static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
-static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *magellan_name = "LogiCad3D Magellan";
-
-/*
- * Per-Magellan data.
- */
-
-struct magellan {
-	struct input_dev dev;
-	int idx;
-	unsigned char data[MAGELLAN_MAX_LENGTH];
-};
-
-/*
- * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
- * have correct upper nibbles for the lower ones, if not, the packet will
- * be thrown away. It also strips these upper halves to simplify further
- * processing.
- */
-
-static int magellan_crunch_nibbles(unsigned char *data, int count)
-{
-	static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
-
-	do {
-		if (data[count] == nibbles[data[count] & 0xf])
-			data[count] = data[count] & 0xf;
-		else
-			return -1;
-	} while (--count);
-
-	return 0;
-}
-
-static void magellan_process_packet(struct magellan* magellan)
-{
-	struct input_dev *dev = &magellan->dev;
-	unsigned char *data = magellan->data;
-	int i, t;
-
-	if (!magellan->idx) return;
-
-	switch (magellan->data[0]) {
-
-		case 'd':				/* Axis data */
-			if (magellan->idx != 25) return;
-			if (magellan_crunch_nibbles(data, 24)) return;
-			for (i = 0; i < 6; i++)
-				input_report_abs(dev, magellan_axes[i],
-					(data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
-					 data[(i << 2) + 3] <<  4 | data[(i << 2) + 4]) - 32768);
-			break;
-
-		case 'k':				/* Button data */
-			if (magellan->idx != 4) return;
-			if (magellan_crunch_nibbles(data, 3)) return;
-			t = (data[1] << 1) | (data[2] << 5) | data[3];
-			for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
-			break;
-	}
-}
-
-static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct magellan* magellan = serio->private;
-
-	if (data == '\r') {
-		magellan_process_packet(magellan);
-		magellan->idx = 0;
-	} else {
-		if (magellan->idx < MAGELLAN_MAX_LENGTH)
-			magellan->data[magellan->idx++] = data;
-	} 
-}
-
-/*
- * magellan_disconnect() is the opposite of magellan_connect()
- */
-
-static void magellan_disconnect(struct serio *serio)
-{
-	struct magellan* magellan = serio->private;
-	input_unregister_device(&magellan->dev);
-	serio_close(serio);
-	kfree(magellan);
-}
-
-/*
- * magellan_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
- */
-
-static void magellan_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct magellan *magellan;
-	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
-		return;
-
-	if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
-		return;
-
-	memset(magellan, 0, sizeof(struct magellan));
-
-	magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-
-	for (i = 0; i < 9; i++)
-		set_bit(magellan_buttons[i], &magellan->dev.keybit);
-
-	for (i = 0; i < 6; i++) {
-		t = magellan_axes[i];
-		set_bit(t, magellan->dev.absbit);
-		magellan->dev.absmin[t] = -360;
-		magellan->dev.absmax[t] =  360;
-	}
-
-	magellan->dev.private = magellan;
-	magellan->dev.name = magellan_name;
-	magellan->dev.idbus = BUS_RS232;
-	magellan->dev.idvendor = SERIO_MAGELLAN;
-	magellan->dev.idproduct = 0x0001;
-	magellan->dev.idversion = 0x0100;
-	
-	serio->private = magellan;
-
-	if (serio_open(serio, dev)) {
-		kfree(magellan);
-		return;
-	}
-
-	input_register_device(&magellan->dev);
-
-	printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev magellan_dev = {
-	interrupt:	magellan_interrupt,
-	connect:	magellan_connect,
-	disconnect:	magellan_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init magellan_init(void)
-{
-	serio_register_device(&magellan_dev);
-	return 0;
-}
-
-void __exit magellan_exit(void)
-{
-	serio_unregister_device(&magellan_dev);
-}
-
-module_init(magellan_init);
-module_exit(magellan_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c
--- a/drivers/char/joystick/ns558.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,285 +0,0 @@
-/*
- * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *  Copyright (c) 1999 Brian Gerst
- *
- *  Sponsored by SuSE
- */
-
-/*
- * NS558 based standard IBM game port driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/isapnp.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-#define NS558_ISA	1
-#define NS558_PNP	2
-
-static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
-				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
-
-struct ns558 {
-	int type;
-	int size;
-	struct pci_dev *dev;
-	struct ns558 *next;
-	struct gameport gameport;
-};
-	
-static struct ns558 *ns558;
-
-/*
- * ns558_isa_probe() tries to find an isa gameport at the
- * specified address, and also checks for mirrors.
- * A joystick must be attached for this to work.
- */
-
-static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
-{
-	int i, j, b;
-	unsigned char c, u, v;
-	struct ns558 *port;
-
-/*
- * No one should be using this address.
- */
-
-	if (check_region(io, 1))
-		return next;
-
-/*
- * We must not be able to write arbitrary values to the port.
- * The lower two axis bits must be 1 after a write.
- */
-
-	c = inb(io);
-	outb(~c & ~3, io);
-	if (~(u = v = inb(io)) & 3) {
-		outb(c, io);
-		return next;
-	}
-/*
- * After a trigger, there must be at least some bits changing.
- */
-
-	for (i = 0; i < 1000; i++) v &= inb(io);
-
-	if (u == v) {
-		outb(c, io);
-		return next;
-	}
-	wait_ms(3);
-/*
- * After some time (4ms) the axes shouldn't change anymore.
- */
-
-	u = inb(io);
-	for (i = 0; i < 1000; i++)
-		if ((u ^ inb(io)) & 0xf) {
-			outb(c, io);
-			return next;
-		}
-/* 
- * And now find the number of mirrors of the port.
- */
-
-	for (i = 1; i < 5; i++) {
-
-		if (check_region(io & (-1 << i), (1 << i)))	/* Don't disturb anyone */
-			break;
-
-		outb(0xff, io & (-1 << i));
-		for (j = b = 0; j < 1000; j++)
-			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
-		wait_ms(3);
-
-		if (b > 300)					/* We allow 30% difference */
-			break;
-	}
-
-	i--;
-
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		return next;
-	}
-       	memset(port, 0, sizeof(struct ns558));
-	
-	port->next = next;
-	port->type = NS558_ISA;
-	port->size = (1 << i);
-	port->gameport.io = io & (-1 << i);
-
-	request_region(port->gameport.io, (1 << i), "ns558-isa");
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
-	if (port->size > 1) printk(" size %d", port->size);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	return port;
-}
-
-#ifdef __ISAPNP__
-
-static struct isapnp_device_id pnp_devids[] = {
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
-	{ 0, },
-};
-
-MODULE_DEVICE_TABLE(isapnp, pnp_devids);
-
-static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
-{
-	int ioport, iolen;
-	struct ns558 *port;
-
-	if (dev->prepare && dev->prepare(dev) < 0)
-		return next;
-
-	if (!(dev->resource[0].flags & IORESOURCE_IO)) {
-		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
-		return next;
-	}
-
-	if (dev->activate && dev->activate(dev) < 0) {
-		printk(KERN_ERR "ns558: PnP resource allocation failed\n");
-		return next;
-	}
-	
-	ioport = pci_resource_start(dev, 0);
-	iolen = pci_resource_len(dev, 0);
-
-	if (!request_region(ioport, iolen, "ns558-pnp"))
-		goto deactivate;
-
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		goto deactivate;
-	}
-	memset(port, 0, sizeof(struct ns558));
-
-	port->next = next;
-	port->type = NS558_PNP;
-	port->gameport.io = ioport;
-	port->size = iolen;
-	port->dev = dev;
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
-	if (iolen > 1) printk(" size %d", iolen);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	return port;
-
-deactivate:
-	if (dev->deactivate)
-		dev->deactivate(dev);
-	return next;
-}
-#endif
-
-int __init ns558_init(void)
-{
-	int i = 0;
-#ifdef __ISAPNP__
-	struct isapnp_device_id *devid;
-	struct pci_dev *dev = NULL;
-#endif
-
-/*
- * Probe for ISA ports.
- */
-
-	while (ns558_isa_portlist[i]) 
-		ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
-
-/*
- * Probe for PnP ports.
- */
-
-#ifdef __ISAPNP__
-	for (devid = pnp_devids; devid->vendor; devid++) {
-		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
-			ns558 = ns558_pnp_probe(dev, ns558);
-		}
-	}
-#endif
-
-	return ns558 ? 0 : -ENODEV;
-}
-
-void __exit ns558_exit(void)
-{
-	struct ns558 *next, *port = ns558;
-
-	while (port) {
-		gameport_unregister_port(&port->gameport);
-		switch (port->type) {
-
-#ifdef __ISAPNP__
-			case NS558_PNP:
-				if (port->dev->deactivate)
-					port->dev->deactivate(port->dev);
-				/* fall through */
-#endif
-
-			case NS558_ISA:
-				release_region(port->gameport.io, port->size);
-				break;
-		
-			default:
-				break;
-		}
-		
-		next = port->next;
-		kfree(port);
-		port = next;
-	}
-}
-
-module_init(ns558_init);
-module_exit(ns558_exit);
diff -Nru a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c
--- a/drivers/char/joystick/pcigame.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,199 +0,0 @@
-/*
- * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Raymond Ingles
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/gameport.h>
-
-#define PCI_VENDOR_ID_AUREAL	0x12eb
-
-#define PCIGAME_DATA_WAIT	20	/* 20 ms */
-
-#define PCIGAME_4DWAVE		0
-#define PCIGAME_VORTEX		1
-#define PCIGAME_VORTEX2		2
-
-struct pcigame_data {
-	int gcr;	/* Gameport control register */
-	int legacy;	/* Legacy port location */
-	int axes;	/* Axes start */
-	int axsize;	/* Axis field size */
-	int axmax;	/* Axis field max value */
-	int adcmode;	/* Value to enable ADC mode in GCR */
-};
-
-static struct pcigame_data pcigame_data[] __devinitdata =
-{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
- { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
- { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
- { 0 }};
-
-struct pcigame {
-	struct gameport gameport;
-	struct pci_dev *dev;
-        unsigned char *base;
-	struct pcigame_data *data;
-};
-
-static unsigned char pcigame_read(struct gameport *gameport)
-{
-	struct pcigame *pcigame = gameport->private;
-	return readb(pcigame->base + pcigame->data->legacy);
-}
-
-static void pcigame_trigger(struct gameport *gameport)
-{
-	struct pcigame *pcigame = gameport->private;
-	writeb(0xff, pcigame->base + pcigame->data->legacy);
-}
-
-static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
-        struct pcigame *pcigame = gameport->private;
-	int i;
-
-	*buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
-
-	for (i = 0; i < 4; i++) {
-		axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
-		if (axes[i] == pcigame->data->axmax) axes[i] = -1;
-	}
-        
-        return 0;
-}
-
-static int pcigame_open(struct gameport *gameport, int mode)
-{
-	struct pcigame *pcigame = gameport->private;
-
-	switch (mode) {
-		case GAMEPORT_MODE_COOKED:
-			writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
-			wait_ms(PCIGAME_DATA_WAIT);
-			return 0;
-		case GAMEPORT_MODE_RAW:
-			writeb(0, pcigame->base + pcigame->data->gcr);
-			return 0;
-		default:
-			return -1;
-	}
-
-	return 0;
-}
-
-static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	struct pcigame *pcigame;
-	int i;
-
-	if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
-		return -1;
-        memset(pcigame, 0, sizeof(struct pcigame));
-
-
-	pcigame->data = pcigame_data + id->driver_data;
-
-	pcigame->dev = dev;
-	pci_set_drvdata(dev, pcigame);
-
-	pcigame->gameport.private = pcigame;
-	pcigame->gameport.fuzz = 64;
-	
-	pcigame->gameport.read = pcigame_read;
-	pcigame->gameport.trigger = pcigame_trigger;
-	pcigame->gameport.cooked_read = pcigame_cooked_read;
-	pcigame->gameport.open = pcigame_open;
-
-	for (i = 0; i < 6; i++)
-		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
-			break;
-
-	pci_enable_device(dev);
-
-	pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
-				pci_resource_len(pcigame->dev, i));
-
-	gameport_register_port(&pcigame->gameport);
-	
-	printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
-		pcigame->gameport.number, dev->name, dev->bus->number,
-			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
-
-	return 0;
-}
-
-static void __devexit pcigame_remove(struct pci_dev *dev)
-{
-	struct pcigame *pcigame = pci_get_drvdata(dev);
-	gameport_unregister_port(&pcigame->gameport);
-	iounmap(pcigame->base);
-	kfree(pcigame);
-}
-
-static struct pci_device_id pcigame_id_table[] __devinitdata =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
- { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
- { PCI_VENDOR_ID_AUREAL,  0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX  },
- { PCI_VENDOR_ID_AUREAL,  0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
- { 0 }};
-
-static struct pci_driver pcigame_driver = {
-	name:		"pcigame",
-	id_table:	pcigame_id_table,
-	probe:		pcigame_probe,
-	remove:		pcigame_remove,
-};
-
-int __init pcigame_init(void)
-{
-	return pci_module_init(&pcigame_driver);
-}
-
-void __exit pcigame_exit(void)
-{
-	pci_unregister_driver(&pcigame_driver);
-}
-
-module_init(pcigame_init);
-module_exit(pcigame_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/serio.c b/drivers/char/joystick/serio.c
--- a/drivers/char/joystick/serio.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,133 +0,0 @@
-/*
- * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- *  The Serio abstraction module
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/stddef.h>
-#include <linux/module.h>
-#include <linux/serio.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(serio_register_port);
-EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_register_device);
-EXPORT_SYMBOL(serio_unregister_device);
-EXPORT_SYMBOL(serio_open);
-EXPORT_SYMBOL(serio_close);
-EXPORT_SYMBOL(serio_rescan);
-
-static struct serio *serio_list;
-static struct serio_dev *serio_dev;
-static int serio_number;
-
-static void serio_find_dev(struct serio *serio)
-{
-        struct serio_dev *dev = serio_dev;
-
-        while (dev && !serio->dev) {
-		if (dev->connect)
-                	dev->connect(serio, dev);
-                dev = dev->next;
-        }
-}
-
-void serio_rescan(struct serio *serio)
-{
-	if (serio->dev && serio->dev->disconnect)
-		serio->dev->disconnect(serio);
-	serio_find_dev(serio);
-}
-
-void serio_register_port(struct serio *serio)
-{
-	serio->number = serio_number++;
-	serio->next = serio_list;	
-	serio_list = serio;
-	serio_find_dev(serio);
-}
-
-void serio_unregister_port(struct serio *serio)
-{
-        struct serio **serioptr = &serio_list;
-
-        while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
-        *serioptr = (*serioptr)->next;
-
-	if (serio->dev && serio->dev->disconnect)
-		serio->dev->disconnect(serio);
-
-	serio_number--;
-}
-
-void serio_register_device(struct serio_dev *dev)
-{
-	struct serio *serio = serio_list;
-
-	dev->next = serio_dev;	
-	serio_dev = dev;
-
-	while (serio) {
-		if (!serio->dev && dev->connect)
-			dev->connect(serio, dev);
-		serio = serio->next;
-	}
-}
-
-void serio_unregister_device(struct serio_dev *dev)
-{
-        struct serio_dev **devptr = &serio_dev;
-	struct serio *serio = serio_list;
-
-        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
-        *devptr = (*devptr)->next;
-
-	while (serio) {
-		if (serio->dev == dev && dev->disconnect)
-			dev->disconnect(serio);
-		serio_find_dev(serio);
-		serio = serio->next;
-	}
-}
-
-int serio_open(struct serio *serio, struct serio_dev *dev)
-{
-	if (serio->open(serio))
-		return -1;
-	serio->dev = dev;
-	return 0;
-}
-
-void serio_close(struct serio *serio)
-{
-	serio->close(serio);
-	serio->dev = NULL;
-}
diff -Nru a/drivers/char/joystick/serport.c b/drivers/char/joystick/serport.c
--- a/drivers/char/joystick/serport.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,226 +0,0 @@
-/*
- * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * This is a module that converts a tty line into a much simpler
- * 'serial io port' abstraction that the input device drivers use.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/uaccess.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serio.h>
-#include <linux/tty.h>
-
-struct serport {
-	struct tty_struct *tty;
-	wait_queue_head_t wait;
-	struct serio serio;
-};
-
-/*
- * Callback functions from the serio code.
- */
-
-static int serport_serio_write(struct serio *serio, unsigned char data)
-{
-	struct serport *serport = serio->driver;
-	return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
-}
-
-static int serport_serio_open(struct serio *serio)
-{
-        return 0;
-}
-
-static void serport_serio_close(struct serio *serio)
-{
-	struct serport *serport = serio->driver;
-	wake_up_interruptible(&serport->wait);
-}
-
-/*
- * serport_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty. It looks for the Mag, and if found, registers
- * it as a joystick device.
- */
-
-static int serport_ldisc_open(struct tty_struct *tty)
-{
-	struct serport *serport;
-
-	MOD_INC_USE_COUNT;
-
-	if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-
-	memset(serport, 0, sizeof(struct serport));
-
-	serport->tty = tty;
-	tty->disc_data = serport;
-
-	serport->serio.type = SERIO_RS232;
-	serport->serio.write = serport_serio_write;
-	serport->serio.open = serport_serio_open;
-	serport->serio.close = serport_serio_close;
-	serport->serio.driver = serport;
-
-	init_waitqueue_head(&serport->wait);
-
-	return 0;
-}
-
-/*
- * serport_ldisc_close() is the opposite of serport_ldisc_open()
- */
-
-static void serport_ldisc_close(struct tty_struct *tty)
-{
-	struct serport *serport = (struct serport*) tty->disc_data;
-	kfree(serport);
-	MOD_DEC_USE_COUNT;
-}
-
-/*
- * serport_ldisc_receive() is called by the low level tty driver when characters
- * are ready for us. We forward the characters, one by one to the 'interrupt'
- * routine.
- */
-
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
-	struct serport *serport = (struct serport*) tty->disc_data;
-	int i;
-	for (i = 0; i < count; i++)
-		if (serport->serio.dev)
-			serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
-}
-
-/*
- * serport_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, and 256 seems to be reasonable.
- */
-
-static int serport_ldisc_room(struct tty_struct *tty)
-{
-	return 256;
-}
-
-/*
- * serport_ldisc_read() just waits indefinitely if everything goes well. 
- * However, when the serio driver closes the serio port, it finishes,
- * returning 0 characters.
- */
-
-static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
-{
-	struct serport *serport = (struct serport*) tty->disc_data;
-	DECLARE_WAITQUEUE(wait, current);
-	char name[32];
-
-#ifdef CONFIG_DEVFS_FS
-	sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#else
-	sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#endif
-
-	serio_register_port(&serport->serio);
-
-	printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
-
-	add_wait_queue(&serport->wait, &wait);
-	current->state = TASK_INTERRUPTIBLE;
-
-	while(serport->serio.type && !signal_pending(current)) schedule();
-
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&serport->wait, &wait);
-
-	serio_unregister_port(&serport->serio);
-
-	return 0;
-}
-
-/*
- * serport_ldisc_ioctl() allows to set the port protocol, and device ID
- */
-
-static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct serport *serport = (struct serport*) tty->disc_data;
-	
-	switch (cmd) {
-		case SPIOCSTYPE:
-			return get_user(serport->serio.type, (unsigned long *) arg);
-	}
-
-	return -EINVAL;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc serport_ldisc = {
-	name:		"input",
-	open:		serport_ldisc_open,
-	close:		serport_ldisc_close,
-	read:		serport_ldisc_read,
-	ioctl:		serport_ldisc_ioctl,
-	receive_buf:	serport_ldisc_receive,
-	receive_room:	serport_ldisc_room,
-};
-
-/*
- * The functions for insering/removing us as a module.
- */
-
-int __init serport_init(void)
-{
-        if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
-                printk(KERN_ERR "serport.c: Error registering line discipline.\n");
-		return -ENODEV;
-	}
-
-	return  0;
-}
-
-void __exit serport_exit(void)
-{
-	tty_register_ldisc(N_MOUSE, NULL);
-}
-
-module_init(serport_init);
-module_exit(serport_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c
--- a/drivers/char/joystick/sidewinder.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,761 +0,0 @@
-/*
- * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Microsoft SideWinder joystick family driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-
-/*
- * These are really magic values. Changing them can make a problem go away,
- * as well as break everything.
- */
-
-#undef SW_DEBUG
-
-#define SW_START	400	/* The time we wait for the first bit [400 us] */
-#define SW_STROBE	45	/* Max time per bit [45 us] */
-#define SW_TIMEOUT	4000	/* Wait for everything to settle [4 ms] */
-#define SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
-#define SW_END		8	/* Number of bits before end of packet to kick */
-#define SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
-#define SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
-#define SW_OK		64	/* Number of packet read successes to switch optimization back on */
-#define SW_LENGTH	512	/* Max number of bits in a packet */
-#define SW_REFRESH	HZ/50	/* Time to wait between updates of joystick data [20 ms] */
-
-#ifdef SW_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-
-/*
- * SideWinder joystick types ...
- */
-
-#define SW_ID_3DP	0
-#define SW_ID_GP	1
-#define SW_ID_PP	2
-#define SW_ID_FFP	3
-#define SW_ID_FSP	4
-#define SW_ID_FFW	5
-
-/*
- * Names, buttons, axes ...
- */
-
-static char *sw_name[] = {	"3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
-				"Force Feedback Wheel" };
-
-static char sw_abs[][7] = {
-	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
-	{ ABS_X, ABS_Y },
-	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
-	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
-	{ ABS_X, ABS_Y,         ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
-	{ ABS_RX, ABS_RUDDER,   ABS_THROTTLE }};
-
-static char sw_bit[][7] = {
-	{ 10, 10,  9, 10,  1,  1 },
-	{  1,  1                 },
-	{ 10, 10,  6,  7,  1,  1 },
-	{ 10, 10,  6,  7,  1,  1 },
-	{ 10, 10,  6,  1,  1     },
-	{ 10,  7,  7,  1,  1     }};
-
-static short sw_btn[][12] = {
-	{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
-	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
-	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
-	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
-	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
-	{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
-
-static struct {
-	int x;
-	int y;
-} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-struct sw {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct input_dev dev[4];
-	char name[64];
-	int length;
-	int type;
-	int bits;
-	int number;
-	int fail;
-	int ok;
-	int reads;
-	int bads;
-	int used;
-};
-
-/*
- * sw_read_packet() is a function which reads either a data packet, or an
- * identification packet from a SideWinder joystick. The protocol is very,
- * very, very braindamaged. Microsoft patented it in US patent #5628686.
- */
-
-static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
-{
-	unsigned long flags;
-	int timeout, bitout, sched, i, kick, start, strobe;
-	unsigned char pending, u, v;
-
-	i = -id;						/* Don't care about data, only want ID */
-	timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0;	/* Set up global timeout for ID packet */
-	kick = id ? gameport_time(gameport, SW_KICK) : 0;	/* Set up kick timeout for ID packet */
-	start = gameport_time(gameport, SW_START);
-	strobe = gameport_time(gameport, SW_STROBE);
-	bitout = start;
-	pending = 0;
-	sched = 0;
-
-        __save_flags(flags);					/* Quiet, please */
-        __cli();
-
-	gameport_trigger(gameport);				/* Trigger */
-	v = gameport_read(gameport);
-
-	do {
-		bitout--;
-		u = v;
-		v = gameport_read(gameport);
-	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */
-
-	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */
-
-	while ((timeout > 0 || bitout > 0) && (i < length)) {
-
-		timeout--;
-		bitout--;					/* Decrement timers */
-		sched--;
-
-		u = v;
-		v = gameport_read(gameport);
-
-		if ((~u & v & 0x10) && (bitout > 0)) {		/* Rising edge on clock - data bit */
-			if (i >= 0)				/* Want this data */
-				buf[i] = v >> 5;		/* Store it */
-			i++;					/* Advance index */
-			bitout = strobe;			/* Extend timeout for next bit */
-		} 
-
-		if (kick && (~v & u & 0x01)) {			/* Falling edge on axis 0 */
-			sched = kick;				/* Schedule second trigger */
-			kick = 0;				/* Don't schedule next time on falling edge */
-			pending = 1;				/* Mark schedule */
-		} 
-
-		if (pending && sched < 0 && (i > -SW_END)) {	/* Second trigger time */
-			gameport_trigger(gameport);		/* Trigger */
-			bitout = start;				/* Long bit timeout */
-			pending = 0;				/* Unmark schedule */
-			timeout = 0;				/* Switch from global to bit timeouts */ 
-		}
-	}
-
-	__restore_flags(flags);					/* Done - relax */
-
-#ifdef SW_DEBUG
-	{
-		int j;
-		printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
-		for (j = 0; j < i; j++) printk("%d", buf[j]);
-		printk("]\n");
-	}
-#endif
-
-	return i;
-}
-
-/*
- * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
- * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
- * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
- * is number of bits per triplet.
- */
-
-#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
-
-static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
-{
-	__u64 data = 0;
-	int tri = pos % bits;						/* Start position */
-	int i   = pos / bits;
-	int bit = 0;
-
-	while (num--) {
-		data |= (__u64)((buf[i] >> tri++) & 1) << bit++;	/* Transfer bit */
-		if (tri == bits) {
-			i++;						/* Next triplet */
-			tri = 0;
-		}
-	}
-
-	return data;
-}
-
-/*
- * sw_init_digital() initializes a SideWinder 3D Pro joystick
- * into digital mode.
- */
-
-static void sw_init_digital(struct gameport *gameport)
-{
-	int seq[] = { 140, 140+725, 140+300, 0 };
-	unsigned long flags;
-	int i, t;
-
-        __save_flags(flags);
-        __cli();
-
-	i = 0;
-        do {
-                gameport_trigger(gameport);			/* Trigger */
-		t = gameport_time(gameport, SW_TIMEOUT);
-		while ((gameport_read(gameport) & 1) && t) t--;	/* Wait for axis to fall back to 0 */
-                udelay(seq[i]);					/* Delay magic time */
-        } while (seq[++i]);
-
-	gameport_trigger(gameport);				/* Last trigger */
-
-	__restore_flags(flags);
-}
-
-/*
- * sw_parity() computes parity of __u64
- */
-
-static int sw_parity(__u64 t)
-{
-	int x = t ^ (t >> 32);
-	x ^= x >> 16;
-	x ^= x >> 8;
-	x ^= x >> 4;
-	x ^= x >> 2;
-	x ^= x >> 1;
-	return x & 1;
-}
-
-/*
- * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
- */
-
-static int sw_check(__u64 t)
-{
-	unsigned char sum = 0;
-
-	if ((t & 0x8080808080808080ULL) ^ 0x80)			/* Sync */
-		return -1;
-
-	while (t) {						/* Sum */
-		sum += t & 0xf;
-		t >>= 4;
-	}
-
-	return sum & 0xf;
-}
-
-/*
- * sw_parse() analyzes SideWinder joystick data, and writes the results into
- * the axes and buttons arrays.
- */
-
-static int sw_parse(unsigned char *buf, struct sw *sw)
-{
-	int hat, i, j;
-	struct input_dev *dev = sw->dev;
-
-	switch (sw->type) {
-
-		case SW_ID_3DP:
-
-			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
-
-			input_report_abs(dev, ABS_X,        (GB( 3,3) << 7) | GB(16,7));
-			input_report_abs(dev, ABS_Y,        (GB( 0,3) << 7) | GB(24,7));
-			input_report_abs(dev, ABS_RZ,       (GB(35,2) << 7) | GB(40,7));
-			input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
-
-			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
-			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
-			for (j = 0; j < 7; j++)
-				input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
-
-			input_report_key(dev, BTN_BASE4, !GB(38,1));
-			input_report_key(dev, BTN_BASE5, !GB(37,1));
-
-			return 0;
-
-		case SW_ID_GP:
-
-			for (i = 0; i < sw->number; i ++) {
-
-				if (sw_parity(GB(i*15,15))) return -1;
-
-				input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
-				input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
-
-				for (j = 0; j < 10; j++)
-					input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
-			}
-
-			return 0;
-
-		case SW_ID_PP:
-		case SW_ID_FFP:
-
-			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
-
-			input_report_abs(dev, ABS_X,        GB( 9,10));
-			input_report_abs(dev, ABS_Y,        GB(19,10));
-			input_report_abs(dev, ABS_RZ,       GB(36, 6));
-			input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
-
-			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
-			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
-			for (j = 0; j < 9; j++)
-				input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
-
-			return 0;
-
-		case SW_ID_FSP:
-
-			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
-
-			input_report_abs(dev, ABS_X,        GB( 0,10));
-			input_report_abs(dev, ABS_Y,        GB(16,10));
-			input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
-
-			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
-			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
-			for (j = 0; j < 6; j++)
-				input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
-
-			input_report_key(dev, BTN_TR,     GB(26,1));
-			input_report_key(dev, BTN_START,  GB(27,1));
-			input_report_key(dev, BTN_MODE,   GB(38,1));
-			input_report_key(dev, BTN_SELECT, GB(39,1));
-
-			return 0;
-
-		case SW_ID_FFW:
-
-			if (!sw_parity(GB(0,33))) return -1;
-
-			input_report_abs(dev, ABS_RX,       GB( 0,10));
-			input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
-			input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
-
-			for (j = 0; j < 8; j++)
-				input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
-
-			return 0;
-	}
-
-	return -1;
-}
-
-/*
- * sw_read() reads SideWinder joystick data, and reinitializes
- * the joystick in case of persistent problems. This is the function that is
- * called from the generic code to poll the joystick.
- */
-
-static int sw_read(struct sw *sw)
-{
-	unsigned char buf[SW_LENGTH];
-	int i;
-
-	i = sw_read_packet(sw->gameport, buf, sw->length, 0);
-
-	if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) {		/* Broken packet, try to fix */
-
-		if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) {		/* Last init failed, 1 bit mode */
-			printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
-				" - going to reinitialize.\n", sw->gameport->number);
-			sw->fail = SW_FAIL;					/* Reinitialize */
-			i = 128;						/* Bogus value */
-		}
-
-		if (i < 66 && GB(0,64) == GB(i*3-66,64))			/* 1 == 3 */
-			i = 66;							/* Everything is fine */
-
-		if (i < 66 && GB(0,64) == GB(66,64))				/* 1 == 2 */
-			i = 66;							/* Everything is fine */
-
-		if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) {		/* 2 == 3 */
-			memmove(buf, buf + i - 22, 22);				/* Move data */
-			i = 66;							/* Carry on */
-		}
-	}
-
-	if (i == sw->length && !sw_parse(buf, sw)) {				/* Parse data */
-
-		sw->fail = 0;
-		sw->ok++;
-
-		if (sw->type == SW_ID_3DP && sw->length == 66			/* Many packets OK */
-			&& sw->ok > SW_OK) {
-
-			printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
-				" - enabling optimization again.\n", sw->gameport->number);
-			sw->length = 22;
-		}
-
-		return 0;
-	}
-
-	sw->ok = 0;
-	sw->fail++;
-
-	if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) {	/* Consecutive bad packets */
-
-		printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
-			" - disabling optimization.\n", sw->gameport->number);
-		sw->length = 66;
-	}
-
-	if (sw->fail < SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
-
-	printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
-		" - reinitializing joystick.\n", sw->gameport->number);
-
-	if (!i && sw->type == SW_ID_3DP) {					/* 3D Pro can be in analog mode */
-		udelay(3 * SW_TIMEOUT);
-		sw_init_digital(sw->gameport);
-	}
-
-	udelay(SW_TIMEOUT);
-	i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);			/* Read normal data packet */
-	udelay(SW_TIMEOUT);
-	sw_read_packet(sw->gameport, buf, SW_LENGTH, i);			/* Read ID packet, this initializes the stick */
-
-	sw->fail = SW_FAIL;
-	
-	return -1;
-}
-
-static void sw_timer(unsigned long private)
-{
-	struct sw *sw = (void *) private;
-	
-	sw->reads++;
-	if (sw_read(sw)) sw->bads++;
-	mod_timer(&sw->timer, jiffies + SW_REFRESH);
-}
-
-static int sw_open(struct input_dev *dev)
-{
-	struct sw *sw = dev->private;
-	if (!sw->used++)
-		mod_timer(&sw->timer, jiffies + SW_REFRESH);
-	return 0;
-}
-
-static void sw_close(struct input_dev *dev)
-{
-	struct sw *sw = dev->private;
-	if (!--sw->used)
-		del_timer(&sw->timer);
-}
-
-/*
- * sw_print_packet() prints the contents of a SideWinder packet.
- */
-
-static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
-{
-	int i;
-
-	printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
-	for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
-		printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
-	printk("]\n");
-}
-
-/*
- * sw_3dp_id() translates the 3DP id into a human legible string.
- * Unfortunately I don't know how to do this for the other SW types.
- */
-
-static void sw_3dp_id(unsigned char *buf, char *comment)
-{
-	int i;
-	char pnp[8], rev[9];
-
-	for (i = 0; i < 7; i++)						/* ASCII PnP ID */
-		pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
-
-	for (i = 0; i < 8; i++)						/* ASCII firmware revision */
-		rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
-
-	pnp[7] = rev[8] = 0;
-
-	sprintf(comment, " [PnP %d.%02d id %s rev %s]",
-		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |		/* Two 6-bit values */
-			sw_get_bits(buf, 16, 6, 1)) / 100,
-		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
-			sw_get_bits(buf, 16, 6, 1)) % 100,
-		 pnp, rev);
-}
-
-/*
- * sw_guess_mode() checks the upper two button bits for toggling -
- * indication of that the joystick is in 3-bit mode. This is documented
- * behavior for 3DP ID packet, and for example the FSP does this in
- * normal packets instead. Fun ...
- */
-
-static int sw_guess_mode(unsigned char *buf, int len)
-{
-	int i;
-	unsigned char xor = 0;
-	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
-	return !!xor * 2 + 1;
-}
-
-/*
- * sw_connect() probes for SideWinder type joysticks.
- */
-
-static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct sw *sw;
-	int i, j, k, l;
-	unsigned char buf[SW_LENGTH];
-	unsigned char idbuf[SW_LENGTH];
-	unsigned char m = 1;
-	char comment[40];
-
-	comment[0] = 0;
-
-	if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
-	memset(sw, 0, sizeof(struct sw));
-
-	gameport->private = sw;
-
-	sw->gameport = gameport;
-	init_timer(&sw->timer);
-	sw->timer.data = (long) sw;
-	sw->timer.function = sw_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	dbg("Init 0: Opened gameport %d, io %#x, speed %d",
-		gameport->number, gameport->io, gameport->speed);
-
-	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
-	m |= sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
-	udelay(SW_TIMEOUT);
-	dbg("Init 1: Mode %d. Length %d.", m , i);
-
-	if (!i) {							/* No data. 3d Pro analog mode? */
-		sw_init_digital(gameport);				/* Switch to digital */
-		udelay(SW_TIMEOUT);
-		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
-		udelay(SW_TIMEOUT);
-		dbg("Init 1b: Length %d.", i);
-		if (!i) goto fail2;					/* No data -> FAIL */
-	}
-
-	j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);		/* Read ID. This initializes the stick */
-	m |= sw_guess_mode(idbuf, j);					/* ID packet should carry mode info [3DP] */
-	dbg("Init 2: Mode %d. ID Length %d.", m , j);
-
-	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
-		udelay(SW_TIMEOUT);
-		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
-		dbg("Init 2b: Mode %d. Length %d.", m, i);
-		if (!i) goto fail2;
-		udelay(SW_TIMEOUT);
-		j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);	/* Retry reading ID */
-		dbg("Init 2c: ID Length %d.", j);
-	}
-
-	sw->type = -1;
-	k = SW_FAIL;							/* Try SW_FAIL times */
-	l = 0;
-
-	do {
-		k--;
-		udelay(SW_TIMEOUT);
-		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Read data packet */
-		dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
-
-		if (i > l) {						/* Longer? As we can only lose bits, it makes */
-									/* no sense to try detection for a packet shorter */
-			l = i;						/* than the previous one */
-
-			sw->number = 1;
-			sw->gameport = gameport;
-			sw->length = i;
-			sw->bits = m;
-
-			dbg("Init 3a: Case %d.\n", i * m);
-
-			switch (i * m) {
-				case 60:
-					sw->number++;
-				case 45:				/* Ambiguous packet length */
-					if (j <= 40) {			/* ID length less or eq 40 -> FSP */	
-				case 43:
-						sw->type = SW_ID_FSP;
-						break;
-					}
-					sw->number++;
-				case 30:
-					sw->number++;
-				case 15:
-					sw->type = SW_ID_GP;
-					break;
-				case 33:
-				case 31:
-					sw->type = SW_ID_FFW;
-					break;
-				case 48:				/* Ambiguous */
-					if (j == 14) {			/* ID length 14*3 -> FFP */
-						sw->type = SW_ID_FFP;
-						sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
-					} else
-					sw->type = SW_ID_PP;
-					break;
-				case 198:
-					sw->length = 22;
-				case 64:
-					sw->type = SW_ID_3DP;
-					if (j == 160) sw_3dp_id(idbuf, comment);
-					break;
-			}
-		}
-
-	} while (k && (sw->type == -1));
-
-	if (sw->type == -1) {
-		printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
-			"on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
-		sw_print_packet("ID", j * 3, idbuf, 3);
-		sw_print_packet("Data", i * m, buf, m);
-		goto fail2;
-	}
-
-#ifdef SW_DEBUG
-	sw_print_packet("ID", j * 3, idbuf, 3);
-	sw_print_packet("Data", i * m, buf, m);
-#endif
-
-	k = i;
-	l = j;
-
-	for (i = 0; i < sw->number; i++) {
-		int bits, code;
-
-		sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
-
-		sw->dev[i].private = sw;
-
-		sw->dev[i].open = sw_open;
-		sw->dev[i].close = sw_close;
-
-		sw->dev[i].name = sw->name;
-		sw->dev[i].idbus = BUS_GAMEPORT;
-		sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
-		sw->dev[i].idproduct = sw->type;
-		sw->dev[i].idversion = 0x0100;
-
-		sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-		for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
-			code = sw_abs[sw->type][j];
-			set_bit(code, sw->dev[i].absbit);
-			sw->dev[i].absmax[code] = (1 << bits) - 1;
-			sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
-			sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
-			if (code != ABS_THROTTLE)
-				sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
-		}
-
-		for (j = 0; (code = sw_btn[sw->type][j]); j++)
-			set_bit(code, sw->dev[i].keybit);
-
-		input_register_device(sw->dev + i);
-		printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
-			sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
-	}
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:	kfree(sw);
-}
-
-static void sw_disconnect(struct gameport *gameport)
-{
-	int i;
-
-	struct sw *sw = gameport->private;
-	for (i = 0; i < sw->number; i++)
-		input_unregister_device(sw->dev + i);
-	gameport_close(gameport);
-	kfree(sw);
-}
-
-static struct gameport_dev sw_dev = {
-	connect:	sw_connect,
-	disconnect:	sw_disconnect,
-};
-
-int __init sw_init(void)
-{
-	gameport_register_device(&sw_dev);
-	return 0;
-}
-
-void __exit sw_exit(void)
-{
-	gameport_unregister_device(&sw_dev);
-}
-
-module_init(sw_init);
-module_exit(sw_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/spaceball.c b/drivers/char/joystick/spaceball.c
--- a/drivers/char/joystick/spaceball.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,238 +0,0 @@
-/*
- * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Based on the work of:
- *  	David Thompson
- *  	Joseph Krahn
- *
- *  Sponsored by SuSE
- */
-
-/*
- * SpaceTec SpaceBall 4000 FLX driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-
-/*
- * Constants.
- */
-
-#define JS_SBALL_MAX_LENGTH	128
-static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
-static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; 
-
-/*
- * Per-Ball data.
- */
-
-struct spaceball {
-	struct input_dev dev;
-	struct serio *serio;
-	int idx;
-	int escape;
-	unsigned char data[JS_SBALL_MAX_LENGTH];
-};
-
-/*
- * spaceball_process_packet() decodes packets the driver receives from the
- * SpaceBall.
- */
-
-static void spaceball_process_packet(struct spaceball* spaceball)
-{
-	struct input_dev *dev = &spaceball->dev;
-	unsigned char *data = spaceball->data;
-	int i;
-
-	if (spaceball->idx < 2) return;
-
-	printk("%c %d\n", spaceball->data[0], spaceball->idx);
-
-	switch (spaceball->data[0]) {
-
-		case '@':					/* Reset packet */
-			spaceball->data[spaceball->idx - 1] = 0;
-			for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
-			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
-				spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
-			break;
-
-		case 'D':					/* Ball data */
-			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++) {
-				input_report_abs(dev, spaceball_axes[i], 
-					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
-			}
-			break;
-
-		case '.':				/* Button data, part2 */
-			if (spaceball->idx != 3) return;
-			input_report_key(dev, BTN_0,  data[2] & 1);
-			input_report_key(dev, BTN_1, data[2] & 2);
-			break;
-
-		case '?':				/* Error packet */
-			spaceball->data[spaceball->idx - 1] = 0;
-			printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
-			break;
-	}
-}
-
-/*
- * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
- * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
- * can occur in the axis values.
- */
-
-static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct spaceball *spaceball = serio->private;
-
-	switch (data) {
-		case 0xd:
-			spaceball_process_packet(spaceball);
-			spaceball->idx = 0;
-			spaceball->escape = 0;
-			return;
-		case '^':
-			if (!spaceball->escape) {
-				spaceball->escape = 1;
-				return;
-			}
-			spaceball->escape = 0;
-		case 'M':
-		case 'Q':
-		case 'S':
-			if (spaceball->escape) {
-				spaceball->escape = 0;
-				data &= 0x1f;
-			}
-		default:
-			if (spaceball->escape) {
-				spaceball->escape = 0;
-				printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
-			}
-			if (spaceball->idx < JS_SBALL_MAX_LENGTH)
-				spaceball->data[spaceball->idx++] = data;
-			return;
-	}
-}
-
-/*
- * spaceball_disconnect() is the opposite of spaceball_connect()
- */
-
-static void spaceball_disconnect(struct serio *serio)
-{
-	struct spaceball* spaceball = serio->private;
-	input_unregister_device(&spaceball->dev);
-	serio_close(serio);
-	kfree(spaceball);
-}
-
-/*
- * spaceball_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
- */
-
-static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct spaceball *spaceball;
-	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
-		return;
-
-	if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
-		return;
-	memset(spaceball, 0, sizeof(struct spaceball));
-
-	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-	spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
-
-	for (i = 0; i < 6; i++) {
-		t = spaceball_axes[i];
-		set_bit(t, spaceball->dev.absbit);
-		spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
-		spaceball->dev.absmax[t] = i < 3 ?  8000 :  1600;
-		spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
-		spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
-	}
-
-	spaceball->serio = serio;
-	spaceball->dev.private = spaceball;
-
-	spaceball->dev.name = spaceball_name;
-	spaceball->dev.idbus = BUS_RS232;
-	spaceball->dev.idvendor = SERIO_SPACEBALL;
-	spaceball->dev.idproduct = 0x0001;
-	spaceball->dev.idversion = 0x0100;
-	
-	serio->private = spaceball;
-
-	if (serio_open(serio, dev)) {
-		kfree(spaceball);
-		return;
-	}
-
-	input_register_device(&spaceball->dev);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev spaceball_dev = {
-	interrupt:	spaceball_interrupt,
-	connect:	spaceball_connect,
-	disconnect:	spaceball_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init spaceball_init(void)
-{
-	serio_register_device(&spaceball_dev);
-	return 0;
-}
-
-void __exit spaceball_exit(void)
-{
-	serio_unregister_device(&spaceball_dev);
-}
-
-module_init(spaceball_init);
-module_exit(spaceball_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/spaceorb.c b/drivers/char/joystick/spaceorb.c
--- a/drivers/char/joystick/spaceorb.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,227 +0,0 @@
-/*
- * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- * 
- *  Based on the work of:
- *  	David Thompson
- *
- *  Sponsored by SuSE
- */
-
-/*
- * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-
-/*
- * Constants.
- */
-
-#define SPACEORB_MAX_LENGTH	64
-
-static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
-static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *spaceorb_name = "SpaceTec SpaceOrb 360";
-
-/*
- * Per-Orb data.
- */
-
-struct spaceorb {
-	struct input_dev dev;
-	struct serio *serio;
-	int idx;
-	unsigned char data[SPACEORB_MAX_LENGTH];
-};
-
-static unsigned char spaceorb_xor[] = "SpaceWare";
-
-static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
-		"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; 
-
-/*
- * spaceorb_process_packet() decodes packets the driver receives from the
- * SpaceOrb.
- */
-
-static void spaceorb_process_packet(struct spaceorb *spaceorb)
-{
-	struct input_dev *dev = &spaceorb->dev;
-	unsigned char *data = spaceorb->data;
-	unsigned char c = 0;
-	int axes[6];
-	int i;
-
-	if (spaceorb->idx < 2) return;
-	for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
-	if (c) return;
-
-	switch (data[0]) {
-
-		case 'R':				/* Reset packet */
-			spaceorb->data[spaceorb->idx - 1] = 0;
-			for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
-			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
-				 spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
-			break;
-
-		case 'D':				/* Ball + button data */
-			if (spaceorb->idx != 12) return;
-			for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; 
-			axes[0] = ( data[2]	 << 3) | (data[ 3] >> 4);
-			axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
-			axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
-			axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
-			axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
-			axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
-			for (i = 0; i < 6; i++)
-				input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
-			for (i = 0; i < 8; i++)
-				input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
-			break;
-
-		case 'K':				/* Button data */
-			if (spaceorb->idx != 5) return;
-			for (i = 0; i < 7; i++)
-				input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
-
-			break;
-
-		case 'E':				/* Error packet */
-			if (spaceorb->idx != 4) return;
-			printk(KERN_ERR "joy-spaceorb: Device error. [ ");
-			for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
-			printk("]\n");
-			break;
-	}
-}
-
-static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct spaceorb* spaceorb = serio->private;
-
-	if (~data & 0x80) {
-		if (spaceorb->idx) spaceorb_process_packet(spaceorb);
-		spaceorb->idx = 0;
-	}
-	if (spaceorb->idx < SPACEORB_MAX_LENGTH)
-		spaceorb->data[spaceorb->idx++] = data & 0x7f;
-}
-
-/*
- * spaceorb_disconnect() is the opposite of spaceorb_connect()
- */
-
-static void spaceorb_disconnect(struct serio *serio)
-{
-	struct spaceorb* spaceorb = serio->private;
-	input_unregister_device(&spaceorb->dev);
-	serio_close(serio);
-	kfree(spaceorb);
-}
-
-/*
- * spaceorb_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
- * it as an input device.
- */
-
-static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct spaceorb *spaceorb;
-	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
-		return;
-
-	if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
-		return;
-	memset(spaceorb, 0, sizeof(struct spaceorb));
-
-	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-
-	for (i = 0; i < 7; i++)
-		set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
-
-	for (i = 0; i < 6; i++) {
-		t = spaceorb_axes[i];
-		set_bit(t, spaceorb->dev.absbit);
-		spaceorb->dev.absmin[t] = -508;
-		spaceorb->dev.absmax[t] =  508;
-	}
-
-	spaceorb->serio = serio;
-	spaceorb->dev.private = spaceorb;
-
-	spaceorb->dev.name = spaceorb_name;
-	spaceorb->dev.idbus = BUS_RS232;
-	spaceorb->dev.idvendor = SERIO_SPACEORB;
-	spaceorb->dev.idproduct = 0x0001;
-	spaceorb->dev.idversion = 0x0100;
-	
-	serio->private = spaceorb;
-
-	if (serio_open(serio, dev)) {
-		kfree(spaceorb);
-		return;
-	}
-
-	input_register_device(&spaceorb->dev);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev spaceorb_dev = {
-	interrupt:	spaceorb_interrupt,
-	connect:	spaceorb_connect,
-	disconnect:	spaceorb_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init spaceorb_init(void)
-{
-	serio_register_device(&spaceorb_dev);
-	return 0;
-}
-
-void __exit spaceorb_exit(void)
-{
-	serio_unregister_device(&spaceorb_dev);
-}
-
-module_init(spaceorb_init);
-module_exit(spaceorb_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/stinger.c b/drivers/char/joystick/stinger.c
--- a/drivers/char/joystick/stinger.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,202 +0,0 @@
-/*
- * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2000 Mark Fletcher
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Gravis Stinger gamepad driver for Linux
- */
-
-/*
- * This program is free warftware; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define STINGER_MAX_LENGTH 8
-
-static char *stinger_name = "Gravis Stinger";
-
-/*
- * Per-Stinger data.
- */
-
-struct stinger {
-	struct input_dev dev;
-	int idx;
-	unsigned char data[STINGER_MAX_LENGTH];
-};
-
-/*
- * stinger_process_packet() decodes packets the driver receives from the
- * Stinger. It updates the data accordingly.
- */
-
-static void stinger_process_packet(struct stinger *stinger)
-{
-	struct input_dev *dev = &stinger->dev;
-	unsigned char *data = stinger->data;
-
-	if (!stinger->idx) return;
-
-	input_report_key(dev, BTN_A,	  ((data[0] & 0x20) >> 5));
-	input_report_key(dev, BTN_B,	  ((data[0] & 0x10) >> 4));
-	input_report_key(dev, BTN_C,	  ((data[0] & 0x08) >> 3));
-	input_report_key(dev, BTN_X,	  ((data[0] & 0x04) >> 2));
-	input_report_key(dev, BTN_Y,	  ((data[3] & 0x20) >> 5));
-	input_report_key(dev, BTN_Z,	  ((data[3] & 0x10) >> 4));
-	input_report_key(dev, BTN_TL,     ((data[3] & 0x08) >> 3));
-	input_report_key(dev, BTN_TR,     ((data[3] & 0x04) >> 2));
-	input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
-	input_report_key(dev, BTN_START,   (data[3] & 0x01));
-
-	input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
-	input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
-
-	return;
-}
-
-/*
- * stinger_interrupt() is called by the low level driver when characters
- * are ready for us. We then buffer them for further processing, or call the
- * packet processing routine.
- */
-
-static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct stinger* stinger = serio->private;
-
-	/* All Stinger packets are 4 bytes */
-
-	if (stinger->idx < STINGER_MAX_LENGTH)
-		stinger->data[stinger->idx++] = data;
-
-	if (stinger->idx == 4) {
-		stinger_process_packet(stinger);
-		stinger->idx = 0;
-	}
-
-	return;
-}
-
-/*
- * stinger_disconnect() is the opposite of stinger_connect()
- */
-
-static void stinger_disconnect(struct serio *serio)
-{
-	struct stinger* stinger = serio->private;
-	input_unregister_device(&stinger->dev);
-	serio_close(serio);
-	kfree(stinger);
-}
-
-/*
- * stinger_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Stinger, and if found, registers
- * it as an input device.
- */
-
-static void stinger_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct stinger *stinger;
-	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_STINGER))
-		return;
-
-	if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
-		return;
-
-	memset(stinger, 0, sizeof(struct stinger));
-
-	stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-	stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
-					   BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
-					   BIT(BTN_START) | BIT(BTN_SELECT);
-	stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
-	stinger->dev.name = stinger_name;
-	stinger->dev.idbus = BUS_RS232;
-	stinger->dev.idvendor = SERIO_STINGER;
-	stinger->dev.idproduct = 0x0001;
-	stinger->dev.idversion = 0x0100;
-
-	for (i = 0; i < 2; i++) {
-		stinger->dev.absmax[ABS_X+i] =  64;	
-		stinger->dev.absmin[ABS_X+i] = -64;	
-		stinger->dev.absflat[ABS_X+i] = 4;
-	}
-
-	stinger->dev.private = stinger;
-	
-	serio->private = stinger;
-
-	if (serio_open(serio, dev)) {
-		kfree(stinger);
-		return;
-	}
-
-	input_register_device(&stinger->dev);
-
-	printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev stinger_dev = {
-	interrupt:	stinger_interrupt,
-	connect:	stinger_connect,
-	disconnect:	stinger_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init stinger_init(void)
-{
-	serio_register_device(&stinger_dev);
-	return 0;
-}
-
-void __exit stinger_exit(void)
-{
-	serio_unregister_device(&stinger_dev);
-}
-
-module_init(stinger_init);
-module_exit(stinger_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/tmdc.c b/drivers/char/joystick/tmdc.c
--- a/drivers/char/joystick/tmdc.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,378 +0,0 @@
-/*
- * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- *
- *   Based on the work of:
- *	Trystan Larey-Williams 
- *
- */
-
-/*
- * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define TMDC_MAX_START		400	/* 400 us */
-#define TMDC_MAX_STROBE		45	/* 45 us */
-#define TMDC_MAX_LENGTH		13
-#define TMDC_REFRESH_TIME	HZ/50	/* 20 ms */
-
-#define TMDC_MODE_M3DI		1
-#define TMDC_MODE_3DRP		3
-#define TMDC_MODE_AT		4
-#define TMDC_MODE_FM		8
-#define TMDC_MODE_FGP		163
-
-#define TMDC_BYTE_ID		10
-#define TMDC_BYTE_REV		11
-#define TMDC_BYTE_DEF		12
-
-#define TMDC_ABS		7	
-#define TMDC_ABS_HAT		4
-#define TMDC_BTN		16
-
-static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
-static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
-
-static signed char tmdc_abs[TMDC_ABS] =
-	{ ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
-static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
-	{ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
-static signed char tmdc_abs_at[TMDC_ABS] =
-	{ ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
-static signed char tmdc_abs_fm[TMDC_ABS] =
-	{ ABS_RX, ABS_RY, ABS_X, ABS_Y };
-
-static short tmdc_btn_pad[TMDC_BTN] =
-	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
-static short tmdc_btn_joy[TMDC_BTN] =
-	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- 	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
-static short tmdc_btn_fm[TMDC_BTN] =
-        { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
-static short tmdc_btn_at[TMDC_BTN] =
-        { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
-          BTN_BASE3, BTN_BASE2, BTN_BASE };
-
-static struct {
-        int x;
-        int y;
-} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
-
-struct tmdc {
-	struct gameport *gameport;
-	struct timer_list timer;
-	struct input_dev dev[2];
-	char name[2][64];
-	int mode[2];
-	signed char *abs[2];
-	short *btn[2];
-	unsigned char absc[2];
-	unsigned char btnc[2][4];
-	unsigned char btno[2][4];
-	int used;
-	int reads;
-	int bads;	
-	unsigned char exists;
-};
-
-/*
- * tmdc_read_packet() reads a ThrustMaster packet.
- */
-
-static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
-{
-	unsigned char u, v, w, x;
-	unsigned long flags;
-	int i[2], j[2], t[2], p, k;
-
-	p = gameport_time(gameport, TMDC_MAX_STROBE);
-
-	for (k = 0; k < 2; k++) {
-		t[k] = gameport_time(gameport, TMDC_MAX_START);
-		i[k] = j[k] = 0;
-	}
-
-	__save_flags(flags);
-	__cli();
-	gameport_trigger(gameport);
-	
-	w = gameport_read(gameport) >> 4;
-
-	do {
-		x = w;
-		w = gameport_read(gameport) >> 4;
-
-		for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
-			if (~v & u & 2) {
-				if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
-				t[k] = p;
-				if (j[k] == 0) {				 /* Start bit */
-					if (~v & 1) t[k] = 0;
-					data[k][i[k]] = 0; j[k]++; continue;
-				}
-				if (j[k] == 9) {				/* Stop bit */
-					if (v & 1) t[k] = 0;
-					j[k] = 0; i[k]++; continue;
-				}
-				data[k][i[k]] |= (~v & 1) << (j[k]++ - 1);	/* Data bit */
-			}
-			t[k]--; 
-		}
-	} while (t[0] > 0 || t[1] > 0);
-
-	__restore_flags(flags);
-
-	return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
-}
-
-/*
- * tmdc_read() reads and analyzes ThrustMaster joystick data.
- */
-
-static void tmdc_timer(unsigned long private)
-{
-	unsigned char data[2][TMDC_MAX_LENGTH];
-	struct tmdc *tmdc = (void *) private;
-	struct input_dev *dev;
-	unsigned char r, bad = 0;
-	int i, j, k, l;
-
-	tmdc->reads++;
-
-	if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
-		bad = 1;
-
-	for (j = 0; j < 2; j++) 
-		if (r & (1 << j) & tmdc->exists) {
-
-			if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
-				bad = 1;
-				continue;
-			}
-
-			dev = tmdc->dev + j;
-
-			for (i = 0; i < tmdc->absc[j]; i++) {
-				if (tmdc->abs[j][i] < 0) continue;
-				input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
-			}
-
-			switch (tmdc->mode[j]) {
-
-				case TMDC_MODE_M3DI:
-
-					i = tmdc_byte_d[0];
-					input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
-					input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i]       & 1));
-					break;
-
-				case TMDC_MODE_AT:
-
-					i = tmdc_byte_a[3];
-					input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
-					input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
-					break;
-
-			}
-
-			for (k = l = 0; k < 4; k++) {
-				for (i = 0; i < tmdc->btnc[j][k]; i++)
-					input_report_key(dev, tmdc->btn[j][i + l],
-						((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
-				l += tmdc->btnc[j][k];
-			}
-	}
-
-	tmdc->bads += bad;
-
-	mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
-}
-
-static int tmdc_open(struct input_dev *dev)
-{
-	struct tmdc *tmdc = dev->private;
-	if (!tmdc->used++)
-		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);	
-	return 0;
-}
-
-static void tmdc_close(struct input_dev *dev)
-{
-	struct tmdc *tmdc = dev->private;
-	if (!--tmdc->used)
-		del_timer(&tmdc->timer);
-}
-
-/*
- * tmdc_probe() probes for ThrustMaster type joysticks.
- */
-
-static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
-	struct models {
-		unsigned char id;
-		char *name;
-		char abs;
-		char hats;
-		char btnc[4];
-		char btno[4];
-		signed char *axes;
-		short *buttons;
-	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor",	  6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
-			{   3, "ThrustMaster Rage 3D Gamepad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
-			{   4, "ThrustMaster Attack Throttle",		  5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
-			{   8, "ThrustMaster FragMaster",		  4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
-			{ 163, "Thrustmaster Fusion GamePad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
-			{   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
-
-	unsigned char data[2][TMDC_MAX_LENGTH];
-	struct tmdc *tmdc;
-	int i, j, k, l, m;
-
-	if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
-		return;
-	memset(tmdc, 0, sizeof(struct tmdc));
-
-	gameport->private = tmdc;
-
-	tmdc->gameport = gameport;
-	init_timer(&tmdc->timer);
-	tmdc->timer.data = (long) tmdc;
-	tmdc->timer.function = tmdc_timer;
-
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		goto fail1;
-
-	if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
-		goto fail2;
-
-	for (j = 0; j < 2; j++)
-		if (tmdc->exists & (1 << j)) {
-
-			tmdc->mode[j] = data[j][TMDC_BYTE_ID];
-
-			for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
-
-			tmdc->abs[j] = models[m].axes;
-			tmdc->btn[j] = models[m].buttons;
-
-			if (!models[m].id) {
-				models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
-				for (k = 0; k < 4; k++)
-					models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
-			}
-
-			tmdc->absc[j] = models[m].abs;
-			for (k = 0; k < 4; k++) {
-				tmdc->btnc[j][k] = models[m].btnc[k];
-				tmdc->btno[j][k] = models[m].btno[k];
-			}
-
-			sprintf(tmdc->name[j], models[m].name, models[m].abs,
-				(data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
-
-			tmdc->dev[j].private = tmdc;
-			tmdc->dev[j].open = tmdc_open;
-			tmdc->dev[j].close = tmdc_close;
-
-			tmdc->dev[j].name = tmdc->name[j];
-			tmdc->dev[j].idbus = BUS_GAMEPORT;
-			tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
-			tmdc->dev[j].idproduct = models[m].id;
-			tmdc->dev[j].idversion = 0x0100;
-
-			tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
-			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
-				if (tmdc->abs[i] < 0) continue;
-				set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
-				tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
-				tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
-				tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
-			}
-
-			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
-				set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
-				tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
-			}
-
-			for (k = l = 0; k < 4; k++) {
-				for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
-					set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
-				l += models[m].btnc[k];
-			}
-
-			input_register_device(tmdc->dev + j);
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
-		}
-
-	return;
-fail2:	gameport_close(gameport);
-fail1:	kfree(tmdc);
-}
-
-static void tmdc_disconnect(struct gameport *gameport)
-{
-	struct tmdc *tmdc = gameport->private;
-	int i;
-	for (i = 0; i < 2; i++)
-		if (tmdc->exists & (1 << i)) 
-			input_unregister_device(tmdc->dev + i);
-	gameport_close(gameport);
-	kfree(tmdc);
-}
-
-static struct gameport_dev tmdc_dev = {
-	connect:	tmdc_connect,
-	disconnect:	tmdc_disconnect,
-};
-
-int __init tmdc_init(void)
-{
-	gameport_register_device(&tmdc_dev);
-	return 0;
-}
-
-void __exit tmdc_exit(void)
-{
-	gameport_unregister_device(&tmdc_dev);
-}
-
-module_init(tmdc_init);
-module_exit(tmdc_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/joystick/turbografx.c b/drivers/char/joystick/turbografx.c
--- a/drivers/char/joystick/turbografx.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,259 +0,0 @@
-/*
- * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
- *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Steffen Schwenke
- *
- *  Sponsored by SuSE
- */
-
-/*
- * TurboGraFX parallel port interface driver for Linux.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(tgfx, "2-8i");
-MODULE_PARM(tgfx_2, "2-8i");
-MODULE_PARM(tgfx_3, "2-8i");
-
-#define TGFX_REFRESH_TIME	HZ/100	/* 10 ms */
-
-#define TGFX_TRIGGER		0x08
-#define TGFX_UP			0x10
-#define TGFX_DOWN		0x20	
-#define TGFX_LEFT		0x40
-#define TGFX_RIGHT		0x80
-
-#define TGFX_THUMB		0x02
-#define TGFX_THUMB2		0x04
-#define TGFX_TOP		0x01
-#define TGFX_TOP2		0x08
-
-static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-
-static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
-static char *tgfx_name = "TurboGraFX Multisystem joystick";
-
-struct tgfx {
-	struct pardevice *pd;
-	struct timer_list timer;
-	struct input_dev dev[7];
-	int sticks;
-	int used;
-} *tgfx_base[3];
-
-/*
- * tgfx_timer() reads and analyzes TurboGraFX joystick data.
- */
-
-static void tgfx_timer(unsigned long private)
-{
-	struct tgfx *tgfx = (void *) private;
-	struct input_dev *dev;
-	int data1, data2, i;
-
-	for (i = 0; i < 7; i++)
-		if (tgfx->sticks & (1 << i)) {
-
- 			dev = tgfx->dev + i;
-
-			parport_write_data(tgfx->pd->port, ~(1 << i));
-			data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
-			data2 = parport_read_control(tgfx->pd->port) ^ 0x04;	/* CAVEAT parport */
-
-			input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT));
-			input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP  ));
-
-			input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER));
-			input_report_key(dev, BTN_THUMB,   (data2 & TGFX_THUMB  ));
-			input_report_key(dev, BTN_THUMB2,  (data2 & TGFX_THUMB2 ));
-			input_report_key(dev, BTN_TOP,     (data2 & TGFX_TOP    ));
-			input_report_key(dev, BTN_TOP2,    (data2 & TGFX_TOP2   ));
-		}
-
-	mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
-}
-
-static int tgfx_open(struct input_dev *dev)
-{
-        struct tgfx *tgfx = dev->private;
-        if (!tgfx->used++) {
-		parport_claim(tgfx->pd);
-		parport_write_control(tgfx->pd->port, 0x04);
-                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); 
-	}
-        return 0;
-}
-
-static void tgfx_close(struct input_dev *dev)
-{
-        struct tgfx *tgfx = dev->private;
-        if (!--tgfx->used) {
-                del_timer(&tgfx->timer);
-		parport_write_control(tgfx->pd->port, 0x00);
-        	parport_release(tgfx->pd);
-	}
-}
-
-/*
- * tgfx_probe() probes for tg gamepads.
- */
-
-static struct tgfx __init *tgfx_probe(int *config)
-{
-	struct tgfx *tgfx;
-	struct parport *pp;
-	int i, j;
-
-	if (config[0] < 0)
-		return NULL;
-
-	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
-		config[0]--;
-
-	if (!pp) {
-		printk(KERN_ERR "turbografx.c: no such parport\n");
-		return NULL;
-	}
-
-	if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL)))
-		return NULL;
-	memset(tgfx, 0, sizeof(struct tgfx));
-
-	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
-	if (!tgfx->pd) {
-		printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
-		kfree(tgfx);
-		return NULL;
-	}
-
-	init_timer(&tgfx->timer);
-	tgfx->timer.data = (long) tgfx;
-	tgfx->timer.function = tgfx_timer;
-
-	tgfx->sticks = 0;
-
-	for (i = 0; i < 7; i++)
-		if (config[i+1] > 0 && config[i+1] < 6) {
-
-			tgfx->sticks |= (1 << i);
-
-			tgfx->dev[i].private = tgfx;
-			tgfx->dev[i].open = tgfx_open;
-			tgfx->dev[i].close = tgfx_close;
-
-			tgfx->dev[i].name = tgfx_name;
-			tgfx->dev[i].idbus = BUS_PARPORT;
-			tgfx->dev[i].idvendor = 0x0003;
-			tgfx->dev[i].idproduct = config[i+1];
-			tgfx->dev[i].idversion = 0x0100;
-
-			tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-			tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
-			for (j = 0; j < config[i+1]; j++)
-				set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); 
-
-			tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
-			tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
-
-			input_register_device(tgfx->dev + i);
-			printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n",
-				tgfx->dev[i].number, config[i+1], tgfx->pd->port->name);
-		}
-
-        if (!tgfx->sticks) {
-		parport_unregister_device(tgfx->pd);
-		kfree(tgfx);
-		return NULL;
-        }
-		
-	return tgfx;
-}
-
-#ifndef MODULE
-int __init tgfx_setup(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1];
-	return 1;
-}
-int __init tgfx_setup_2(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1];
-	return 1;
-}
-int __init tgfx_setup_3(char *str)
-{
-	int i, ints[9];
-	get_options(str, ARRAY_SIZE(ints), ints);
-	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1];
-	return 1;
-}
-__setup("tgfx=", tgfx_setup);
-__setup("tgfx_2=", tgfx_setup_2);
-__setup("tgfx_3=", tgfx_setup_3);
-#endif
-
-int __init tgfx_init(void)
-{
-	tgfx_base[0] = tgfx_probe(tgfx);
-	tgfx_base[1] = tgfx_probe(tgfx_2);
-	tgfx_base[2] = tgfx_probe(tgfx_3);
-
-	if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
-		return 0;
-
-	return -ENODEV;
-}
-
-void __exit tgfx_exit(void)
-{
-	int i, j;
-
-	for (i = 0; i < 3; i++) 
-		if (tgfx_base[i]) {
-			for (j = 0; j < 7; j++)
-				if (tgfx_base[i]->sticks & (1 << j))
-					input_unregister_device(tgfx_base[i]->dev + j);
-		parport_unregister_device(tgfx_base[i]->pd);
-	}
-}
-
-module_init(tgfx_init);
-module_exit(tgfx_exit);
diff -Nru a/drivers/char/joystick/warrior.c b/drivers/char/joystick/warrior.c
--- a/drivers/char/joystick/warrior.c	Tue Feb  5 19:17:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,214 +0,0 @@
-/*
- * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
- *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
- */
-
-/*
- * Logitech WingMan Warrior joystick driver for Linux
- */
-
-/*
- * This program is free warftware; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define WARRIOR_MAX_LENGTH	16
-static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; 
-static char *warrior_name = "Logitech WingMan Warrior";
-
-/*
- * Per-Warrior data.
- */
-
-struct warrior {
-	struct input_dev dev;
-	int idx, len;
-	unsigned char data[WARRIOR_MAX_LENGTH];
-};
-
-/*
- * warrior_process_packet() decodes packets the driver receives from the
- * Warrior. It updates the data accordingly.
- */
-
-static void warrior_process_packet(struct warrior *warrior)
-{
-	struct input_dev *dev = &warrior->dev;
-	unsigned char *data = warrior->data;
-
-	if (!warrior->idx) return;
-
-	switch ((data[0] >> 4) & 7) {
-		case 1:					/* Button data */
-			input_report_key(dev, BTN_TRIGGER,  data[3]       & 1);
-			input_report_key(dev, BTN_THUMB,   (data[3] >> 1) & 1);
-			input_report_key(dev, BTN_TOP,     (data[3] >> 2) & 1);
-			input_report_key(dev, BTN_TOP2,    (data[3] >> 3) & 1);
-			return;
-		case 3:					/* XY-axis info->data */
-			input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
-			input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
-			return;
-		case 5:					/* Throttle, spinner, hat info->data */
-			input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
-			input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
-			input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
-			input_report_rel(dev, REL_DIAL,  (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
-			return;
-	}
-}
-
-/*
- * warrior_interrupt() is called by the low level driver when characters
- * are ready for us. We then buffer them for further processing, or call the
- * packet processing routine.
- */
-
-static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
-	struct warrior* warrior = serio->private;
-
-	if (data & 0x80) {
-		if (warrior->idx) warrior_process_packet(warrior);
-		warrior->idx = 0;
-		warrior->len = warrior_lengths[(data >> 4) & 7];
-	}
-
-	if (warrior->idx < warrior->len)
-		warrior->data[warrior->idx++] = data;
-
-	if (warrior->idx == warrior->len) {
-		if (warrior->idx) warrior_process_packet(warrior);	
-		warrior->idx = 0;
-		warrior->len = 0;
-	}
-}
-
-/*
- * warrior_disconnect() is the opposite of warrior_connect()
- */
-
-static void warrior_disconnect(struct serio *serio)
-{
-	struct warrior* warrior = serio->private;
-	input_unregister_device(&warrior->dev);
-	serio_close(serio);
-	kfree(warrior);
-}
-
-/*
- * warrior_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Warrior, and if found, registers
- * it as an input device.
- */
-
-static void warrior_connect(struct serio *serio, struct serio_dev *dev)
-{
-	struct warrior *warrior;
-	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
-		return;
-
-	if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
-		return;
-
-	memset(warrior, 0, sizeof(struct warrior));
-
-	warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);	
-	warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
-	warrior->dev.relbit[0] = BIT(REL_DIAL);
-	warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
-
-	warrior->dev.name = warrior_name;
-	warrior->dev.idbus = BUS_RS232;
-	warrior->dev.idvendor = SERIO_WARRIOR;
-	warrior->dev.idproduct = 0x0001;
-	warrior->dev.idversion = 0x0100;
-
-	for (i = 0; i < 2; i++) {
-		warrior->dev.absmax[ABS_X+i] = -64;	
-		warrior->dev.absmin[ABS_X+i] =  64;	
-		warrior->dev.absflat[ABS_X+i] = 8;	
-	}
-
-	warrior->dev.absmax[ABS_THROTTLE] = -112;	
-	warrior->dev.absmin[ABS_THROTTLE] =  112;	
-
-	for (i = 0; i < 2; i++) {
-		warrior->dev.absmax[ABS_HAT0X+i] = -1;	
-		warrior->dev.absmin[ABS_HAT0X+i] =  1;	
-	}
-
-	warrior->dev.private = warrior;
-	
-	serio->private = warrior;
-
-	if (serio_open(serio, dev)) {
-		kfree(warrior);
-		return;
-	}
-
-	input_register_device(&warrior->dev);
-
-	printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev warrior_dev = {
-	interrupt:	warrior_interrupt,
-	connect:	warrior_connect,
-	disconnect:	warrior_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init warrior_init(void)
-{
-	serio_register_device(&warrior_dev);
-	return 0;
-}
-
-void __exit warrior_exit(void)
-{
-	serio_unregister_device(&warrior_dev);
-}
-
-module_init(warrior_init);
-module_exit(warrior_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/char/lp.c	Tue Feb  5 19:17:21 2002
@@ -648,7 +648,7 @@
 	do {
 		/* Write the data, converting LF->CRLF as we go. */
 		ssize_t canwrite = count;
-		char *lf = strchr (s, '\n');
+		char *lf = memchr (s, '\n', count);
 		if (lf)
 			canwrite = lf - s;
 
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/char/ppdev.c	Tue Feb  5 19:17:21 2002
@@ -320,6 +320,7 @@
 	case PPCLAIM:
 	    {
 		struct ieee1284_info *info;
+		int ret;
 
 		if (pp->flags & PP_CLAIMED) {
 			printk (KERN_DEBUG CHRDEV
@@ -335,7 +336,10 @@
 			}
 		}
 
-		parport_claim_or_block (pp->pdev);
+		ret = parport_claim_or_block (pp->pdev);
+		if (ret < 0)
+			return ret;
+
 		pp->flags |= PP_CLAIMED;
 
 		/* For interrupt-reporting to work, we need to be
@@ -429,8 +433,12 @@
 	    {
 		unsigned int modes;
 
-		modes = pp->pdev->port->modes;
-		if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) {
+		port = parport_find_number (minor);
+		if (!port)
+			return -ENODEV;
+
+		modes = port->modes;
+		if (copy_to_user ((unsigned int *)arg, &modes, sizeof (modes))) {
 			return -EFAULT;
 		}
 		return 0;
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/ide/ide-proc.c	Tue Feb  5 19:17:21 2002
@@ -597,7 +597,7 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive));
+		len = sprintf(page,"%llu\n", (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/ide/ide.c	Tue Feb  5 19:17:21 2002
@@ -813,7 +813,7 @@
 					high = read_24(drive);
 
 					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low);
+					printk(", LBAsect=%lld, high=%d, low=%d", (long long) sectors, high, low);
 				} else {
 					byte cur = IN_BYTE(IDE_SELECT_REG);
 					if (cur & 0x40) {	/* using LBA? */
diff -Nru a/drivers/input/Config.help b/drivers/input/Config.help
--- a/drivers/input/Config.help	Tue Feb  5 19:17:21 2002
+++ b/drivers/input/Config.help	Tue Feb  5 19:17:21 2002
@@ -1,27 +1,35 @@
 CONFIG_INPUT
-  Say Y here if you want to enable any of the following options for
-  USB Human Interface Device (HID) support.
+  Say Y here if you have any input device (mouse, keyboard, tablet,
+  joystick, steering wheel ...) connected to your system and want
+  it to be available to applications. This includes standard PS/2
+  keyboard and mouse.
 
-  Say Y here if you want to enable any of the USB HID options in the
-  USB support section which require Input core support.
+  Say N here if you have a headless (no monitor, no keyboard) system.
 
-  Otherwise, say N.
+  More information is available: <file:Documentation/input/input.txt>
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called input.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_INPUT_KEYBDEV
-  Say Y here if you want your USB HID keyboard (or an ADB keyboard
-  handled by the input layer) to be able to serve as a system
-  keyboard.
+  Say Y here if you want your keyboard to be able to serve as a system
+  keyboard. This is needed in most cases. The only exceptions are
+  headless and embedded systems.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called keybdev.o.  If you want to compile it as a
+  The module will be called keybdev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_INPUT_MOUSEDEV
-  Say Y here if you want your USB HID mouse (or ADB mouse handled by
-  the input layer) to be accessible as char devices 13:32+ -
-  /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2
-  mouse.  That way, all user space programs will be able to use your
+  Say Y here if you want your mouse to be accessible as char devices
+  13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
+  emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
+  programs (includung SVGAlib, GPM and X) will be able to use your
   mouse.
 
   If unsure, say Y.
@@ -44,16 +52,23 @@
   you're not using a digitizer, this value is ignored.
 
 CONFIG_INPUT_JOYDEV
-  Say Y here if you want your USB HID joystick or gamepad to be
+  Say Y here if you want your joystick or gamepad to be
   accessible as char device 13:0+ - /dev/input/jsX device.
 
+  If unsure, say Y.
+
+  More information is available: <file:Documentation/input/joystick.txt>
+
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called joydev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_INPUT_EVDEV
-  Say Y here if you want your USB or ADB HID device events be
-  accessible under char device 13:64+ - /dev/input/eventX in a generic
-  way.  This is the future ...
+  Say Y here if you want your input device events be accessible
+  under char device 13:64+ - /dev/input/eventX in a generic way.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called evdev.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/Config.in b/drivers/input/Config.in
--- a/drivers/input/Config.in	Tue Feb  5 19:17:21 2002
+++ b/drivers/input/Config.in	Tue Feb  5 19:17:21 2002
@@ -1,18 +1,25 @@
 #
-# Input core configuration
+# Input device configuration
 #
 
 mainmenu_option next_comment
-comment 'Input core support'
+comment 'Input device support'
 
 tristate 'Input core support' CONFIG_INPUT
-dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
-dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+dep_tristate '  Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
+dep_tristate '  Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
 if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
    int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
    int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
 fi
-dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
-dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate '  Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate '  Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+
+source drivers/input/gameport/Config.in
+source drivers/input/serio/Config.in
+
+if [ "$CONFIG_INPUT" != "n" ]; then
+   source drivers/input/joystick/Config.in
+fi
 
 endmenu
diff -Nru a/drivers/input/Makefile b/drivers/input/Makefile
--- a/drivers/input/Makefile	Tue Feb  5 19:17:21 2002
+++ b/drivers/input/Makefile	Tue Feb  5 19:17:21 2002
@@ -8,15 +8,9 @@
 
 # Objects that export symbols.
 
+mod-subdirs	:= joystick
 export-objs	:= input.o
 
-# Object file lists.
-
-obj-y	:=
-obj-m	:=
-obj-n	:=
-obj-	:=
-
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT)		+= input.o
@@ -24,6 +18,12 @@
 obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
 obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
+
+subdir-$(CONFIG_INPUT_JOYSTICK)	+= joystick
+
+ifeq ($(CONFIG_INPUT_JOYSTICK),y)
+	obj-y += joystick/joydrv.o
+endif
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/gameport/Config.help b/drivers/input/gameport/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/Config.help	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,62 @@
+CONFIG_GAMEPORT
+  Gameport support is for the standard 15-pin PC gameport. If you
+  have a joystick, gamepad, gameport card, a soundcard with a gameport
+  or anything else that uses the gameport, say Y or M here and also to
+  at least one of the hardware specific drivers.
+
+  For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1,
+  S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport
+  support is provided by the sound drivers, so you won't need any
+  from the below listed modules. You still need to say Y here.
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called gameport.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_NS558
+  Say Y here if you have an ISA or PnP gameport.
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ns558.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_L4
+  Say Y here if you have a PDPI Lightning 4 gamecard.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called lightning.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_EMU10K1
+  Say Y here if you have a SoundBlaster Live! or SoundBlaster
+  Audigy card and want to use its gameport.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called emu10k1-gp.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_PCIGAME
+  Say Y here if you have an Aureal Vortex 1 or 2 or a Trident
+  4DWave NX or DX card and want to use its gameport.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pcigame.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_CS461X
+  Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
+  PCI audio accelerator and want to use its gameport.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cs461x.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/gameport/Config.in b/drivers/input/gameport/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/Config.in	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,19 @@
+#
+# Gameport configuration
+#
+
+tristate 'Gameport support' CONFIG_GAMEPORT
+
+if [ "$CONFIG_GAMEPORT" = "m" ]; then
+	define_tristate CONFIG_SOUND_GAMEPORT m
+fi
+if [ "$CONFIG_GAMEPORT" != "m" ]; then
+	define_tristate CONFIG_SOUND_GAMEPORT y
+fi
+
+dep_tristate '  Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
+dep_tristate '  PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
+dep_tristate '  SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
+dep_tristate '  Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT
+dep_tristate '  ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
+dep_tristate '  Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
diff -Nru a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/Makefile	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,24 @@
+#
+# Makefile for the gameport drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET	:= gamedrv.o
+
+# Objects that export symbols.
+
+export-objs	:= gameport.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_GAMEPORT)		+= gameport.o
+obj-$(CONFIG_GAMEPORT_CS461X)	+= cs461x.o
+obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
+obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
+obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
+obj-$(CONFIG_GAMEPORT_PCIGAME)	+= pcigame.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/cs461x.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,331 @@
+/*
+	The all defines and part of code (such as cs461x_*) are 
+	contributed from ALSA 0.5.8 sources. 
+	See http://www.alsa-project.org/ for sources
+	
+	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
+*/
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+MODULE_LICENSE("GPL");
+
+/*
+	These options are experimental
+
+#define CS461X_FULL_MAP
+*/
+
+#define COOKED_MODE
+
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS            0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4610
+#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4612
+#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4615
+#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
+#endif
+
+/* Registers */
+
+#define BA0_JSPT                                0x00000480
+#define BA0_JSCTL                               0x00000484
+#define BA0_JSC1                                0x00000488
+#define BA0_JSC2                                0x0000048C
+#define BA0_JSIO                                0x000004A0
+
+/* Bits for JSPT */
+
+#define JSPT_CAX                                0x00000001
+#define JSPT_CAY                                0x00000002
+#define JSPT_CBX                                0x00000004
+#define JSPT_CBY                                0x00000008
+#define JSPT_BA1                                0x00000010
+#define JSPT_BA2                                0x00000020
+#define JSPT_BB1                                0x00000040
+#define JSPT_BB2                                0x00000080
+
+/* Bits for JSCTL */
+
+#define JSCTL_SP_MASK                           0x00000003
+#define JSCTL_SP_SLOW                           0x00000000
+#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
+#define JSCTL_SP_MEDIUM_FAST                    0x00000002
+#define JSCTL_SP_FAST                           0x00000003
+#define JSCTL_ARE                               0x00000004
+
+/* Data register pairs masks */
+
+#define JSC1_Y1V_MASK                           0x0000FFFF
+#define JSC1_X1V_MASK                           0xFFFF0000
+#define JSC1_Y1V_SHIFT                          0
+#define JSC1_X1V_SHIFT                          16
+#define JSC2_Y2V_MASK                           0x0000FFFF
+#define JSC2_X2V_MASK                           0xFFFF0000
+#define JSC2_Y2V_SHIFT                          0
+#define JSC2_X2V_SHIFT                          16
+
+/* JS GPIO */
+
+#define JSIO_DAX                                0x00000001
+#define JSIO_DAY                                0x00000002
+#define JSIO_DBX                                0x00000004
+#define JSIO_DBY                                0x00000008
+#define JSIO_AXOE                               0x00000010
+#define JSIO_AYOE                               0x00000020
+#define JSIO_BXOE                               0x00000040
+#define JSIO_BYOE                               0x00000080
+
+/* 
+   The card initialization code is obfuscated; the module cs461x 
+   need to be loaded after ALSA modules initialized and something
+   played on the CS 4610 chip (see sources for details of CS4610
+   initialization code from ALSA)
+*/
+
+/* Card specific definitions */
+
+#define CS461X_BA0_SIZE         0x2000
+#define CS461X_BA1_DATA0_SIZE   0x3000
+#define CS461X_BA1_DATA1_SIZE   0x3800
+#define CS461X_BA1_PRG_SIZE     0x7000
+#define CS461X_BA1_REG_SIZE     0x0100
+
+#define BA1_SP_DMEM0                            0x00000000
+#define BA1_SP_DMEM1                            0x00010000
+#define BA1_SP_PMEM                             0x00020000
+#define BA1_SP_REG                              0x00030000
+
+#define BA1_DWORD_SIZE          (13 * 1024 + 512)
+#define BA1_MEMORY_COUNT        3
+
+/* 
+   Only one CS461x card is still suppoted; the code requires
+   redesign to avoid this limitatuion.
+*/
+
+static unsigned long ba0_addr;
+static unsigned int *ba0;
+
+#ifdef CS461X_FULL_MAP
+static unsigned long ba1_addr;
+static union ba1_t {
+        struct {
+                unsigned int *data0;
+                unsigned int *data1;
+                unsigned int *pmem;
+                unsigned int *reg;
+        } name;
+        unsigned int *idx[4];
+} ba1;
+
+static void cs461x_poke(unsigned long reg, unsigned int val)
+{
+        ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
+}
+
+static unsigned int cs461x_peek(unsigned long reg)
+{
+        return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
+}
+
+#endif
+
+static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
+{
+        ba0[reg >> 2] = val;
+}
+
+static unsigned int cs461x_peekBA0(unsigned long reg)
+{
+        return ba0[reg >> 2];
+}
+
+static int cs461x_free(struct pci_dev *pdev)
+{
+	struct gameport *port = pci_get_drvdata(pdev);
+	if(port){
+	    gameport_unregister_port(port);
+	    kfree(port);
+	}    
+	if (ba0) iounmap(ba0);
+#ifdef CS461X_FULL_MAP
+	if (ba1.name.data0) iounmap(ba1.name.data0);
+	if (ba1.name.data1) iounmap(ba1.name.data1);
+	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
+	if (ba1.name.reg)   iounmap(ba1.name.reg);
+#endif
+	return 0;
+}
+
+static void cs461x_gameport_trigger(struct gameport *gameport)
+{
+	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
+}
+
+static unsigned char cs461x_gameport_read(struct gameport *gameport)
+{
+	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
+}
+
+static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	unsigned js1, js2, jst;
+	
+	js1 = cs461x_peekBA0(BA0_JSC1);
+	js2 = cs461x_peekBA0(BA0_JSC2);
+	jst = cs461x_peekBA0(BA0_JSPT);
+	
+	*buttons = (~jst >> 4) & 0x0F; 
+	
+	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
+	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
+	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
+	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
+
+	for(jst=0;jst<4;++jst)
+		if(axes[jst]==0xFFFF) axes[jst] = -1;
+	return 0;
+}
+
+static int cs461x_gameport_open(struct gameport *gameport, int mode)
+{
+	switch (mode) {
+#ifdef COOKED_MODE
+	case GAMEPORT_MODE_COOKED:
+		return 0;
+#endif
+	case GAMEPORT_MODE_RAW:
+		return 0;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
+	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
+	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
+
+static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct gameport* port;
+	
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
+			pdev->bus->number, pdev->devfn, rc);
+		return rc;
+	}
+
+	ba0_addr = pci_resource_start(pdev, 0);
+#ifdef CS461X_FULL_MAP
+	ba1_addr = pci_resource_start(pdev, 1);
+#endif
+	if (ba0_addr == 0 || ba0_addr == ~0 
+#ifdef CS461X_FULL_MAP
+            || ba1_addr == 0 || ba1_addr == ~0
+#endif
+	    ) {
+                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
+#ifdef CS461X_FULL_MAP
+                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
+#endif
+		cs461x_free(pdev);
+                return -ENOMEM;
+        }
+
+	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
+#ifdef CS461X_FULL_MAP
+	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
+	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
+	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
+	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
+
+	if (ba0 == NULL || ba1.name.data0 == NULL ||
+            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
+            ba1.name.reg == NULL) {
+		cs461x_free(pdev);
+                return -ENOMEM;
+        }
+#else
+	if (ba0 == NULL){
+		cs461x_free(pdev);
+		return -ENOMEM;
+	}
+#endif
+	printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
+	    ba0_addr, CS461X_BA0_SIZE);
+        
+	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
+		printk(KERN_ERR "Memory allocation failed.\n");
+		cs461x_free(pdev);
+		return -ENOMEM;
+	}
+	memset(port, 0, sizeof(struct gameport));
+
+	pci_set_drvdata(pdev, port);
+	
+	port->open = cs461x_gameport_open;
+	port->read = cs461x_gameport_read;
+	port->trigger = cs461x_gameport_trigger;
+#ifdef COOKED_MODE
+	port->cooked_read = cs461x_gameport_cooked_read;
+#endif
+
+	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
+	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
+
+	gameport_register_port(port);
+
+	printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
+		port->number, port->speed);
+
+	return 0;
+}
+
+static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
+{
+	cs461x_free(pdev);
+}
+	
+static struct pci_driver cs461x_pci_driver = {
+        name:           "PCI Gameport",
+        id_table:       cs461x_pci_tbl,
+        probe:          cs461x_pci_probe,
+        remove:         cs461x_pci_remove,
+};
+
+int __init js_cs461x_init(void)
+{
+        return pci_module_init(&cs461x_pci_driver);
+}
+
+void __exit js_cs461x_exit(void)
+{
+        pci_unregister_driver(&cs461x_pci_driver);
+}
+
+module_init(js_cs461x_init);
+module_exit(js_cs461x_exit);
+
diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/emu10k1-gp.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,125 @@
+/*
+ * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
+ *
+ *  Copyright (c) 2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * EMU10k1 - SB Live! - gameport driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+struct emu {
+	struct pci_dev *dev;
+	struct emu *next;
+	struct gameport gameport;
+	int size;
+};
+	
+static struct pci_device_id emu_tbl[] __devinitdata = {
+	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, emu_tbl);
+
+static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int ioport, iolen;
+	int rc;
+	struct emu *port;
+        
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
+			pdev->bus->number, pdev->devfn, rc);
+		return rc;
+	}
+
+	ioport = pci_resource_start(pdev, 0);
+	iolen = pci_resource_len(pdev, 0);
+
+	if (!request_region(ioport, iolen, "emu10k1-gp"))
+		return -EBUSY;
+
+	if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
+		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
+		release_region(ioport, iolen);
+		return -ENOMEM;
+	}
+	memset(port, 0, sizeof(struct emu));
+
+	port->gameport.io = ioport;
+	port->size = iolen;
+	port->dev = pdev;
+	pci_set_drvdata(pdev, port);
+
+	gameport_register_port(&port->gameport);
+
+	printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
+		port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
+
+	return 0;
+}
+
+static void __devexit emu_remove(struct pci_dev *pdev)
+{
+	struct emu *port = pci_get_drvdata(pdev);
+	gameport_unregister_port(&port->gameport);
+	release_region(port->gameport.io, port->size);
+	kfree(port);
+}
+
+static struct pci_driver emu_driver = {
+        name:           "Emu10k1 Gameport",
+        id_table:       emu_tbl,
+        probe:          emu_probe,
+        remove:         emu_remove,
+};
+
+int __init emu_init(void)
+{
+	return pci_module_init(&emu_driver);
+}
+
+void __exit emu_exit(void)
+{
+	pci_unregister_driver(&emu_driver);
+}
+
+module_init(emu_init);
+module_exit(emu_exit);
diff -Nru a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/gameport.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,199 @@
+/*
+ * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Generic gameport layer
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/isapnp.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(gameport_register_port);
+EXPORT_SYMBOL(gameport_unregister_port);
+EXPORT_SYMBOL(gameport_register_device);
+EXPORT_SYMBOL(gameport_unregister_device);
+EXPORT_SYMBOL(gameport_open);
+EXPORT_SYMBOL(gameport_close);
+EXPORT_SYMBOL(gameport_rescan);
+EXPORT_SYMBOL(gameport_cooked_read);
+
+static struct gameport *gameport_list;
+static struct gameport_dev *gameport_dev;
+static int gameport_number;
+
+/*
+ * gameport_measure_speed() measures the gameport i/o speed.
+ */
+
+static int gameport_measure_speed(struct gameport *gameport)
+{
+#if defined(__i386__) || defined(__x86_64__)
+
+#define GET_TIME(x)     do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193180L/HZ:0))
+
+	unsigned int i, t, t1, t2, t3, tx;
+	unsigned long flags;
+
+	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+		return 0;
+
+	tx = 1 << 30;
+
+	for(i = 0; i < 50; i++) {
+		save_flags(flags);	/* Yes, all CPUs */
+		cli();
+		GET_TIME(t1);
+		for(t = 0; t < 50; t++) gameport_read(gameport);
+		GET_TIME(t2);
+		GET_TIME(t3);
+		restore_flags(flags);
+		udelay(i * 10);
+		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
+	}
+
+	return 59659 / (tx < 1 ? 1 : tx);
+
+#else
+
+	unsigned int j, t = 0;
+
+	j = jiffies; while (j == jiffies);
+	j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
+
+	return t * HZ / 1000;
+
+#endif
+
+	gameport_close(gameport);
+}
+
+static void gameport_find_dev(struct gameport *gameport)
+{
+        struct gameport_dev *dev = gameport_dev;
+
+        while (dev && !gameport->dev) {
+		if (dev->connect)
+                	dev->connect(gameport, dev);
+                dev = dev->next;
+        }
+}
+
+void gameport_rescan(struct gameport *gameport)
+{
+	gameport_close(gameport);
+	gameport_find_dev(gameport);
+}
+
+void gameport_register_port(struct gameport *gameport)
+{
+	gameport->number = gameport_number++;
+	gameport->next = gameport_list;	
+	gameport_list = gameport;
+
+	gameport->speed = gameport_measure_speed(gameport);
+
+	gameport_find_dev(gameport);
+}
+
+void gameport_unregister_port(struct gameport *gameport)
+{
+        struct gameport **gameportptr = &gameport_list;
+
+        while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
+        *gameportptr = (*gameportptr)->next;
+
+	if (gameport->dev && gameport->dev->disconnect)
+		gameport->dev->disconnect(gameport);
+
+	gameport_number--;
+}
+
+void gameport_register_device(struct gameport_dev *dev)
+{
+	struct gameport *gameport = gameport_list;
+
+	dev->next = gameport_dev;	
+	gameport_dev = dev;
+
+	while (gameport) {
+		if (!gameport->dev && dev->connect)
+			dev->connect(gameport, dev);
+		gameport = gameport->next;
+	}
+}
+
+void gameport_unregister_device(struct gameport_dev *dev)
+{
+        struct gameport_dev **devptr = &gameport_dev;
+	struct gameport *gameport = gameport_list;
+
+        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
+        *devptr = (*devptr)->next;
+
+	while (gameport) {
+		if (gameport->dev == dev && dev->disconnect)
+			dev->disconnect(gameport);
+		gameport_find_dev(gameport);
+		gameport = gameport->next;
+	}
+}
+
+int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
+{
+	if (gameport->open) {
+		if (gameport->open(gameport, mode))
+			return -1;
+	} else {
+		if (mode != GAMEPORT_MODE_RAW)
+			return -1;
+	}
+
+	if (gameport->dev)
+		return -1;
+
+	gameport->dev = dev;
+	
+	return 0;
+}
+
+void gameport_close(struct gameport *gameport)
+{
+	gameport->dev = NULL;
+	if (gameport->close) gameport->close(gameport);
+}
diff -Nru a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/lightning.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,298 @@
+/*
+ * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * PDPI Lightning 4 gamecard driver for Linux.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+
+#define L4_PORT			0x201
+#define L4_SELECT_ANALOG	0xa4
+#define L4_SELECT_DIGITAL	0xa5
+#define L4_SELECT_SECONDARY	0xa6
+#define L4_CMD_ID		0x80
+#define L4_CMD_GETCAL		0x92
+#define L4_CMD_SETCAL		0x93
+#define L4_ID			0x04
+#define L4_BUSY			0x01
+#define L4_TIMEOUT		80	/* 80 us */
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+
+struct l4 {
+	struct gameport gameport;
+	unsigned char port;
+} *l4_port[8];
+
+/*
+ * l4_wait_ready() waits for the L4 to become ready.
+ */
+
+static int l4_wait_ready(void)
+{
+	unsigned int t;
+	t = L4_TIMEOUT;
+	while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
+	return -(t<=0);
+}
+
+/*
+ * l4_cooked_read() reads data from the Lightning 4.
+ */
+
+static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	struct l4 *l4 = gameport->private;
+	unsigned char status;
+	int i, result = -1;
+
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
+
+	if (inb(L4_PORT) & L4_BUSY) goto fail;
+	outb(l4->port & 3, L4_PORT);
+
+	if (l4_wait_ready()) goto fail;
+	status = inb(L4_PORT);
+
+	for (i = 0; i < 4; i++)
+		if (status & (1 << i)) {
+			if (l4_wait_ready()) goto fail;
+			axes[i] = inb(L4_PORT);
+			if (axes[i] > 252) axes[i] = -1;
+		}
+
+	if (status & 0x10) {
+		if (l4_wait_ready()) goto fail;
+		*buttons = inb(L4_PORT) & 0x0f;
+	}
+
+	result = 0;
+
+fail:	outb(L4_SELECT_ANALOG, L4_PORT);	
+	return result;
+}
+
+static int l4_open(struct gameport *gameport, int mode)
+{
+	struct l4 *l4 = gameport->private;
+        if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
+		return -1;
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	return 0;
+}
+
+/*
+ * l4_getcal() reads the L4 with calibration values.
+ */
+
+static int l4_getcal(int port, int *cal)
+{
+	int i, result = -1;
+	
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+
+	if (inb(L4_PORT) & L4_BUSY) goto fail;
+	outb(L4_CMD_GETCAL, L4_PORT);
+
+	if (l4_wait_ready()) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+
+	if (l4_wait_ready()) goto fail;
+        outb(port & 3, L4_PORT);
+
+	for (i = 0; i < 4; i++) {
+		if (l4_wait_ready()) goto fail;
+		cal[i] = inb(L4_PORT);
+	}
+
+	result = 0;
+
+fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+	return result;
+}
+
+/*
+ * l4_setcal() programs the L4 with calibration values.
+ */
+
+static int l4_setcal(int port, int *cal)
+{
+	int i, result = -1;
+
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+
+	if (inb(L4_PORT) & L4_BUSY) goto fail;
+	outb(L4_CMD_SETCAL, L4_PORT);
+
+	if (l4_wait_ready()) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+
+	if (l4_wait_ready()) goto fail;
+        outb(port & 3, L4_PORT);
+
+	for (i = 0; i < 4; i++) {
+		if (l4_wait_ready()) goto fail;
+		outb(cal[i], L4_PORT);
+	}
+
+	result = 0;
+
+fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+	return result;
+}
+
+/*
+ * l4_calibrate() calibrates the L4 for the attached device, so
+ * that the device's resistance fits into the L4's 8-bit range.
+ */
+
+static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
+{
+	int i, t;
+	int cal[4];
+	struct l4 *l4 = gameport->private;
+
+	if (l4_getcal(l4->port, cal))
+		return -1;
+
+	for (i = 0; i < 4; i++) {
+		t = (max[i] * cal[i]) / 200;
+		t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
+		axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
+		axes[i] = (axes[i] > 252) ? 252 : axes[i];
+		cal[i] = t;
+	}
+
+	if (l4_setcal(l4->port, cal))
+		return -1;
+
+	return 0;
+}
+	
+int __init l4_init(void)
+{
+	int cal[4] = {255,255,255,255};
+	int i, j, rev, cards = 0;
+	struct gameport *gameport;
+	struct l4 *l4;
+
+	if (!request_region(L4_PORT, 1, "lightning"))
+		return -1;
+
+	for (i = 0; i < 2; i++) {
+
+		outb(L4_SELECT_ANALOG, L4_PORT);
+		outb(L4_SELECT_DIGITAL + i, L4_PORT);
+
+		if (inb(L4_PORT) & L4_BUSY) continue;
+		outb(L4_CMD_ID, L4_PORT);
+
+		if (l4_wait_ready()) continue;
+		if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
+
+		if (l4_wait_ready()) continue;
+		if (inb(L4_PORT) != L4_ID) continue;
+
+		if (l4_wait_ready()) continue;
+		rev = inb(L4_PORT);
+
+		if (!rev) continue;
+
+		if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
+			printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
+			continue;
+		}
+		memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
+
+		for (j = 0; j < 4; j++) {
+
+			l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
+			l4->port = i * 4 + j;
+
+			gameport = &l4->gameport;
+			gameport->private = l4;
+			gameport->open = l4_open;
+			gameport->cooked_read = l4_cooked_read;
+			gameport->calibrate = l4_calibrate;
+
+			if (!i && !j)
+				gameport->io = L4_PORT;
+
+			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
+				l4_setcal(l4->port, cal);
+			
+			gameport_register_port(gameport);
+		}
+
+		printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
+			l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number, 
+			l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number, 
+			i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
+
+		cards++;
+	}
+
+	outb(L4_SELECT_ANALOG, L4_PORT);
+
+	if (!cards) {
+		release_region(L4_PORT, 1);
+		return -1;
+	}
+
+	return 0;
+}
+
+void __init l4_exit(void)
+{
+	int i;
+	int cal[4] = {59, 59, 59, 59};
+
+	for (i = 0; i < 8; i++)
+		if (l4_port[i]) {
+			l4_setcal(l4_port[i]->port, cal);
+			gameport_unregister_port(&l4_port[i]->gameport);
+		}
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	release_region(L4_PORT, 1);
+}
+
+module_init(l4_init);
+module_exit(l4_exit);
diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/ns558.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,285 @@
+/*
+ * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *  Copyright (c) 1999 Brian Gerst
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * NS558 based standard IBM game port driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/isapnp.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+#define NS558_ISA	1
+#define NS558_PNP	2
+
+static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
+
+struct ns558 {
+	int type;
+	int size;
+	struct pci_dev *dev;
+	struct ns558 *next;
+	struct gameport gameport;
+};
+	
+static struct ns558 *ns558;
+
+/*
+ * ns558_isa_probe() tries to find an isa gameport at the
+ * specified address, and also checks for mirrors.
+ * A joystick must be attached for this to work.
+ */
+
+static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
+{
+	int i, j, b;
+	unsigned char c, u, v;
+	struct ns558 *port;
+
+/*
+ * No one should be using this address.
+ */
+
+	if (check_region(io, 1))
+		return next;
+
+/*
+ * We must not be able to write arbitrary values to the port.
+ * The lower two axis bits must be 1 after a write.
+ */
+
+	c = inb(io);
+	outb(~c & ~3, io);
+	if (~(u = v = inb(io)) & 3) {
+		outb(c, io);
+		return next;
+	}
+/*
+ * After a trigger, there must be at least some bits changing.
+ */
+
+	for (i = 0; i < 1000; i++) v &= inb(io);
+
+	if (u == v) {
+		outb(c, io);
+		return next;
+	}
+	wait_ms(3);
+/*
+ * After some time (4ms) the axes shouldn't change anymore.
+ */
+
+	u = inb(io);
+	for (i = 0; i < 1000; i++)
+		if ((u ^ inb(io)) & 0xf) {
+			outb(c, io);
+			return next;
+		}
+/* 
+ * And now find the number of mirrors of the port.
+ */
+
+	for (i = 1; i < 5; i++) {
+
+		if (check_region(io & (-1 << i), (1 << i)))	/* Don't disturb anyone */
+			break;
+
+		outb(0xff, io & (-1 << i));
+		for (j = b = 0; j < 1000; j++)
+			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
+		wait_ms(3);
+
+		if (b > 300)					/* We allow 30% difference */
+			break;
+	}
+
+	i--;
+
+	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+		printk(KERN_ERR "ns558: Memory allocation failed.\n");
+		return next;
+	}
+       	memset(port, 0, sizeof(struct ns558));
+	
+	port->next = next;
+	port->type = NS558_ISA;
+	port->size = (1 << i);
+	port->gameport.io = io & (-1 << i);
+
+	request_region(port->gameport.io, (1 << i), "ns558-isa");
+
+	gameport_register_port(&port->gameport);
+
+	printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
+	if (port->size > 1) printk(" size %d", port->size);
+	printk(" speed %d kHz\n", port->gameport.speed);
+
+	return port;
+}
+
+#ifdef __ISAPNP__
+
+static struct isapnp_device_id pnp_devids[] = {
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(isapnp, pnp_devids);
+
+static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
+{
+	int ioport, iolen;
+	struct ns558 *port;
+
+	if (dev->prepare && dev->prepare(dev) < 0)
+		return next;
+
+	if (!(dev->resource[0].flags & IORESOURCE_IO)) {
+		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
+		return next;
+	}
+
+	if (dev->activate && dev->activate(dev) < 0) {
+		printk(KERN_ERR "ns558: PnP resource allocation failed\n");
+		return next;
+	}
+	
+	ioport = pci_resource_start(dev, 0);
+	iolen = pci_resource_len(dev, 0);
+
+	if (!request_region(ioport, iolen, "ns558-pnp"))
+		goto deactivate;
+
+	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+		printk(KERN_ERR "ns558: Memory allocation failed.\n");
+		goto deactivate;
+	}
+	memset(port, 0, sizeof(struct ns558));
+
+	port->next = next;
+	port->type = NS558_PNP;
+	port->gameport.io = ioport;
+	port->size = iolen;
+	port->dev = dev;
+
+	gameport_register_port(&port->gameport);
+
+	printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
+	if (iolen > 1) printk(" size %d", iolen);
+	printk(" speed %d kHz\n", port->gameport.speed);
+
+	return port;
+
+deactivate:
+	if (dev->deactivate)
+		dev->deactivate(dev);
+	return next;
+}
+#endif
+
+int __init ns558_init(void)
+{
+	int i = 0;
+#ifdef __ISAPNP__
+	struct isapnp_device_id *devid;
+	struct pci_dev *dev = NULL;
+#endif
+
+/*
+ * Probe for ISA ports.
+ */
+
+	while (ns558_isa_portlist[i]) 
+		ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
+
+/*
+ * Probe for PnP ports.
+ */
+
+#ifdef __ISAPNP__
+	for (devid = pnp_devids; devid->vendor; devid++) {
+		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
+			ns558 = ns558_pnp_probe(dev, ns558);
+		}
+	}
+#endif
+
+	return ns558 ? 0 : -ENODEV;
+}
+
+void __exit ns558_exit(void)
+{
+	struct ns558 *next, *port = ns558;
+
+	while (port) {
+		gameport_unregister_port(&port->gameport);
+		switch (port->type) {
+
+#ifdef __ISAPNP__
+			case NS558_PNP:
+				if (port->dev->deactivate)
+					port->dev->deactivate(port->dev);
+				/* fall through */
+#endif
+
+			case NS558_ISA:
+				release_region(port->gameport.io, port->size);
+				break;
+		
+			default:
+				break;
+		}
+		
+		next = port->next;
+		kfree(port);
+		port = next;
+	}
+}
+
+module_init(ns558_init);
+module_exit(ns558_exit);
diff -Nru a/drivers/input/gameport/pcigame.c b/drivers/input/gameport/pcigame.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/pcigame.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,199 @@
+/*
+ * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Raymond Ingles
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Trident 4DWave and Aureal Vortex gameport driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gameport.h>
+
+#define PCI_VENDOR_ID_AUREAL	0x12eb
+
+#define PCIGAME_DATA_WAIT	20	/* 20 ms */
+
+#define PCIGAME_4DWAVE		0
+#define PCIGAME_VORTEX		1
+#define PCIGAME_VORTEX2		2
+
+struct pcigame_data {
+	int gcr;	/* Gameport control register */
+	int legacy;	/* Legacy port location */
+	int axes;	/* Axes start */
+	int axsize;	/* Axis field size */
+	int axmax;	/* Axis field max value */
+	int adcmode;	/* Value to enable ADC mode in GCR */
+};
+
+static struct pcigame_data pcigame_data[] __devinitdata =
+{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
+ { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
+ { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
+ { 0 }};
+
+struct pcigame {
+	struct gameport gameport;
+	struct pci_dev *dev;
+        unsigned char *base;
+	struct pcigame_data *data;
+};
+
+static unsigned char pcigame_read(struct gameport *gameport)
+{
+	struct pcigame *pcigame = gameport->private;
+	return readb(pcigame->base + pcigame->data->legacy);
+}
+
+static void pcigame_trigger(struct gameport *gameport)
+{
+	struct pcigame *pcigame = gameport->private;
+	writeb(0xff, pcigame->base + pcigame->data->legacy);
+}
+
+static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+        struct pcigame *pcigame = gameport->private;
+	int i;
+
+	*buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
+
+	for (i = 0; i < 4; i++) {
+		axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
+		if (axes[i] == pcigame->data->axmax) axes[i] = -1;
+	}
+        
+        return 0;
+}
+
+static int pcigame_open(struct gameport *gameport, int mode)
+{
+	struct pcigame *pcigame = gameport->private;
+
+	switch (mode) {
+		case GAMEPORT_MODE_COOKED:
+			writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
+			wait_ms(PCIGAME_DATA_WAIT);
+			return 0;
+		case GAMEPORT_MODE_RAW:
+			writeb(0, pcigame->base + pcigame->data->gcr);
+			return 0;
+		default:
+			return -1;
+	}
+
+	return 0;
+}
+
+static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct pcigame *pcigame;
+	int i;
+
+	if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
+		return -1;
+        memset(pcigame, 0, sizeof(struct pcigame));
+
+
+	pcigame->data = pcigame_data + id->driver_data;
+
+	pcigame->dev = dev;
+	pci_set_drvdata(dev, pcigame);
+
+	pcigame->gameport.private = pcigame;
+	pcigame->gameport.fuzz = 64;
+	
+	pcigame->gameport.read = pcigame_read;
+	pcigame->gameport.trigger = pcigame_trigger;
+	pcigame->gameport.cooked_read = pcigame_cooked_read;
+	pcigame->gameport.open = pcigame_open;
+
+	for (i = 0; i < 6; i++)
+		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
+			break;
+
+	pci_enable_device(dev);
+
+	pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
+				pci_resource_len(pcigame->dev, i));
+
+	gameport_register_port(&pcigame->gameport);
+	
+	printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
+		pcigame->gameport.number, dev->name, dev->bus->number,
+			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
+
+	return 0;
+}
+
+static void __devexit pcigame_remove(struct pci_dev *dev)
+{
+	struct pcigame *pcigame = pci_get_drvdata(dev);
+	gameport_unregister_port(&pcigame->gameport);
+	iounmap(pcigame->base);
+	kfree(pcigame);
+}
+
+static struct pci_device_id pcigame_id_table[] __devinitdata =
+{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
+ { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE  },
+ { PCI_VENDOR_ID_AUREAL,  0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX  },
+ { PCI_VENDOR_ID_AUREAL,  0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
+ { 0 }};
+
+static struct pci_driver pcigame_driver = {
+	name:		"pcigame",
+	id_table:	pcigame_id_table,
+	probe:		pcigame_probe,
+	remove:		pcigame_remove,
+};
+
+int __init pcigame_init(void)
+{
+	return pci_module_init(&pcigame_driver);
+}
+
+void __exit pcigame_exit(void)
+{
+	pci_unregister_driver(&pcigame_driver);
+}
+
+module_init(pcigame_init);
+module_exit(pcigame_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/Config.help	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,205 @@
+CONFIG_JOYSTICK
+  If you have a joystick, 6dof controller, gamepad, steering wheel,
+  weapon control system or something like that you can say Y here
+  and the list of supported devices will be displayed. This option
+  doesn't affect the kernel.
+
+  Please read the file <file:Documentation/input/joystick.txt> which
+  contains more information.
+
+CONFIG_JOYSTICK_ANALOG
+  Say Y here if you have a joystick that connects to the PC
+  gameport. In addition to the usual PC analog joystick, this driver
+  supports many extensions, including joysticks with throttle control,
+  with rudders, additional hats and buttons compatible with CH
+  Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or
+  Saitek Cyborg joysticks. 
+
+  Please read the file <file:Documentation/input/joystick.txt> which
+  contains more information.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called analog.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_A3D
+  Say Y here if you have an FPGaming or MadCatz controller using the
+  A3D protocol over the PC gameport. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called a3d.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_ADI
+  Say Y here if you have a Logitech controller using the ADI
+  protocol over the PC gameport. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called adi.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_COBRA
+  Say Y here if you have a Creative Labs Blaster Cobra gamepad.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cobra.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GF2K
+  Say Y here if you have a Genius Flight2000 or MaxFighter digitally
+  communicating joystick or gamepad.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called gf2k.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GRIP
+  Say Y here if you have a Gravis controller using the GrIP protocol
+  over the PC gameport. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called grip.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_INTERACT
+  Say Y here if you have an InterAct gameport or joystick
+  communicating digitally over the gameport.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called interact.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SIDEWINDER
+  Say Y here if you have a Microsoft controller using the Digital
+  Overdrive protocol over PC gameport.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called sidewinder.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_TMDC
+  Say Y here if you have a ThrustMaster controller using the
+  DirectConnect (BSP) protocol over the PC gameport. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tmdc.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_IFORCE_USB
+  Say Y here if you have an I-Force joystick or steering wheel
+  connected to your USB port. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called iforce.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_IFORCE_232
+  Say Y here if you have an I-Force joystick or steering wheel
+  connected to your serial (COM) port.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called iforce.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_WARRIOR
+  Say Y here if you have a Logitech WingMan Warrior joystick connected
+  to your computer's serial port. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called warrior.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_MAGELLAN
+  Say Y here if you have a Magellan or Space Mouse 6DOF controller
+  connected to your computer's serial port.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called magellan.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SPACEORB
+  Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
+  controller connected to your computer's serial port.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called spaceorb.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SPACEBALL
+  Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX
+  controller connected to your computer's serial port. For the
+  SpaceBall 4000 USB model, use the USB HID driver.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called spaceball.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_STINGER
+  Say Y here if you have a Gravis Stinger connected to one of your
+  serial ports.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called stinger.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_DB9
+  Say Y here if you have a Sega Master System gamepad, Sega Genesis
+  gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
+  Commodore, Amstrad CPC joystick connected to your parallel port.
+  For more information on how to use the driver please read
+  <file:Documentation/input/joystick-parport.txt>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called db9.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GAMECON
+  Say Y here if you have a Nintendo Entertainment System gamepad,
+  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
+  Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
+  Commodore, Amstrad CPC joystick connected to your parallel port.
+  For more information on how to use the driver please read
+  <file:Documentation/input/joystick-parport.txt>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called gamecon.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_TURBOGRAFX
+  Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
+  and want to use it with Multisystem -- Atari, Amiga, Commodore,
+  Amstrad CPC joystick. For more information on how to use the driver
+  please read <file:Documentation/input/joystick-parport.txt>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called turbografx.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_AMIJOY
+  Say Y here if you have an Amiga with a digital joystick connected
+  to it.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called joy-amiga.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
diff -Nru a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/Config.in	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,31 @@
+#
+# Joystick driver configuration
+#
+
+bool 'Joysticks' CONFIG_INPUT_JOYSTICK
+
+dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_JOYSTICK_ANALOG $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Assasin 3D and MadCatz Panther devices' CONFIG_JOYSTICK_A3D $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Logitech ADI digital joysticks and gamepads' CONFIG_JOYSTICK_ADI $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate '  ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+
+dep_tristate '  I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_USB
+dep_tristate '  I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  Logitech WingMan Warrior joystick' CONFIG_JOYSTICK_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate '  Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+
+dep_tristate '  Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+dep_tristate '  Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+dep_tristate '  Multisystem joysticks via TurboGraFX device' CONFIG_JOYSTICK_TURBOGRAFX $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate '  Amiga joysticks' CONFIG_JOYSTICK_AMIJOY $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
+fi
diff -Nru a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/Makefile	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,51 @@
+#
+# Makefile for the input core drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET	:= joydrv.o
+
+# I-Force may need both USB and RS-232
+
+CONFIG_JOYSTICK_IFORCE := n
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
+	ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
+		CONFIG_JOYSTICK_IFORCE := y
+	endif
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
+	CONFIG_JOYSTICK_IFORCE := m
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
+	CONFIG_JOYSTICK_IFORCE := m
+endif
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_JOYSTICK_A3D)		+= a3d.o
+obj-$(CONFIG_JOYSTICK_ADI)		+= adi.o
+obj-$(CONFIG_JOYSTICK_AMIGA)		+= amijoy.o
+obj-$(CONFIG_JOYSTICK_ANALOG)		+= analog.o
+obj-$(CONFIG_JOYSTICK_COBRA)		+= cobra.o
+obj-$(CONFIG_JOYSTICK_DB9)		+= db9.o
+obj-$(CONFIG_JOYSTICK_GAMECON)		+= gamecon.o
+obj-$(CONFIG_JOYSTICK_GF2K)		+= gf2k.o
+obj-$(CONFIG_JOYSTICK_GRIP)		+= grip.o
+obj-$(CONFIG_JOYSTICK_IFORCE)		+= iforce.o
+obj-$(CONFIG_JOYSTICK_INTERACT)		+= interact.o
+obj-$(CONFIG_JOYSTICK_MAGELLAN)		+= magellan.o
+obj-$(CONFIG_JOYSTICK_SIDEWINDER)	+= sidewinder.o
+obj-$(CONFIG_JOYSTICK_SPACEBALL)	+= spaceball.o
+obj-$(CONFIG_JOYSTICK_SPACEORB)		+= spaceorb.o
+obj-$(CONFIG_JOYSTICK_STINGER)		+= stinger.o
+obj-$(CONFIG_JOYSTICK_TMDC)		+= tmdc.o
+obj-$(CONFIG_JOYSTICK_TURBOGRAFX)	+= turbografx.o
+obj-$(CONFIG_JOYSTICK_WARRIOR)		+= warrior.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/a3d.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,388 @@
+/*
+ * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * FP-Gaming Assasin 3D joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define A3D_MAX_START		400	/* 400 us */ 
+#define A3D_MAX_STROBE		60	/* 40 us */ 
+#define A3D_DELAY_READ		3	/* 3 ms */
+#define A3D_MAX_LENGTH		40	/* 40*3 bits */
+#define A3D_REFRESH_TIME	HZ/50	/* 20 ms */
+
+#define A3D_MODE_A3D		1	/* Assassin 3D */
+#define A3D_MODE_PAN		2	/* Panther */
+#define A3D_MODE_OEM		3	/* Panther OEM version */
+#define A3D_MODE_PXL		4	/* Panther XL */
+
+char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
+			"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
+
+struct a3d {
+	struct gameport *gameport;
+	struct gameport adc;
+	struct input_dev dev;
+	struct timer_list timer;
+	int axes[4];
+	int buttons;
+	int mode;
+	int length;
+	int used;
+	int reads;
+	int bads;
+};
+
+/*
+ * a3d_read_packet() reads an Assassin 3D packet.
+ */
+
+static int a3d_read_packet(struct gameport *gameport, int length, char *data)
+{
+	unsigned long flags;
+	unsigned char u, v;
+	unsigned int t, s;
+	int i;
+
+	i = 0;
+	t = gameport_time(gameport, A3D_MAX_START);
+	s = gameport_time(gameport, A3D_MAX_STROBE);
+
+	__save_flags(flags);
+	__cli();
+	gameport_trigger(gameport);
+	v = gameport_read(gameport);
+
+	while (t > 0 && i < length) {
+		t--;
+		u = v; v = gameport_read(gameport);
+		if (~v & u & 0x10) {
+			data[i++] = v >> 5;
+			t = s;
+		}
+	}
+
+	__restore_flags(flags);
+
+	return i;
+}
+
+/*
+ * a3d_csum() computes checksum of triplet packet
+ */
+
+static int a3d_csum(char *data, int count)
+{
+	int i, csum = 0;
+	for (i = 0; i < count - 2; i++) csum += data[i];
+	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
+}
+
+static void a3d_read(struct a3d *a3d, unsigned char *data)
+{
+	struct input_dev *dev = &a3d->dev;
+
+	switch (a3d->mode) {
+
+		case A3D_MODE_A3D:
+		case A3D_MODE_OEM:
+		case A3D_MODE_PAN:
+
+			input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
+			input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
+			
+			input_report_key(dev, BTN_RIGHT,  data[2] & 1);
+			input_report_key(dev, BTN_LEFT,   data[3] & 2);
+			input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+
+			a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
+			a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
+			a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
+			a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
+
+			a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
+
+			return;
+
+		case A3D_MODE_PXL:
+
+			input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
+			input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
+
+			input_report_key(dev, BTN_RIGHT,  data[2] & 1);
+			input_report_key(dev, BTN_LEFT,   data[3] & 2);
+			input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+			input_report_key(dev, BTN_SIDE,   data[7] & 2);
+			input_report_key(dev, BTN_EXTRA,  data[7] & 4);
+
+			input_report_abs(dev, ABS_X,        ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
+			input_report_abs(dev, ABS_Y,        ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
+			input_report_abs(dev, ABS_RUDDER,   ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
+			input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
+
+			input_report_abs(dev, ABS_HAT0X, ( data[5]       & 1) - ((data[5] >> 2) & 1));
+			input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
+			input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3]       & 1));
+			input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4]       & 1));
+
+			input_report_key(dev, BTN_TRIGGER, data[8] & 1);
+			input_report_key(dev, BTN_THUMB,   data[8] & 2);
+			input_report_key(dev, BTN_TOP,     data[8] & 4);
+			input_report_key(dev, BTN_PINKIE,  data[7] & 1);
+
+			return;
+	}
+}
+
+
+/*
+ * a3d_timer() reads and analyzes A3D joystick data.
+ */
+
+static void a3d_timer(unsigned long private)
+{
+	struct a3d *a3d = (void *) private;
+	unsigned char data[A3D_MAX_LENGTH];
+	a3d->reads++;
+	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
+		|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
+	 	a3d->bads++; else a3d_read(a3d, data);
+	mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+}
+
+/*
+ * a3d_adc_cooked_read() copies the acis and button data to the
+ * callers arrays. It could do the read itself, but the caller could
+ * call this more than 50 times a second, which would use too much CPU.
+ */
+
+int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	struct a3d *a3d = gameport->private;
+	int i;
+	for (i = 0; i < 4; i++)
+		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
+	*buttons = a3d->buttons; 
+	return 0;
+}
+
+/*
+ * a3d_adc_open() is the gameport open routine. It refuses to serve
+ * any but cooked data.
+ */
+
+int a3d_adc_open(struct gameport *gameport, int mode)
+{
+	struct a3d *a3d = gameport->private;
+	if (mode != GAMEPORT_MODE_COOKED)
+		return -1;
+	if (!a3d->used++)
+		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * a3d_adc_close() is a callback from the input close routine.
+ */
+
+static void a3d_adc_close(struct gameport *gameport)
+{
+	struct a3d *a3d = gameport->private;
+	if (!--a3d->used)
+		del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_open() is a callback from the input open routine.
+ */
+
+static int a3d_open(struct input_dev *dev)
+{
+	struct a3d *a3d = dev->private;
+	if (!a3d->used++)
+		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * a3d_close() is a callback from the input close routine.
+ */
+
+static void a3d_close(struct input_dev *dev)
+{
+	struct a3d *a3d = dev->private;
+	if (!--a3d->used)
+		del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_connect() probes for A3D joysticks.
+ */
+
+static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct a3d *a3d;
+	unsigned char data[A3D_MAX_LENGTH];
+	int i;
+
+	if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
+		return;
+	memset(a3d, 0, sizeof(struct a3d));
+
+	gameport->private = a3d;
+
+	a3d->gameport = gameport;
+	init_timer(&a3d->timer);
+	a3d->timer.data = (long) a3d;
+	a3d->timer.function = a3d_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
+
+	if (!i || a3d_csum(data, i))
+		goto fail2;
+
+	a3d->mode = data[0];
+
+	if (!a3d->mode || a3d->mode > 5) {
+		printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
+			"(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
+		goto fail2;
+	}
+
+
+	if (a3d->mode == A3D_MODE_PXL) {
+
+		int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
+
+		a3d->length = 33;
+
+		a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+		a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
+				   | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
+
+		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
+						 | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+
+		a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
+
+		a3d_read(a3d, data);
+
+		for (i = 0; i < 4; i++) {
+			if (i < 2) {
+				a3d->dev.absmin[axes[i]] = 48;
+				a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
+				a3d->dev.absflat[axes[i]] = 8;
+			} else {
+				a3d->dev.absmin[axes[i]] = 2;
+				a3d->dev.absmax[axes[i]] = 253;
+			}
+			a3d->dev.absmin[ABS_HAT0X + i] = -1;
+			a3d->dev.absmax[ABS_HAT0X + i] = 1;
+		}
+
+	} else {
+		a3d->length = 29;
+
+		a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
+		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
+
+		a3d->adc.private = a3d;
+		a3d->adc.open = a3d_adc_open;
+		a3d->adc.close = a3d_adc_close;
+		a3d->adc.cooked_read = a3d_adc_cooked_read;
+		a3d->adc.fuzz = 1; 
+
+		a3d_read(a3d, data);
+
+		gameport_register_port(&a3d->adc);
+		printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
+			a3d->adc.number, a3d_names[a3d->mode], gameport->number);
+	}
+
+	a3d->dev.private = a3d;
+	a3d->dev.open = a3d_open;
+	a3d->dev.close = a3d_close;
+
+	a3d->dev.name = a3d_names[a3d->mode];
+	a3d->dev.idbus = BUS_GAMEPORT;
+	a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
+	a3d->dev.idproduct = a3d->mode;
+	a3d->dev.idversion = 0x0100;
+
+	input_register_device(&a3d->dev);
+	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+		a3d->dev.number, a3d_names[a3d->mode], gameport->number);
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:  kfree(a3d);
+}
+
+static void a3d_disconnect(struct gameport *gameport)
+{
+
+	struct a3d *a3d = gameport->private;
+	input_unregister_device(&a3d->dev);
+	if (a3d->mode < A3D_MODE_PXL)
+		gameport_unregister_port(&a3d->adc);
+	gameport_close(gameport);
+	kfree(a3d);
+}
+
+static struct gameport_dev a3d_dev = {
+	connect:	a3d_connect,
+	disconnect:	a3d_disconnect,
+};
+
+int __init a3d_init(void)
+{
+	gameport_register_device(&a3d_dev);
+	return 0;
+}
+
+void __exit a3d_exit(void)
+{
+	gameport_unregister_device(&a3d_dev);
+}
+
+module_init(a3d_init);
+module_exit(a3d_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/adi.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,557 @@
+/*
+ * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Logitech ADI joystick family driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+#include <linux/init.h>
+
+/*
+ * Times, array sizes, flags, ids.
+ */
+
+#define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
+#define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
+#define ADI_REFRESH_TIME	HZ/50	/* How often to poll the joystick [20 ms] */
+#define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
+#define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
+
+#define ADI_MAX_LENGTH		256
+#define ADI_MIN_LENGTH		8
+#define ADI_MIN_LEN_LENGTH	10
+#define ADI_MIN_ID_LENGTH	66
+#define ADI_MAX_NAME_LENGTH	48
+#define ADI_MAX_CNAME_LENGTH	16
+
+#define ADI_FLAG_HAT		0x04
+#define ADI_FLAG_10BIT		0x08
+
+#define ADI_ID_TPD		0x01
+#define ADI_ID_WGP		0x06
+#define ADI_ID_WGPE		0x08
+#define ADI_ID_MAX		0x0a
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *adi_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
+				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 
+				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 
+				"WingMan GamePad USB", "Unknown Device %#x" };
+
+static char adi_wmgpe_abs[] =	{ ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
+static char adi_wmi_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static char adi_wmed3d_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
+static char adi_cm2_abs[] =	{ ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+
+static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
+static short adi_wmi_key[] = 	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
+static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
+
+static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
+			   adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
+
+static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
+			    adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
+
+/*
+ * Hat to axis conversion arrays.
+ */
+
+static struct {
+	int x;
+	int y;
+} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+/*
+ * Per-port information.
+ */
+
+struct adi {
+	struct input_dev dev;
+	int length;
+	int ret;
+	int idx;
+	unsigned char id;
+	char buttons;
+	char axes10;
+	char axes8;
+	signed char pad;
+	char hats;
+	char *abs;
+	short *key;
+	char name[ADI_MAX_NAME_LENGTH];
+	char cname[ADI_MAX_CNAME_LENGTH];
+	unsigned char data[ADI_MAX_LENGTH];
+};
+
+struct adi_port {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct adi adi[2];
+	int bad;
+	int reads;
+	int used;
+};
+
+/*
+ * adi_read_packet() reads a Logitech ADI packet.
+ */
+
+static void adi_read_packet(struct adi_port *port)
+{
+	struct adi *adi = port->adi;
+	struct gameport *gameport = port->gameport;
+	unsigned char u, v, w, x, z;
+	int t[2], s[2], i;
+	unsigned long flags;
+
+	for (i = 0; i < 2; i++) {
+		adi[i].ret = -1;
+		t[i] = gameport_time(gameport, ADI_MAX_START);
+		s[i] = 0;
+	}
+
+	__save_flags(flags);
+	__cli();
+
+	gameport_trigger(gameport);
+	v = z = gameport_read(gameport);
+
+	do {
+		u = v;
+		w = u ^ (v = x = gameport_read(gameport));
+		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
+			t[i]--;
+			if ((w & 0x30) && s[i]) {
+				if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
+					adi[i].data[++adi[i].ret] = w;
+					t[i] = gameport_time(gameport, ADI_MAX_STROBE);
+				} else t[i] = 0;
+			} else if (!(x & 0x30)) s[i] = 1;
+		}
+	} while (t[0] > 0 || t[1] > 0);
+
+	__restore_flags(flags);
+
+	return;
+}
+
+/*
+ * adi_move_bits() detects a possible 2-stream mode, and moves
+ * the bits accordingly. 
+ */
+
+static void adi_move_bits(struct adi_port *port, int length)
+{
+	int i;
+	struct adi *adi = port->adi;
+
+ 	adi[0].idx = adi[1].idx = 0;
+
+	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
+	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
+
+	for (i = 1; i <= adi[1].ret; i++)
+		adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
+
+	adi[0].ret += adi[1].ret;
+	adi[1].ret = -1;
+}
+
+/*
+ * adi_get_bits() gathers bits from the data packet.
+ */
+
+static inline int adi_get_bits(struct adi *adi, int count)
+{
+	int bits = 0;
+	int i;
+	if ((adi->idx += count) > adi->ret) return 0;
+	for (i = 0; i < count; i++)
+		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; 
+	return bits;
+}
+
+/*
+ * adi_decode() decodes Logitech joystick data into input events.
+ */
+
+static int adi_decode(struct adi *adi)
+{
+	struct input_dev *dev = &adi->dev;
+	char *abs = adi->abs;
+	short *key = adi->key;
+	int i, t;
+
+	if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
+		return -1;	
+
+	for (i = 0; i < adi->axes10; i++) 
+		input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
+
+	for (i = 0; i < adi->axes8; i++) 
+		input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
+
+	for (i = 0; i < adi->buttons && i < 63; i++) {
+		if (i == adi->pad) {
+			t = adi_get_bits(adi, 4);
+			input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t       & 1));
+			input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
+		}
+		input_report_key(dev, *key++, adi_get_bits(adi, 1));
+	}
+
+	for (i = 0; i < adi->hats; i++) {
+		if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
+		input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
+		input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
+	}
+
+	for (i = 63; i < adi->buttons; i++)
+		input_report_key(dev, *key++, adi_get_bits(adi, 1));
+
+	return 0;
+}
+
+/*
+ * adi_read() reads the data packet and decodes it.
+ */
+
+static int adi_read(struct adi_port *port)
+{
+	int i;
+	int result = 0;
+
+	adi_read_packet(port);
+	adi_move_bits(port, port->adi[0].length);
+
+	for (i = 0; i < 2; i++)
+		if (port->adi[i].length)
+			 result |= adi_decode(port->adi + i);
+
+	return result;
+}
+
+/*
+ * adi_timer() repeatedly polls the Logitech joysticks.
+ */
+
+static void adi_timer(unsigned long data)
+{
+	struct adi_port *port = (void *) data;
+	port->bad -= adi_read(port);
+	port->reads++;
+	mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+}
+
+/*
+ * adi_open() is a callback from the input open routine.
+ */
+
+static int adi_open(struct input_dev *dev)
+{
+	struct adi_port *port = dev->private;
+	if (!port->used++)
+		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * adi_close() is a callback from the input close routine.
+ */
+
+static void adi_close(struct input_dev *dev)
+{
+	struct adi_port *port = dev->private;
+	if (!--port->used)
+		del_timer(&port->timer);
+}
+
+/*
+ * adi_init_digital() sends a trigger & delay sequence
+ * to reset and initialize a Logitech joystick into digital mode.
+ */
+
+static void adi_init_digital(struct gameport *gameport)
+{
+	int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
+	int i;
+
+	for (i = 0; seq[i]; i++) {
+		gameport_trigger(gameport);
+		if (seq[i] > 0) wait_ms(seq[i]);
+		if (seq[i] < 0) mdelay(-seq[i]);
+	}
+}
+
+static void adi_id_decode(struct adi *adi, struct adi_port *port)
+{
+	int i, t;
+
+	if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
+		return;
+
+	if (adi->ret < (t = adi_get_bits(adi, 10))) {
+		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); 
+		return;
+	}
+
+	adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
+
+	if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
+
+	adi->length = adi_get_bits(adi, 10);
+
+	if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
+		printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
+		adi->length = 0;
+		return;
+	}
+
+	adi->axes8 = adi_get_bits(adi, 4);
+	adi->buttons = adi_get_bits(adi, 6);
+
+	if (adi_get_bits(adi, 6) != 8 && adi->hats) {
+		printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
+		adi->length = 0;
+		return;
+	}
+
+	adi->buttons += adi_get_bits(adi, 6);
+	adi->hats += adi_get_bits(adi, 4);
+
+	i = adi_get_bits(adi, 4);
+
+	if (t & ADI_FLAG_10BIT) {
+		adi->axes10 = adi->axes8 - i;
+		adi->axes8 = i;
+	}
+
+	t = adi_get_bits(adi, 4);
+
+	for (i = 0; i < t; i++)
+		adi->cname[i] = adi_get_bits(adi, 8);
+	adi->cname[i] = 0;
+
+	t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
+	if (adi->length != t && adi->length != t + (t & 1)) {
+		printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
+		adi->length = 0;
+		return;
+	}
+
+	switch (adi->id) {
+		case ADI_ID_TPD:
+			adi->pad = 4;
+			adi->buttons -= 4;
+			break;
+		case ADI_ID_WGP:
+			adi->pad = 0;
+			adi->buttons -= 4;
+			break;
+		default:
+			adi->pad = -1;
+			break;
+	}
+}
+
+static void adi_init_input(struct adi *adi, struct adi_port *port)
+{
+	int i, t;
+	char buf[ADI_MAX_NAME_LENGTH];
+
+	if (!adi->length) return;
+
+	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
+
+	sprintf(buf, adi_names[t], adi->id);
+	sprintf(adi->name, "Logitech %s", buf);
+
+	adi->abs = adi_abs[t];
+	adi->key = adi_key[t];
+
+	adi->dev.open = adi_open;
+	adi->dev.close = adi_close;
+
+	adi->dev.name = adi->name;
+	adi->dev.idbus = BUS_GAMEPORT;
+	adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
+	adi->dev.idproduct = adi->id;
+	adi->dev.idversion = 0x0100;
+
+	adi->dev.private = port;
+	adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
+		set_bit(adi->abs[i], &adi->dev.absbit);
+
+	for (i = 0; i < adi->buttons; i++)
+		set_bit(adi->key[i], &adi->dev.keybit);
+}
+
+static void adi_init_center(struct adi *adi)
+{
+	int i, t, x;
+
+	if (!adi->length) return;
+
+	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
+
+		t = adi->abs[i];
+		x = adi->dev.abs[t];
+
+		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
+			if (i < adi->axes10) x = 512; else x = 128;
+		}
+
+		if (i < adi->axes10) {
+			adi->dev.absmax[t] = x * 2 - 64;
+			adi->dev.absmin[t] = 64;
+			adi->dev.absfuzz[t] = 2;
+			adi->dev.absflat[t] = 16;
+			continue;
+		}
+
+		if (i < adi->axes10 + adi->axes8) {
+			adi->dev.absmax[t] = x * 2 - 48;
+			adi->dev.absmin[t] = 48;
+			adi->dev.absfuzz[t] = 1;
+			adi->dev.absflat[t] = 16;
+			continue;
+		}
+
+		adi->dev.absmax[t] = 1;
+		adi->dev.absmin[t] = -1;
+	}
+}
+
+/*
+ * adi_connect() probes for Logitech ADI joysticks.
+ */
+
+static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct adi_port *port;
+	int i;
+
+	if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
+		return;
+	memset(port, 0, sizeof(struct adi_port));
+
+	gameport->private = port;
+
+	port->gameport = gameport;
+	init_timer(&port->timer);
+	port->timer.data = (long) port;
+	port->timer.function = adi_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+		kfree(port);
+		return;
+	}
+
+	adi_init_digital(gameport);
+	adi_read_packet(port);
+	
+	if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
+		adi_move_bits(port, adi_get_bits(port->adi, 10));
+
+	for (i = 0; i < 2; i++) {
+		adi_id_decode(port->adi + i, port);
+		adi_init_input(port->adi + i, port);
+	}
+
+	if (!port->adi[0].length && !port->adi[1].length) {
+		gameport_close(gameport);
+		kfree(port);
+		return;
+	}
+
+	wait_ms(ADI_INIT_DELAY);
+	if (adi_read(port)) {
+		wait_ms(ADI_DATA_DELAY);
+		adi_read(port);
+	}
+
+	for (i = 0; i < 2; i++)
+		if (port->adi[i].length > 0) {
+			adi_init_center(port->adi + i);
+			input_register_device(&port->adi[i].dev);
+			printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
+				port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
+		}
+}
+
+static void adi_disconnect(struct gameport *gameport)
+{
+	int i;
+
+	struct adi_port *port = gameport->private;
+	for (i = 0; i < 2; i++)
+		if (port->adi[i].length > 0)
+			input_unregister_device(&port->adi[i].dev);
+	gameport_close(gameport);
+	kfree(port);
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev adi_dev = {
+	connect:	adi_connect,
+	disconnect:	adi_disconnect,
+};
+
+int __init adi_init(void)
+{
+	gameport_register_device(&adi_dev);
+	return 0;
+}
+
+void __exit adi_exit(void)
+{
+	gameport_unregister_device(&adi_dev);
+}
+
+module_init(adi_init);
+module_exit(adi_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/amijoy.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,161 @@
+/*
+ * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Driver for Amiga joysticks for Linux/m68k
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/system.h>
+#include <asm/amigahw.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(amijoy, "1-2i");
+MODULE_LICENSE("GPL");
+
+static int amijoy[2] = { 0, 1 };
+static int amijoy_used[2] = { 0, 0 };
+static struct input_dev amijoy_dev[2];
+
+static char *amijoy_name = "Amiga joystick";
+
+static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+	int i, data = 0, button = 0;
+
+	for (i = 0; i < 2; i++)
+		if (amijoy[i]) {
+
+			switch (i) {
+				case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
+				case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
+			}
+
+			input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
+
+			input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
+			data = ~(data ^ (data << 1));
+			input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
+		}
+}
+
+static int amijoy_open(struct input_dev *dev)
+{
+	int *used = dev->private;
+
+	if ((*used)++)
+		return 0;
+	
+	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
+		(*used)--;
+		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
+		return -EBUSY;
+	}
+		
+	return 0;
+}
+
+static void amijoy_close(struct input_dev *dev)
+{
+	int *used = dev->private;
+
+	if (!--(*used))
+		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+}
+
+static int __init amijoy_setup(char *str)
+{
+	int i;
+	int ints[4]
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
+	return 1;
+}
+__setup("amijoy=", amijoy_setup);
+
+static int __init amijoy_init(void)
+{
+	int i, j;
+
+	init_timer(amijoy_timer);
+	port->timer.function = amijoy_timer;
+
+	for (i = 0; i < 2; i++)
+		if (amijoy[i]) {
+			if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
+						"amijoy [Denise]")) {
+				if (i == 1 && amijoy[0]) {
+					input_unregister_device(amijoy_dev);
+					release_mem_region(CUSTOM_PHYSADDR+10, 2);
+				}
+				return -EBUSY;
+			}
+
+			amijoy_dev[i].open = amijoy_open;
+			amijoy_dev[i].close = amijoy_close;
+			amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+			amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+			amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+			for (j = 0; j < 2; j++) {
+				amijoy_dev[i].absmin[ABS_X + j] = -1;
+				amijoy_dev[i].absmax[ABS_X + j] = 1;
+			}
+
+			amijoy->dev[i].name = amijoy_name;
+			amijoy->dev[i].idbus = BUS_AMIGA;
+			amijoy->dev[i].idvendor = 0x0001;
+			amijoy->dev[i].idproduct = 0x0003;
+			amijoy->dev[i].version = 0x0100;
+
+			amijoy_dev[i].private = amijoy_used + i;
+
+			input_register_device(amijoy_dev + i);
+			printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
+		}
+	return 0;
+}
+
+static void _exit amijoy_exit(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++)
+		if (amijoy[i]) {
+			input_unregister_device(amijoy_dev + i);
+			release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
+		}
+}
+
+module_init(amijoy_init);
+module_exit(amijoy_exit);
diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/analog.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,761 @@
+/*
+ * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
+ *
+ *  Copyright (c) 1996-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Analog joystick and gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+#include <asm/timex.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
+MODULE_LICENSE("GPL");
+
+/*
+ * Option parsing.
+ */
+
+#define ANALOG_PORTS		16
+
+static char *js[ANALOG_PORTS];
+static int analog_options[ANALOG_PORTS];
+MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
+MODULE_PARM_DESC(js, "Analog joystick options");
+
+/*
+ * Times, feature definitions.
+ */
+
+#define ANALOG_RUDDER		0x00004
+#define ANALOG_THROTTLE		0x00008
+#define ANALOG_AXES_STD		0x0000f
+#define ANALOG_BTNS_STD		0x000f0
+
+#define ANALOG_BTNS_CHF		0x00100
+#define ANALOG_HAT1_CHF		0x00200
+#define ANALOG_HAT2_CHF		0x00400
+#define ANALOG_HAT_FCS		0x00800
+#define ANALOG_HATS_ALL		0x00e00
+#define ANALOG_BTN_TL		0x01000
+#define ANALOG_BTN_TR		0x02000
+#define ANALOG_BTN_TL2		0x04000
+#define ANALOG_BTN_TR2		0x08000
+#define ANALOG_BTNS_TLR		0x03000
+#define ANALOG_BTNS_TLR2	0x0c000
+#define ANALOG_BTNS_GAMEPAD	0x0f000
+
+#define ANALOG_HBTN_CHF		0x10000
+#define ANALOG_ANY_CHF		0x10700
+#define ANALOG_SAITEK		0x20000
+#define ANALOG_EXTENSIONS	0x7ff00
+#define ANALOG_GAMEPAD		0x80000
+
+#define ANALOG_MAX_TIME		3	/* 3 ms */
+#define ANALOG_LOOP_TIME	2000	/* 2 * loop */
+#define ANALOG_REFRESH_TIME	HZ/100	/* 10 ms */
+#define ANALOG_SAITEK_DELAY	200	/* 200 us */
+#define ANALOG_SAITEK_TIME	2000	/* 2000 us */
+#define ANALOG_AXIS_TIME	2	/* 2 * refresh */
+#define ANALOG_INIT_RETRIES	8	/* 8 times */
+#define ANALOG_FUZZ_BITS	2	/* 2 bit more */
+#define ANALOG_FUZZ_MAGIC	36	/* 36 u*ms/loop */
+
+#define ANALOG_MAX_NAME_LENGTH  128
+
+static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
+static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
+static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
+static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
+static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
+				  BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
+
+static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
+
+struct analog {
+	struct input_dev dev;
+	int mask;
+	short *buttons;
+	char name[ANALOG_MAX_NAME_LENGTH];
+};
+
+struct analog_port {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct analog analog[2];
+	unsigned char mask;
+	char saitek;
+	char cooked;
+	int bads;
+	int reads;
+	int speed;
+	int loop;
+	int fuzz;
+	int axes[4];
+	int buttons;
+	int initial[4];
+	int used;
+	int axtime;
+};
+
+/*
+ * Time macros.
+ */
+
+#ifdef __i386__
+#define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
+#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
+#define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
+#define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
+#elif __x86_64__
+#define GET_TIME(x)	rdtscl(x)
+#define DELTA(x,y)	((y)-(x))
+#define TIME_NAME	"TSC"
+#elif __alpha__
+#define GET_TIME(x)	((x) = get_cycles())
+#define DELTA(x,y)	((y)-(x))
+#define TIME_NAME	"PCC"
+#else
+#define FAKE_TIME
+static unsigned long analog_faketime = 0;
+#define GET_TIME(x)     do { x = analog_faketime++; } while(0)
+#define DELTA(x,y)	((y)-(x))
+#define TIME_NAME	"Unreliable"
+#warning Precise timer not defined for this architecture.
+#endif
+
+/*
+ * analog_decode() decodes analog joystick data and reports input events.
+ */
+
+static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
+{
+	struct input_dev *dev = &analog->dev;
+	int i, j;
+
+	if (analog->mask & ANALOG_HAT_FCS)
+		for (i = 0; i < 4; i++)
+			if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
+				buttons |= 1 << (i + 14);
+				break;
+			}
+
+	for (i = j = 0; i < 6; i++)
+		if (analog->mask & (0x10 << i))
+			input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
+
+	if (analog->mask & ANALOG_HBTN_CHF)
+		for (i = 0; i < 4; i++)
+			input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
+
+	if (analog->mask & ANALOG_BTN_TL)
+		input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
+	if (analog->mask & ANALOG_BTN_TR)
+		input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
+	if (analog->mask & ANALOG_BTN_TL2)
+		input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
+	if (analog->mask & ANALOG_BTN_TR2)
+		input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
+
+	for (i = j = 0; i < 4; i++)
+		if (analog->mask & (1 << i))
+			input_report_abs(dev, analog_axes[j++], axes[i]);
+
+	for (i = j = 0; i < 3; i++)
+		if (analog->mask & analog_exts[i]) {
+			input_report_abs(dev, analog_hats[j++],
+				((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
+			input_report_abs(dev, analog_hats[j++],
+				((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
+		}
+}
+
+/*
+ * analog_cooked_read() reads analog joystick data.
+ */
+
+static int analog_cooked_read(struct analog_port *port)
+{
+	struct gameport *gameport = port->gameport;
+	unsigned int time[4], start, loop, now, loopout, timeout;
+	unsigned char data[4], this, last;
+	unsigned long flags;
+	int i, j;
+
+	loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
+	timeout = ANALOG_MAX_TIME * port->speed;
+	
+	__save_flags(flags);
+	__cli();
+	gameport_trigger(gameport);
+	GET_TIME(now);
+	__restore_flags(flags);
+
+	start = now;
+	this = port->mask;
+	i = 0;
+
+	do {
+		loop = now;
+		last = this;
+
+		__cli();
+		this = gameport_read(gameport) & port->mask;
+		GET_TIME(now);
+		__restore_flags(flags);
+
+		if ((last ^ this) && (DELTA(loop, now) < loopout)) {
+			data[i] = last ^ this;
+			time[i] = now;
+			i++;
+		}
+
+	} while (this && (i < 4) && (DELTA(start, now) < timeout));
+
+	this <<= 4;
+
+	for (--i; i >= 0; i--) {
+		this |= data[i];
+		for (j = 0; j < 4; j++)
+			if (data[i] & (1 << j))
+				port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
+	}
+
+	return -(this != port->mask);
+}
+
+static int analog_button_read(struct analog_port *port, char saitek, char chf)
+{
+	unsigned char u;
+	int t = 1, i = 0;
+	int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
+
+	u = gameport_read(port->gameport);
+
+	if (!chf) { 
+		port->buttons = (~u >> 4) & 0xf;
+		return 0;
+	}
+
+	port->buttons = 0;
+
+	while ((~u & 0xf0) && (i < 16) && t) {
+		port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
+		if (!saitek) return 0;
+		udelay(ANALOG_SAITEK_DELAY);
+		t = strobe;
+		gameport_trigger(port->gameport);
+		while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
+		i++;
+	}
+
+	return -(!t || (i == 16));
+}
+
+/*
+ * analog_timer() repeatedly polls the Analog joysticks.
+ */
+
+static void analog_timer(unsigned long data)
+{
+	struct analog_port *port = (void *) data;
+	int i;
+
+	char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
+	char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
+
+	if (port->cooked) {
+		port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
+		if (chf)
+			port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
+		port->reads++;
+	} else {
+		if (!port->axtime--) {
+			port->bads -= analog_cooked_read(port);
+			port->bads -= analog_button_read(port, saitek, chf);
+			port->reads++;
+			port->axtime = ANALOG_AXIS_TIME - 1;
+		} else {
+			if (!saitek)
+				analog_button_read(port, saitek, chf);
+		}
+	}
+
+	for (i = 0; i < 2; i++) 
+		if (port->analog[i].mask)
+			analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
+
+	mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+}
+
+/*
+ * analog_open() is a callback from the input open routine.
+ */
+
+static int analog_open(struct input_dev *dev)
+{
+	struct analog_port *port = dev->private;
+	if (!port->used++)
+		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * analog_close() is a callback from the input close routine.
+ */
+
+static void analog_close(struct input_dev *dev)
+{
+	struct analog_port *port = dev->private;
+	if (!--port->used)
+		del_timer(&port->timer);
+}
+
+/*
+ * analog_calibrate_timer() calibrates the timer and computes loop
+ * and timeout values for a joystick port.
+ */
+
+static void analog_calibrate_timer(struct analog_port *port)
+{
+	struct gameport *gameport = port->gameport;
+	unsigned int i, t, tx, t1, t2, t3;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	GET_TIME(t1);
+#ifdef FAKE_TIME
+	analog_faketime += 830;
+#endif
+	udelay(1000);
+	GET_TIME(t2);
+	GET_TIME(t3);
+	restore_flags(flags);
+
+	port->speed = DELTA(t1, t2) - DELTA(t2, t3);
+
+	tx = ~0;
+
+	for (i = 0; i < 50; i++) {
+		save_flags(flags);
+		cli();
+		GET_TIME(t1);
+		for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
+		GET_TIME(t3);
+		restore_flags(flags);
+		udelay(i);
+		t = DELTA(t1, t2) - DELTA(t2, t3);
+		if (t < tx) tx = t;
+	}
+
+        port->loop = tx / 50;
+}
+
+/*
+ * analog_name() constructs a name for an analog joystick.
+ */
+
+static void analog_name(struct analog *analog)
+{
+	sprintf(analog->name, "Analog %d-axis %d-button", 
+		hweight8(analog->mask & ANALOG_AXES_STD),
+		hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
+		hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
+
+	if (analog->mask & ANALOG_HATS_ALL)
+		sprintf(analog->name, "%s %d-hat",
+			analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
+
+	if (analog->mask & ANALOG_HAT_FCS)
+			strcat(analog->name, " FCS");
+	if (analog->mask & ANALOG_ANY_CHF)
+			strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
+
+	strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
+}
+
+/*
+ * analog_init_device()
+ */
+
+static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
+{
+	int i, j, t, v, w, x, y, z;
+
+	analog_name(analog);
+
+	analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
+
+	analog->dev.name = analog->name;
+	analog->dev.idbus = BUS_GAMEPORT;
+	analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
+	analog->dev.idproduct = analog->mask >> 4;
+	analog->dev.idversion = 0x0100;
+
+	analog->dev.open = analog_open;
+	analog->dev.close = analog_close;
+	analog->dev.private = port;
+	analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	
+	for (i = j = 0; i < 4; i++)
+		if (analog->mask & (1 << i)) {
+			
+			t = analog_axes[j];
+			x = port->axes[i];
+			y = (port->axes[0] + port->axes[1]) >> 1;
+			z = y - port->axes[i];
+			z = z > 0 ? z : -z;
+			v = (x >> 3);
+			w = (x >> 3);
+
+			set_bit(t, analog->dev.absbit);
+
+			if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
+				x = y;
+
+			if (analog->mask & ANALOG_SAITEK) {
+				if (i == 2) x = port->axes[i];
+				v = x - (x >> 2);
+				w = (x >> 4);
+			}
+
+			analog->dev.absmax[t] = (x << 1) - v;
+			analog->dev.absmin[t] = v;
+			analog->dev.absfuzz[t] = port->fuzz;
+			analog->dev.absflat[t] = w;
+
+			j++;
+		}
+
+	for (i = j = 0; i < 3; i++) 
+		if (analog->mask & analog_exts[i]) 
+			for (x = 0; x < 2; x++) {
+				t = analog_hats[j++];
+				set_bit(t, analog->dev.absbit);
+				analog->dev.absmax[t] = 1;
+				analog->dev.absmin[t] = -1;
+			}
+
+	for (i = j = 0; i < 4; i++)
+		if (analog->mask & (0x10 << i))
+			set_bit(analog->buttons[j++], analog->dev.keybit);
+
+	if (analog->mask & ANALOG_BTNS_CHF)
+		for (i = 0; i < 2; i++)
+			set_bit(analog->buttons[j++], analog->dev.keybit);
+
+	if (analog->mask & ANALOG_HBTN_CHF)
+		for (i = 0; i < 4; i++)
+			set_bit(analog->buttons[j++], analog->dev.keybit);
+
+	for (i = 0; i < 4; i++)
+		if (analog->mask & (ANALOG_BTN_TL << i))
+			set_bit(analog_pads[i], analog->dev.keybit);
+
+	analog_decode(analog, port->axes, port->initial, port->buttons);
+
+	input_register_device(&analog->dev);
+
+	printk(KERN_INFO "input%d: %s at gameport%d.%d",
+		analog->dev.number, analog->name, port->gameport->number, index);
+
+	if (port->cooked)
+		printk(" [ADC port]\n");
+	else
+		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
+		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
+		port->speed > 10000 ? "M" : "k",
+		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
+				    : (port->loop * 1000000) / port->speed);
+}
+
+/*
+ * analog_init_devices() sets up device-specific values and registers the input devices.
+ */
+
+static int analog_init_masks(struct analog_port *port)
+{
+	int i;
+	struct analog *analog = port->analog;
+	int max[4];
+
+	if (!port->mask)
+		return -1;
+
+	if ((port->mask & 3) != 3 && port->mask != 0xc) {
+		printk(KERN_WARNING "analog.c: Unknown joystick device found  "
+			"(data=%#x, gameport%d), probably not analog joystick.\n",
+			port->mask, port->gameport->number);
+		return -1;
+	}
+
+	i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
+
+	analog[0].mask = i & 0xfffff;
+
+	analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
+			| port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
+			| ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
+
+	analog[0].mask &= ~(ANALOG_HAT2_CHF)
+			| ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
+
+	analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
+			| ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
+			| ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
+			| ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
+
+	analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
+			| (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
+			&  ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
+
+	analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
+
+	analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
+			: (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
+
+	if (port->cooked) {
+
+		for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
+
+		if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
+		if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
+		if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
+		if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
+		if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
+
+		gameport_calibrate(port->gameport, port->axes, max);
+	}
+		
+	for (i = 0; i < 4; i++) 
+		port->initial[i] = port->axes[i];
+
+	return -!(analog[0].mask || analog[1].mask);	
+}
+
+static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
+{
+	int i, t, u, v;
+
+	gameport->private = port;
+	port->gameport = gameport;
+	init_timer(&port->timer);
+	port->timer.data = (long) port;
+	port->timer.function = analog_timer;
+
+	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+
+		analog_calibrate_timer(port);
+
+		gameport_trigger(gameport);
+		t = gameport_read(gameport);
+		wait_ms(ANALOG_MAX_TIME);
+		port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
+		port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
+	
+		for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
+			if (!analog_cooked_read(port)) break;
+			wait_ms(ANALOG_MAX_TIME);
+		}
+
+		u = v = 0;
+
+		wait_ms(ANALOG_MAX_TIME);
+		t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
+		gameport_trigger(gameport);
+		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++; 
+		udelay(ANALOG_SAITEK_DELAY);
+		t = gameport_time(gameport, ANALOG_SAITEK_TIME);
+		gameport_trigger(gameport);
+		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; 
+
+		if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
+			analog_options[port->gameport->number] |=
+				ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
+			return 0;
+		}
+
+		gameport_close(gameport);
+	}
+
+	if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+
+		for (i = 0; i < ANALOG_INIT_RETRIES; i++)
+			if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
+				break;
+		for (i = 0; i < 4; i++)
+			if (port->axes[i] != -1) port->mask |= 1 << i;
+
+		port->fuzz = gameport->fuzz;
+		port->cooked = 1;
+		return 0;
+	}
+
+	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		return 0;
+
+	return -1;
+}
+
+static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct analog_port *port;
+	int i;
+
+	if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
+		return;
+	memset(port, 0, sizeof(struct analog_port));
+
+	if (analog_init_port(gameport, dev, port)) {
+		kfree(port);
+		return;
+	}
+
+	if (analog_init_masks(port)) {
+		gameport_close(gameport);
+		kfree(port);
+		return;
+	}
+
+	for (i = 0; i < 2; i++)
+		if (port->analog[i].mask)
+			analog_init_device(port, port->analog + i, i);
+}
+
+static void analog_disconnect(struct gameport *gameport)
+{
+	int i;
+
+	struct analog_port *port = gameport->private;
+	for (i = 0; i < 2; i++)
+		if (port->analog[i].mask)
+			input_unregister_device(&port->analog[i].dev);
+	gameport_close(gameport);
+	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
+		port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
+		port->gameport->number);
+	kfree(port);
+}
+
+struct analog_types {
+	char *name;
+	int value;
+};
+
+struct analog_types analog_types[] = {
+	{ "none",	0x00000000 },
+	{ "auto",	0x000000ff },
+	{ "2btn",	0x0000003f },
+	{ "y-joy",	0x0cc00033 },
+	{ "y-pad",	0x8cc80033 },
+	{ "fcs",	0x000008f7 },
+	{ "chf",	0x000002ff },
+	{ "fullchf",	0x000007ff },
+	{ "gamepad",	0x000830f3 },
+	{ "gamepad8",	0x0008f0f3 },
+	{ NULL, 0 }
+};
+
+static void analog_parse_options(void)
+{
+	int i, j;
+	char *end;
+
+	for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
+
+		for (j = 0; analog_types[j].name; j++)
+			if (!strcmp(analog_types[j].name, js[i])) {
+				analog_options[i] = analog_types[j].value;
+				break;
+			} 
+		if (analog_types[j].name) continue;
+
+		analog_options[i] = simple_strtoul(js[i], &end, 0);
+		if (end != js[i]) continue;
+
+		analog_options[i] = 0xff;
+		if (!strlen(js[i])) continue;
+
+		printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
+	}
+
+	for (; i < ANALOG_PORTS; i++)
+		analog_options[i] = 0xff;
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev analog_dev = {
+	connect:	analog_connect,
+	disconnect:	analog_disconnect,
+};
+
+#ifndef MODULE
+static int __init analog_setup(char *str)
+{
+	char *s = str;
+	int i = 0;
+
+	if (!str || !*str) return 0;
+
+	while ((str = s) && (i < ANALOG_PORTS)) {
+		if ((s = strchr(str,','))) *s++ = 0;
+		js[i++] = str;
+	}
+
+	return 1;
+}
+__setup("js=", analog_setup);
+#endif
+
+int __init analog_init(void)
+{
+	analog_parse_options();
+	gameport_register_device(&analog_dev);
+	return 0;
+}
+
+void __exit analog_exit(void)
+{
+	gameport_unregister_device(&analog_dev);
+}
+
+module_init(analog_init);
+module_exit(analog_exit);
diff -Nru a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/cobra.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,252 @@
+/*
+ * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Creative Labd Blaster GamePad Cobra driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
+#define COBRA_REFRESH_TIME	HZ/50	/* 20 ms between reads */
+#define COBRA_LENGTH		36
+
+static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
+
+static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
+
+struct cobra {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct input_dev dev[2];
+	int used;
+	int reads;
+	int bads;
+	unsigned char exists;
+};
+
+static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
+{
+	unsigned long flags;
+	unsigned char u, v, w;
+	__u64 buf[2];
+	int r[2], t[2];
+	int i, j, ret;
+
+	int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
+
+	for (i = 0; i < 2; i++) {
+		r[i] = buf[i] = 0;
+		t[i] = COBRA_MAX_STROBE;
+	}
+	
+	__save_flags(flags);
+	__cli();
+
+	u = gameport_read(gameport);
+
+	do {
+		t[0]--; t[1]--;
+		v = gameport_read(gameport);
+		for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
+			if (w & 0x30) {
+				if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
+					buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
+					t[i] = strobe;
+					u = v;
+				} else t[i] = 0;
+			}
+	} while (t[0] > 0 || t[1] > 0);
+
+	__restore_flags(flags);
+
+	ret = 0;
+
+	for (i = 0; i < 2; i++) {
+
+		if (r[i] != COBRA_LENGTH) continue;
+
+		for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
+			buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
+
+		if (j < COBRA_LENGTH) ret |= (1 << i);
+
+		data[i] = ((buf[i] >>  7) & 0x000001f) | ((buf[i] >>  8) & 0x00003e0)
+			| ((buf[i] >>  9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
+			| ((buf[i] >> 11) & 0x1f00000);
+
+	}
+
+	return ret;
+}
+
+static void cobra_timer(unsigned long private)
+{
+	struct cobra *cobra = (void *) private;
+	struct input_dev *dev;
+	unsigned int data[2];
+	int i, j, r;
+
+	cobra->reads++;
+
+	if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
+		cobra->bads++;
+
+	for (i = 0; i < 2; i++)
+		if (cobra->exists & r & (1 << i)) {
+
+			dev = cobra->dev + i;
+
+			input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
+			input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
+
+			for (j = 0; cobra_btn[j]; j++)
+				input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
+
+		}
+
+	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
+}
+
+static int cobra_open(struct input_dev *dev)
+{
+	struct cobra *cobra = dev->private;
+	if (!cobra->used++)
+		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);	
+	return 0;
+}
+
+static void cobra_close(struct input_dev *dev)
+{
+	struct cobra *cobra = dev->private;
+	if (!--cobra->used)
+		del_timer(&cobra->timer);
+}
+
+static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct cobra *cobra;
+	unsigned int data[2];
+	int i, j;
+
+	if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
+		return;
+	memset(cobra, 0, sizeof(struct cobra));
+
+	gameport->private = cobra;
+
+	cobra->gameport = gameport;
+	init_timer(&cobra->timer);
+	cobra->timer.data = (long) cobra;
+	cobra->timer.function = cobra_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	cobra->exists = cobra_read_packet(gameport, data);
+
+	for (i = 0; i < 2; i++) 
+		if ((cobra->exists >> i) & data[i] & 1) {
+			printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
+				" Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
+			cobra->exists &= ~(1 << i);
+		}
+
+	if (!cobra->exists)
+		goto fail2;
+
+	for (i = 0; i < 2; i++)
+		if ((cobra->exists >> i) & 1) {
+
+			cobra->dev[i].private = cobra;
+			cobra->dev[i].open = cobra_open;
+			cobra->dev[i].close = cobra_close;
+
+			cobra->dev[i].name = cobra_name;
+			cobra->dev[i].idbus = BUS_GAMEPORT;
+			cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
+			cobra->dev[i].idproduct = 0x0008;
+			cobra->dev[i].idversion = 0x0100;
+		
+			cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+			cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+			for (j = 0; cobra_btn[j]; j++)
+				set_bit(cobra_btn[j], cobra->dev[i].keybit);
+
+			cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
+			cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
+
+			input_register_device(cobra->dev + i);
+			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+				cobra->dev[i].number, cobra_name, gameport->number, i);
+		}
+
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:	kfree(cobra);
+}
+
+static void cobra_disconnect(struct gameport *gameport)
+{
+	int i;
+
+	struct cobra *cobra = gameport->private;
+	for (i = 0; i < 2; i++)
+		if ((cobra->exists >> i) & 1)
+			input_unregister_device(cobra->dev + i);
+	gameport_close(gameport);
+	kfree(cobra);
+}
+
+static struct gameport_dev cobra_dev = {
+	connect:	cobra_connect,
+	disconnect:	cobra_disconnect,
+};
+
+int __init cobra_init(void)
+{
+	gameport_register_device(&cobra_dev);
+	return 0;
+}
+
+void __exit cobra_exit(void)
+{
+	gameport_unregister_device(&cobra_dev);
+}
+
+module_init(cobra_init);
+module_exit(cobra_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/db9.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,424 @@
+/*
+ * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $
+ *
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Andree Borrmann		Mats Sjövall
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(db9, "2i");
+MODULE_PARM(db9_2, "2i");
+MODULE_PARM(db9_3, "2i");
+
+#define DB9_MULTI_STICK		0x01
+#define DB9_MULTI2_STICK	0x02
+#define DB9_GENESIS_PAD		0x03
+#define DB9_GENESIS5_PAD	0x05
+#define DB9_GENESIS6_PAD	0x06
+#define DB9_SATURN_PAD		0x07
+#define DB9_MULTI_0802		0x08
+#define DB9_MULTI_0802_2	0x09
+#define DB9_CD32_PAD		0x0A
+#define DB9_MAX_PAD		0x0B
+
+#define DB9_UP			0x01
+#define DB9_DOWN		0x02
+#define DB9_LEFT		0x04
+#define DB9_RIGHT		0x08
+#define DB9_FIRE1		0x10
+#define DB9_FIRE2		0x20
+#define DB9_FIRE3		0x40
+#define DB9_FIRE4		0x80
+
+#define DB9_NORMAL		0x0a
+#define DB9_NOSELECT		0x08
+
+#define DB9_SATURN0		0x00
+#define DB9_SATURN1		0x02
+#define DB9_SATURN2		0x04
+#define DB9_SATURN3		0x06
+
+#define DB9_GENESIS6_DELAY	14
+#define DB9_REFRESH_TIME	HZ/100
+
+static int db9[] __initdata = { -1, 0 };
+static int db9_2[] __initdata = { -1, 0 };
+static int db9_3[] __initdata = { -1, 0 };
+
+struct db9 {
+	struct input_dev dev[2];
+	struct timer_list timer;
+	struct pardevice *pd;	
+	int mode;
+	int used;
+};
+
+static struct db9 *db9_base[3];
+
+static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
+static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
+static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
+
+static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
+static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
+					db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
+static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
+				      NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
+				     "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
+
+static void db9_timer(unsigned long private)
+{
+	struct db9 *db9 = (void *) private;
+	struct parport *port = db9->pd->port;
+	struct input_dev *dev = db9->dev;
+	int data, i;
+
+	switch(db9->mode) {
+		case DB9_MULTI_0802_2:
+
+			data = parport_read_data(port) >> 3;
+
+			input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
+
+		case DB9_MULTI_0802:
+
+			data = parport_read_status(port) >> 3;
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
+			break;
+
+		case DB9_MULTI_STICK:
+
+			data = parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
+			break;
+
+		case DB9_MULTI2_STICK:
+
+			data = parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_THUMB,   ~data & DB9_FIRE2);
+			break;
+
+		case DB9_GENESIS_PAD:
+
+			parport_write_control(port, DB9_NOSELECT);
+			data = parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+			parport_write_control(port, DB9_NORMAL);
+			data=parport_read_data(port);
+
+			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
+			break;
+
+		case DB9_GENESIS5_PAD:
+
+			parport_write_control(port, DB9_NOSELECT);
+			data=parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+			parport_write_control(port, DB9_NORMAL);
+			data=parport_read_data(port);
+
+			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_X,     ~data & DB9_FIRE2);
+			input_report_key(dev, BTN_Y,     ~data & DB9_LEFT);
+			input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
+			break;
+
+		case DB9_GENESIS6_PAD:
+
+			parport_write_control(port, DB9_NOSELECT); /* 1 */
+			udelay(DB9_GENESIS6_DELAY);
+			data=parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+			parport_write_control(port, DB9_NORMAL);
+			udelay(DB9_GENESIS6_DELAY);
+			data=parport_read_data(port);
+
+			input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
+			input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
+
+			parport_write_control(port, DB9_NOSELECT); /* 2 */
+			udelay(DB9_GENESIS6_DELAY);
+			parport_write_control(port, DB9_NORMAL);
+			udelay(DB9_GENESIS6_DELAY);
+			parport_write_control(port, DB9_NOSELECT); /* 3 */
+			udelay(DB9_GENESIS6_DELAY);
+			data=parport_read_data(port);
+
+			input_report_key(dev, BTN_Y,     ~data & DB9_LEFT);
+			input_report_key(dev, BTN_Z,     ~data & DB9_DOWN);
+			input_report_key(dev, BTN_MODE,  ~data & DB9_UP);
+			input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
+
+			parport_write_control(port, DB9_NORMAL);
+			udelay(DB9_GENESIS6_DELAY);
+			parport_write_control(port, DB9_NOSELECT); /* 4 */
+			udelay(DB9_GENESIS6_DELAY);
+			parport_write_control(port, DB9_NORMAL);
+			break;
+
+		case DB9_SATURN_PAD:
+
+			parport_write_control(port, DB9_SATURN0);
+			data = parport_read_data(port);
+
+			input_report_key(dev, BTN_Y,  ~data & DB9_LEFT);
+			input_report_key(dev, BTN_Z,  ~data & DB9_DOWN);
+			input_report_key(dev, BTN_TL, ~data & DB9_UP);
+			input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
+
+			parport_write_control(port, DB9_SATURN2);
+			data = parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+			
+			parport_write_control(port, DB9_NORMAL);
+			data = parport_read_data(port);
+
+			input_report_key(dev, BTN_A, ~data & DB9_LEFT);
+			input_report_key(dev, BTN_B, ~data & DB9_UP);
+			input_report_key(dev, BTN_C, ~data & DB9_DOWN);
+			input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
+			break;
+
+		case DB9_CD32_PAD:
+
+			data=parport_read_data(port);
+
+			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
+
+			parport_write_control(port, 0x0a); 
+
+			for (i = 0; i < 7; i++) { 
+				data = parport_read_data(port);
+				parport_write_control(port, 0x02); 
+				parport_write_control(port, 0x0a); 
+				input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
+				}
+
+			parport_write_control(port, 0x00); 
+			break;
+		}
+
+	mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+}
+
+static int db9_open(struct input_dev *dev)
+{
+	struct db9 *db9 = dev->private;
+	struct parport *port = db9->pd->port;
+
+	if (!db9->used++) {
+		parport_claim(db9->pd);
+		parport_write_data(port, 0xff);
+		parport_data_reverse(port);
+		parport_write_control(port, DB9_NORMAL);
+		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+	}
+
+	return 0;
+}
+
+static void db9_close(struct input_dev *dev)
+{
+	struct db9 *db9 = dev->private;
+	struct parport *port = db9->pd->port;
+
+	if (!--db9->used) {
+		del_timer(&db9->timer);
+		parport_write_control(port, 0x00);
+		parport_data_forward(port);
+		parport_release(db9->pd);
+	}
+}
+
+static struct db9 __init *db9_probe(int *config)
+{
+	struct db9 *db9;
+	struct parport *pp;
+	int i, j;
+
+	if (config[0] < 0)
+		return NULL;
+	if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
+		printk(KERN_ERR "db9.c: bad config\n");
+		return NULL;
+	}
+
+	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+		config[0]--;
+
+	if (!pp) {
+		printk(KERN_ERR "db9.c: no such parport\n");
+		return NULL;
+	}
+
+	if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
+		printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
+		return NULL;
+	}
+	
+	if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
+		return NULL;
+	memset(db9, 0, sizeof(struct db9));
+
+	db9->mode = config[1];
+	init_timer(&db9->timer);
+	db9->timer.data = (long) db9;
+	db9->timer.function = db9_timer;
+
+	db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+	if (!db9->pd) {
+		printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
+		kfree(db9);
+		return NULL;
+	}
+
+	for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
+
+		db9->dev[i].private = db9;
+		db9->dev[i].open = db9_open;
+		db9->dev[i].close = db9_close;
+
+		db9->dev[i].name = db9_name[db9->mode];
+		db9->dev[i].idbus = BUS_PARPORT;
+		db9->dev[i].idvendor = 0x0002;
+		db9->dev[i].idproduct = config[1];
+		db9->dev[i].idversion = 0x0100;
+
+		db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+		db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+		for (j = 0; j < db9_buttons[db9->mode]; j++)
+			set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit); 
+
+		db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
+		db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
+
+		input_register_device(db9->dev + i);
+		printk(KERN_INFO "input%d: %s on %s\n",
+			db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
+	}
+
+	return db9;
+}
+
+#ifndef MODULE
+int __init db9_setup(char *str)
+{
+	int i, ints[3];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
+	return 1;
+}
+int __init db9_setup_2(char *str)
+{
+	int i, ints[3];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
+	return 1;
+}
+int __init db9_setup_3(char *str)
+{
+	int i, ints[3];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
+	return 1;
+}
+__setup("db9=", db9_setup);
+__setup("db9_2=", db9_setup_2);
+__setup("db9_3=", db9_setup_3);
+#endif
+
+int __init db9_init(void)
+{
+	db9_base[0] = db9_probe(db9);
+	db9_base[1] = db9_probe(db9_2);
+	db9_base[2] = db9_probe(db9_3);
+
+	if (db9_base[0] || db9_base[1] || db9_base[2])
+		return 0;
+
+	return -ENODEV;
+}
+
+void __exit db9_exit(void)
+{
+	int i, j;
+
+	for (i = 0; i < 3; i++) 
+		if (db9_base[i]) {
+			for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
+				input_unregister_device(db9_base[i]->dev + j);
+		parport_unregister_device(db9_base[i]->pd);
+	}
+}
+
+module_init(db9_init);
+module_exit(db9_exit);
diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/gamecon.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,670 @@
+/*
+ * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *  	Andree Borrmann		John Dahlstrom
+ *  	David Kuder		Nathan Hand
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(gc, "2-6i");
+MODULE_PARM(gc_2,"2-6i");
+MODULE_PARM(gc_3,"2-6i");
+
+#define GC_SNES		1
+#define GC_NES		2
+#define GC_NES4		3
+#define GC_MULTI	4
+#define GC_MULTI2	5
+#define GC_N64		6	
+#define GC_PSX		7
+
+#define GC_MAX		7
+
+#define GC_REFRESH_TIME	HZ/100
+ 
+struct gc {
+	struct pardevice *pd;
+	struct input_dev dev[5];
+	struct timer_list timer;
+	unsigned char pads[GC_MAX + 1];
+	int used;
+};
+
+static struct gc *gc_base[3];
+
+static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
+
+static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+				"Multisystem 2-button joystick", "N64 controller", "PSX controller" };
+/*
+ * N64 support.
+ */
+
+static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+
+#define GC_N64_LENGTH		32		/* N64 bit length, not including stop bit */
+#define GC_N64_REQUEST_LENGTH	37		/* transmit request sequence is 9 bits long */
+#define GC_N64_DELAY		133		/* delay between transmit request, and response ready (us) */
+#define GC_N64_REQUEST		0x1dd1111111ULL /* the request data command (encoded for 000000011) */
+#define GC_N64_DWS		3		/* delay between write segments (required for sound playback because of ISA DMA) */
+						/* GC_N64_DWS > 24 is known to fail */ 
+#define GC_N64_POWER_W		0xe2		/* power during write (transmit request) */
+#define GC_N64_POWER_R		0xfd		/* power during read */
+#define GC_N64_OUT		0x1d		/* output bits to the 4 pads */
+						/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
+						/* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
+						/* than 123 us */
+#define GC_N64_CLOCK		0x02		/* clock bits for read */
+
+/* 
+ * gc_n64_read_packet() reads an N64 packet. 
+ * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ */
+
+static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
+{
+	int i;
+	unsigned long flags;
+
+/*
+ * Request the pad to transmit data
+ */
+
+	__save_flags(flags);
+	__cli();
+	for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
+		parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
+		udelay(GC_N64_DWS);
+	}
+	__restore_flags(flags);
+
+/*
+ * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ */
+
+	udelay(GC_N64_DELAY);
+
+/*
+ * Grab data (ignoring the last bit, which is a stop bit)
+ */
+
+	for (i = 0; i < GC_N64_LENGTH; i++) {
+		parport_write_data(gc->pd->port, GC_N64_POWER_R);
+		data[i] = parport_read_status(gc->pd->port);
+		parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
+	 }
+
+/*
+ * We must wait 200 ms here for the controller to reinitialize before the next read request.
+ * No worries as long as gc_read is polled less frequently than this.
+ */
+
+}
+
+/*
+ * NES/SNES support.
+ */
+
+#define GC_NES_DELAY	6	/* Delay between bits - 6us */
+#define GC_NES_LENGTH	8	/* The NES pads use 8 bits of data */
+#define GC_SNES_LENGTH	12	/* The SNES true length is 16, but the last 4 bits are unused */
+
+#define GC_NES_POWER	0xfc
+#define GC_NES_CLOCK	0x01
+#define GC_NES_LATCH	0x02
+
+static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+
+/*
+ * gc_nes_read_packet() reads a NES/SNES packet.
+ * Each pad uses one bit per byte. So all pads connected to
+ * this port are read in parallel.
+ */
+
+static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+	int i;
+
+	parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
+	udelay(GC_NES_DELAY * 2);
+	parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+
+	for (i = 0; i < length; i++) {
+		udelay(GC_NES_DELAY);
+		parport_write_data(gc->pd->port, GC_NES_POWER);
+		data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+		udelay(GC_NES_DELAY);
+		parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+	}
+}
+
+/*
+ * Multisystem joystick support
+ */
+
+#define GC_MULTI_LENGTH		5	/* Multi system joystick packet length is 5 */
+#define GC_MULTI2_LENGTH	6	/* One more bit for one more button */
+
+/*
+ * gc_multi_read_packet() reads a Multisystem joystick packet.
+ */
+
+static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+	int i;
+
+	for (i = 0; i < length; i++) {
+		parport_write_data(gc->pd->port, ~(1 << i));
+		data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+	}
+}
+
+/*
+ * PSX support
+ *
+ * See documentation at:
+ *	http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
+ *	http://www.gamesx.com/controldata/psxcont/psxcont.htm
+ *	ftp://milano.usal.es/pablo/
+ *	
+ */
+
+#define GC_PSX_DELAY	60		/* 60 usec */
+#define GC_PSX_LENGTH	8		/* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE	1		/* Mouse */
+#define GC_PSX_NEGCON	2		/* NegCon */
+#define GC_PSX_NORMAL	4		/* Digital / Analog or Rumble in Digital mode  */
+#define GC_PSX_ANALOG	5		/* Analog in Analog mode / Rumble in Green mode */
+#define GC_PSX_RUMBLE	7		/* Rumble in Red mode */
+
+#define GC_PSX_CLOCK	0x04		/* Pin 4 */
+#define GC_PSX_COMMAND	0x01		/* Pin 1 */
+#define GC_PSX_POWER	0xf8		/* Pins 5-9 */
+#define GC_PSX_SELECT	0x02		/* Pin 3 */
+
+#define GC_PSX_ID(x)	((x) >> 4)	/* High nibble is device type */
+#define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
+
+static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
+static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+				BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
+
+/*
+ * gc_psx_command() writes 8bit command and reads 8bit data from
+ * the psx pad.
+ */
+
+static int gc_psx_command(struct gc *gc, int b)
+{
+	int i, cmd, data = 0;
+
+	for (i = 0; i < 8; i++, b >>= 1) {
+		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+		parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+		udelay(GC_PSX_DELAY);
+		data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
+		parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
+		udelay(GC_PSX_DELAY);
+	}
+	return data;
+}
+
+/*
+ * gc_psx_read_packet() reads a whole psx packet and returns
+ * device identifier code.
+ */
+
+static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
+{
+	int i, id;
+	unsigned long flags;
+
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);	/* Select pad */
+	udelay(GC_PSX_DELAY * 2);
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);			/* Deselect, begin command */
+	udelay(GC_PSX_DELAY * 2);
+
+	__save_flags(flags);
+	__cli();
+
+	gc_psx_command(gc, 0x01);							/* Access pad */
+	id = gc_psx_command(gc, 0x42);							/* Get device id */
+	if (gc_psx_command(gc, 0) == 0x5a) {						/* Okay? */
+		for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
+			data[i] = gc_psx_command(gc, 0);
+	} else id = 0;
+
+	__restore_flags(flags);
+
+	parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
+
+	return GC_PSX_ID(id);
+}
+
+/*
+ * gc_timer() reads and analyzes console pads data.
+ */
+
+#define GC_MAX_LENGTH GC_N64_LENGTH
+
+static void gc_timer(unsigned long private)
+{
+	struct gc *gc = (void *) private;
+	struct input_dev *dev = gc->dev;
+	unsigned char data[GC_MAX_LENGTH];
+	int i, j, s;
+
+/*
+ * N64 pads - must be read first, any read confuses them for 200 us
+ */
+
+	if (gc->pads[GC_N64]) {
+
+		gc_n64_read_packet(gc, data);
+
+		for (i = 0; i < 5; i++) {
+
+			s = gc_status_bit[i];
+
+			if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+	
+				signed char axes[2];
+				axes[0] = axes[1] = 0;
+
+				for (j = 0; j < 8; j++) {
+					if (data[23 - j] & s) axes[0] |= 1 << j; 
+					if (data[31 - j] & s) axes[1] |= 1 << j; 
+				}
+
+				input_report_abs(dev + i, ABS_X,  axes[0]);
+				input_report_abs(dev + i, ABS_Y, -axes[1]);
+
+				input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
+				input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
+
+				for (j = 0; j < 10; j++)
+					input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+			}
+		}
+	}
+
+/*
+ * NES and SNES pads
+ */
+
+	if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
+
+		gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
+
+		for (i = 0; i < 5; i++) {
+
+			s = gc_status_bit[i];
+
+			if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+				input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
+				input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
+			}
+
+			if (s & gc->pads[GC_NES])
+				for (j = 0; j < 4; j++)
+					input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+
+			if (s & gc->pads[GC_SNES])
+				for (j = 0; j < 8; j++)
+					input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+		}
+	}
+
+/*
+ * Multi and Multi2 joysticks
+ */
+
+	if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
+
+		gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+
+		for (i = 0; i < 5; i++) {
+
+			s = gc_status_bit[i];
+
+			if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
+				input_report_abs(dev + i, ABS_X,  !(s & data[2]) - !(s & data[3]));
+				input_report_abs(dev + i, ABS_Y,  !(s & data[0]) - !(s & data[1]));
+				input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
+			}
+
+			if (s & gc->pads[GC_MULTI2])
+				input_report_key(dev + i, BTN_THUMB, s & data[5]);
+		}
+	}
+
+/*
+ * PSX controllers
+ */
+
+	if (gc->pads[GC_PSX]) {
+
+		for (i = 0; i < 5; i++)
+	       		if (gc->pads[GC_PSX] & gc_status_bit[i])
+				break;
+
+ 		switch (gc_psx_read_packet(gc, data)) {
+
+			case GC_PSX_RUMBLE:
+
+				input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
+				input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+			case GC_PSX_NEGCON:
+			case GC_PSX_ANALOG:
+
+				for (j = 0; j < 4; j++)
+					input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
+
+				input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
+				input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
+
+				for (j = 0; j < 8; j++)
+					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
+
+				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
+				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+				break;
+
+			case GC_PSX_NORMAL:
+
+				input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
+				input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
+
+				for (j = 0; j < 8; j++)
+					input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
+
+				input_report_key(dev + i, BTN_START,  ~data[0] & 0x08);
+				input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+				break;
+		}
+	}
+
+	mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+}
+
+static int gc_open(struct input_dev *dev)
+{
+	struct gc *gc = dev->private;
+	if (!gc->used++) {
+		parport_claim(gc->pd);
+		parport_write_control(gc->pd->port, 0x04);
+		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+	}
+	return 0;
+}
+
+static void gc_close(struct input_dev *dev)
+{
+	struct gc *gc = dev->private;
+	if (!--gc->used) {
+		del_timer(&gc->timer);
+		parport_write_control(gc->pd->port, 0x00);
+		parport_release(gc->pd);
+	}
+}
+
+static struct gc __init *gc_probe(int *config)
+{
+	struct gc *gc;
+	struct parport *pp;
+	int i, j, psx;
+	unsigned char data[32];
+
+	if (config[0] < 0)
+		return NULL;
+
+	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+		config[0]--;
+
+	if (!pp) {
+		printk(KERN_ERR "gamecon.c: no such parport\n");
+		return NULL;
+	}
+
+	if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
+		return NULL;
+	memset(gc, 0, sizeof(struct gc));
+
+	gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+	if (!gc->pd) {
+		printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+		kfree(gc);
+		return NULL;
+	}
+
+	parport_claim(gc->pd);
+
+	init_timer(&gc->timer);
+	gc->timer.data = (long) gc;
+	gc->timer.function = gc_timer;
+
+	for (i = 0; i < 5; i++) {
+
+		if (!config[i + 1])
+			continue;
+
+		if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
+			printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
+			continue;
+		}
+
+                gc->dev[i].private = gc;
+                gc->dev[i].open = gc_open;
+                gc->dev[i].close = gc_close;
+
+                gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+		for (j = 0; j < 2; j++) {
+			set_bit(ABS_X + j, gc->dev[i].absbit);
+			gc->dev[i].absmin[ABS_X + j] = -1;
+			gc->dev[i].absmax[ABS_X + j] =  1;
+		}
+
+		gc->pads[0] |= gc_status_bit[i];
+		gc->pads[config[i + 1]] |= gc_status_bit[i];
+
+		switch(config[i + 1]) {
+
+			case GC_N64:
+				for (j = 0; j < 10; j++)
+					set_bit(gc_n64_btn[j], gc->dev[i].keybit);
+
+				for (j = 0; j < 2; j++) {
+					set_bit(ABS_X + j, gc->dev[i].absbit);
+					gc->dev[i].absmin[ABS_X + j] = -127;
+					gc->dev[i].absmax[ABS_X + j] =  126;
+					gc->dev[i].absflat[ABS_X + j] = 2;
+					set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
+					gc->dev[i].absmin[ABS_HAT0X + j] = -1;
+					gc->dev[i].absmax[ABS_HAT0X + j] =  1;
+				}
+
+				break;
+
+			case GC_SNES:
+				for (j = 4; j < 8; j++)
+					set_bit(gc_snes_btn[j], gc->dev[i].keybit);
+			case GC_NES:
+				for (j = 0; j < 4; j++)
+					set_bit(gc_snes_btn[j], gc->dev[i].keybit);
+				break;
+
+			case GC_MULTI2:
+				set_bit(BTN_THUMB, gc->dev[i].keybit);
+			case GC_MULTI:
+				set_bit(BTN_TRIGGER, gc->dev[i].keybit);
+				break;
+
+			case GC_PSX:
+				
+				psx = gc_psx_read_packet(gc, data);
+
+				switch(psx) {
+					case GC_PSX_NEGCON:
+					case GC_PSX_NORMAL:
+					case GC_PSX_ANALOG:
+					case GC_PSX_RUMBLE:
+
+						for (j = 0; j < 6; j++) {
+							psx = gc_psx_abs[j];
+							set_bit(psx, gc->dev[i].absbit);
+							if (j < 4) {
+								gc->dev[i].absmin[psx] = 4;
+								gc->dev[i].absmax[psx] = 252;
+								gc->dev[i].absflat[psx] = 2;
+							} else {
+								gc->dev[i].absmin[psx] = -1;
+								gc->dev[i].absmax[psx] = 1;
+							}
+						}
+
+						for (j = 0; j < 12; j++)
+							set_bit(gc_psx_btn[j], gc->dev[i].keybit);
+
+						break;
+
+					case 0:
+						gc->pads[GC_PSX] &= ~gc_status_bit[i];
+						printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
+						break;
+
+					default:
+						gc->pads[GC_PSX] &= ~gc_status_bit[i];
+						printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
+							" please report to <vojtech@suse.cz>.\n", psx);
+				}
+				break;
+		}
+
+                gc->dev[i].name = gc_names[config[i + 1]];
+                gc->dev[i].idbus = BUS_PARPORT;
+                gc->dev[i].idvendor = 0x0001;
+                gc->dev[i].idproduct = config[i + 1];
+                gc->dev[i].idversion = 0x0100;
+	}
+
+	parport_release(gc->pd);
+
+	if (!gc->pads[0]) {
+		parport_unregister_device(gc->pd);
+		kfree(gc);
+		return NULL;
+	}
+
+	for (i = 0; i < 5; i++) 
+		if (gc->pads[0] & gc_status_bit[i]) {
+			input_register_device(gc->dev + i);
+			printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
+		}
+
+	return gc;
+}
+
+#ifndef MODULE
+int __init gc_setup(char *str)
+{
+	int i, ints[7];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
+	return 1;
+}
+int __init gc_setup_2(char *str)
+{
+	int i, ints[7];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
+	return 1;
+}
+int __init gc_setup_3(char *str)
+{
+	int i, ints[7];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
+	return 1;
+}
+__setup("gc=", gc_setup);
+__setup("gc_2=", gc_setup_2);
+__setup("gc_3=", gc_setup_3);
+#endif
+
+int __init gc_init(void)
+{
+	gc_base[0] = gc_probe(gc);
+	gc_base[1] = gc_probe(gc_2);
+	gc_base[2] = gc_probe(gc_3);
+
+	if (gc_base[0] || gc_base[1] || gc_base[2])
+		return 0;
+
+	return -ENODEV;
+}
+
+void __exit gc_exit(void)
+{
+	int i, j;
+
+	for (i = 0; i < 3; i++)
+		if (gc_base[i]) {
+			for (j = 0; j < 5; j++)
+				if (gc_base[i]->pads[0] & gc_status_bit[j])
+					input_unregister_device(gc_base[i]->dev + j); 
+			parport_unregister_device(gc_base[i]->pd);
+		}
+}
+
+module_init(gc_init);
+module_exit(gc_exit);
diff -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/gf2k.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,361 @@
+/*
+ * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Genius Flight 2000 joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+#define GF2K_START		400	/* The time we wait for the first bit [400 us] */
+#define GF2K_STROBE		40	/* The time we wait for the first bit [40 us] */
+#define GF2K_TIMEOUT		4	/* Wait for everything to settle [4 ms] */
+#define GF2K_LENGTH		80	/* Max number of triplets in a packet */
+#define GF2K_REFRESH		HZ/50	/* Time between joystick polls [20 ms] */
+
+/*
+ * Genius joystick ids ...
+ */
+
+#define GF2K_ID_G09		1
+#define GF2K_ID_F30D		2
+#define GF2K_ID_F30		3
+#define GF2K_ID_F31D		4
+#define GF2K_ID_F305		5
+#define GF2K_ID_F23P		6
+#define GF2K_ID_F31		7
+#define GF2K_ID_MAX		7
+
+static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
+static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
+				"Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
+static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
+static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
+static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
+static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
+static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
+
+static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
+static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
+static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
+
+
+static short gf2k_seq_reset[] = { 240, 340, 0 };
+static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
+
+struct gf2k {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct input_dev dev;
+	int reads;
+	int bads;
+	int used;
+	unsigned char id;
+	unsigned char length;
+};
+
+/*
+ * gf2k_read_packet() reads a Genius Flight2000 packet.
+ */
+
+static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
+{
+	unsigned char u, v;
+	int i;
+	unsigned int t, p;
+	unsigned long flags;
+
+	t = gameport_time(gameport, GF2K_START);
+	p = gameport_time(gameport, GF2K_STROBE);
+
+	i = 0;
+
+	__save_flags(flags);
+	__cli();
+
+	gameport_trigger(gameport);
+	v = gameport_read(gameport);;
+
+	while (t > 0 && i < length) {
+		t--; u = v;
+		v = gameport_read(gameport);
+		if (v & ~u & 0x10) {
+			data[i++] = v >> 5;
+			t = p;
+		}
+	}
+
+	__restore_flags(flags);
+
+	return i;
+}
+
+/*
+ * gf2k_trigger_seq() initializes a Genius Flight2000 joystick
+ * into digital mode.
+ */
+
+static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
+{
+
+	unsigned long flags;
+	int i, t;
+
+        __save_flags(flags);
+        __cli();
+
+	i = 0;
+        do {
+		gameport_trigger(gameport);
+		t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
+		while ((gameport_read(gameport) & 1) && t) t--;
+                udelay(seq[i]);
+        } while (seq[++i]);
+
+	gameport_trigger(gameport);
+
+	__restore_flags(flags);
+}
+
+/*
+ * js_sw_get_bits() composes bits from the triplet buffer into a __u64.
+ * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
+ * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
+ * is number of bits per triplet.
+ */
+
+#define GB(p,n,s)	gf2k_get_bits(data, p, n, s)
+
+static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
+{
+	__u64 data = 0;
+	int i;
+
+	for (i = 0; i < num / 3 + 2; i++)
+		data |= buf[pos / 3 + i] << (i * 3);
+	data >>= pos % 3;
+	data &= (1 << num) - 1;
+	data <<= shift;
+
+	return data;
+}
+
+static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
+{
+	struct input_dev *dev = &gf2k->dev;
+	int i, t;
+
+	for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
+		input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
+
+	for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
+		input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
+
+	t = GB(40,4,0);
+
+	for (i = 0; i < gf2k_hats[gf2k->id]; i++)
+		input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
+
+	t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
+
+	for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+		input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
+
+	for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+		input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
+}
+
+/*
+ * gf2k_timer() reads and analyzes Genius joystick data.
+ */
+
+static void gf2k_timer(unsigned long private)
+{
+	struct gf2k *gf2k = (void *) private;
+	unsigned char data[GF2K_LENGTH];
+
+	gf2k->reads++;
+
+	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
+		gf2k->bads++;
+	} else gf2k_read(gf2k, data);
+
+	mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+}
+
+static int gf2k_open(struct input_dev *dev)
+{
+	struct gf2k *gf2k = dev->private;
+	if (!gf2k->used++)
+		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);	
+	return 0;
+}
+
+static void gf2k_close(struct input_dev *dev)
+{
+	struct gf2k *gf2k = dev->private;
+	if (!--gf2k->used)
+		del_timer(&gf2k->timer);
+}
+
+/*
+ * gf2k_connect() probes for Genius id joysticks.
+ */
+
+static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct gf2k *gf2k;
+	unsigned char data[GF2K_LENGTH];
+	int i;
+
+	if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
+		return;
+	memset(gf2k, 0, sizeof(struct gf2k));
+
+	gameport->private = gf2k;
+
+	gf2k->gameport = gameport;
+	init_timer(&gf2k->timer);
+	gf2k->timer.data = (long) gf2k;
+	gf2k->timer.function = gf2k_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	gf2k_trigger_seq(gameport, gf2k_seq_reset);
+
+	wait_ms(GF2K_TIMEOUT);
+
+	gf2k_trigger_seq(gameport, gf2k_seq_digital);
+
+	wait_ms(GF2K_TIMEOUT);
+
+	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
+		goto fail2;
+
+	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
+		goto fail2;
+
+#ifdef RESET_WORKS
+	if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
+	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
+		goto fail2;
+#else
+	gf2k->id = 6;
+#endif
+
+	if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
+		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
+			gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+		goto fail2;
+	}
+
+	gf2k->length = gf2k_lens[gf2k->id];
+
+	gf2k->dev.private = gf2k;
+	gf2k->dev.open = gf2k_open;
+	gf2k->dev.close = gf2k_close;
+	gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	gf2k->dev.name = gf2k_names[gf2k->id];
+	gf2k->dev.idbus = BUS_GAMEPORT;
+	gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
+	gf2k->dev.idproduct = gf2k->id;
+	gf2k->dev.idversion = 0x0100;
+
+	for (i = 0; i < gf2k_axes[gf2k->id]; i++)
+		set_bit(gf2k_abs[i], gf2k->dev.absbit);
+
+	for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
+		set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
+		gf2k->dev.absmin[ABS_HAT0X + i] = -1;
+		gf2k->dev.absmax[ABS_HAT0X + i] = 1;
+	}
+
+	for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+		set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
+
+	for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+		set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
+
+	gf2k_read_packet(gameport, gf2k->length, data);
+	gf2k_read(gf2k, data);
+
+	for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
+		gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
+	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32; 
+		gf2k->dev.absmin[gf2k_abs[i]] = 32;
+		gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
+		gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
+	}
+
+	input_register_device(&gf2k->dev);
+	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+		gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:	kfree(gf2k);
+}
+
+static void gf2k_disconnect(struct gameport *gameport)
+{
+	struct gf2k *gf2k = gameport->private;
+	input_unregister_device(&gf2k->dev);
+	gameport_close(gameport);
+	kfree(gf2k);
+}
+
+static struct gameport_dev gf2k_dev = {
+	connect:	gf2k_connect,
+	disconnect:	gf2k_disconnect,
+};
+
+int __init gf2k_init(void)
+{
+	gameport_register_device(&gf2k_dev);
+	return 0;
+}
+
+void __exit gf2k_exit(void)
+{
+	gameport_unregister_device(&gf2k_dev);
+}
+
+module_init(gf2k_init);
+module_exit(gf2k_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/grip.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,425 @@
+/*
+ * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define GRIP_MODE_GPP		1
+#define GRIP_MODE_BD		2
+#define GRIP_MODE_XT		3
+#define GRIP_MODE_DC		4
+
+#define GRIP_LENGTH_GPP		24
+#define GRIP_STROBE_GPP		200	/* 200 us */
+#define GRIP_LENGTH_XT		4
+#define GRIP_STROBE_XT		64	/* 64 us */
+#define GRIP_MAX_CHUNKS_XT	10	
+#define GRIP_MAX_BITS_XT	30	
+
+#define GRIP_REFRESH_TIME	HZ/50	/* 20 ms */
+
+struct grip {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct input_dev dev[2];
+	unsigned char mode[2];
+	int used;
+	int reads;
+	int bads;
+};
+
+static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
+static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
+static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
+static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
+
+static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
+static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
+static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+
+static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
+				"Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
+static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
+static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
+static char grip_anx[] = { 0, 0, 3, 5, 5 };
+static char grip_cen[] = { 0, 0, 2, 2, 4 };
+
+/*
+ * grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
+ */
+
+static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+	unsigned long flags;
+	unsigned char u, v;
+	unsigned int t;
+	int i;
+
+	int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
+
+	data[0] = 0;
+	t = strobe;
+	i = 0;
+
+	__save_flags(flags);
+	__cli();
+
+	v = gameport_read(gameport) >> shift;
+
+	do {
+		t--;
+		u = v; v = (gameport_read(gameport) >> shift) & 3;
+		if (~v & u & 1) {
+			data[0] |= (v >> 1) << i++;
+			t = strobe;
+		}
+	} while (i < GRIP_LENGTH_GPP && t > 0);
+
+	__restore_flags(flags);
+
+	if (i < GRIP_LENGTH_GPP) return -1;
+
+	for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
+		data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
+
+	return -(i == GRIP_LENGTH_GPP);
+}
+
+/*
+ * grip_xt_read_packet() reads a Gravis Xterminator packet.
+ */
+
+static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+	unsigned int i, j, buf, crc;
+	unsigned char u, v, w;
+	unsigned long flags;
+	unsigned int t;
+	char status;
+
+	int strobe = gameport_time(gameport, GRIP_STROBE_XT);
+
+	data[0] = data[1] = data[2] = data[3] = 0;
+	status = buf = i = j = 0;
+	t = strobe;
+
+	__save_flags(flags);
+	__cli();
+
+	v = w = (gameport_read(gameport) >> shift) & 3;
+
+	do {
+		t--;
+		u = (gameport_read(gameport) >> shift) & 3;
+
+		if (u ^ v) {
+
+			if ((u ^ v) & 1) {
+				buf = (buf << 1) | (u >> 1);
+				t = strobe;
+				i++;
+			} else 
+
+			if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
+				if (i == 20) {
+					crc = buf ^ (buf >> 7) ^ (buf >> 14);
+					if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
+						data[buf >> 18] = buf >> 4;
+						status |= 1 << (buf >> 18);
+					}
+					j++;
+				}
+				t = strobe;
+				buf = 0;
+				i = 0;
+			}
+			w = v;
+			v = u;
+		}
+
+	} while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
+
+	__restore_flags(flags);
+
+	return -(status != 0xf);
+}
+
+/*
+ * grip_timer() repeatedly polls the joysticks and generates events.
+ */
+
+static void grip_timer(unsigned long private)
+{
+	struct grip *grip = (void*) private;
+	unsigned int data[GRIP_LENGTH_XT];
+	struct input_dev *dev;
+	int i, j;
+
+	for (i = 0; i < 2; i++) {
+
+		dev = grip->dev + i;
+		grip->reads++;
+
+		switch (grip->mode[i]) {
+
+			case GRIP_MODE_GPP:
+
+				if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
+					grip->bads++;
+					break;
+				}
+
+				input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
+				input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
+
+				for (j = 0; j < 12; j++)
+					if (grip_btn_gpp[j])
+						input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
+
+				break;
+
+			case GRIP_MODE_BD:
+
+				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+					grip->bads++;
+					break;
+				}
+
+				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
+				input_report_abs(dev, ABS_Y,  63 - ((data[0] >> 8) & 0x3f));
+				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
+				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+				for (j = 0; j < 5; j++)
+					input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
+
+				break;
+
+			case GRIP_MODE_XT:
+
+				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+					grip->bads++;
+					break;
+				}
+
+				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
+				input_report_abs(dev, ABS_Y,  63 - ((data[0] >> 8) & 0x3f));
+				input_report_abs(dev, ABS_BRAKE,    (data[1] >> 2) & 0x3f);
+				input_report_abs(dev, ABS_GAS,	    (data[1] >> 8) & 0x3f);
+				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
+				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+				input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
+				input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
+
+				for (j = 0; j < 11; j++)
+					input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
+				break;
+
+			case GRIP_MODE_DC:
+
+				if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+					grip->bads++;
+					break;
+				}
+
+				input_report_abs(dev, ABS_X,        (data[0] >> 2) & 0x3f);
+				input_report_abs(dev, ABS_Y,        (data[0] >> 8) & 0x3f);
+				input_report_abs(dev, ABS_RX,       (data[1] >> 2) & 0x3f);
+				input_report_abs(dev, ABS_RY,	    (data[1] >> 8) & 0x3f);
+				input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+				input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2]       & 1));
+				input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+				for (j = 0; j < 9; j++)
+					input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
+				break;
+
+
+		}
+	}
+
+	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+}
+
+static int grip_open(struct input_dev *dev)
+{
+	struct grip *grip = dev->private;
+	if (!grip->used++)
+		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+	return 0;
+}
+
+static void grip_close(struct input_dev *dev)
+{
+	struct grip *grip = dev->private;
+	if (!--grip->used)
+		del_timer(&grip->timer);
+}
+
+static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct grip *grip;
+	unsigned int data[GRIP_LENGTH_XT];
+	int i, j, t;
+
+	if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
+		return;
+	memset(grip, 0, sizeof(struct grip));
+
+	gameport->private = grip;
+
+	grip->gameport = gameport;
+	init_timer(&grip->timer);
+	grip->timer.data = (long) grip;
+	grip->timer.function = grip_timer;
+
+	 if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	for (i = 0; i < 2; i++) {
+		if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
+			grip->mode[i] = GRIP_MODE_GPP;
+			continue;
+		}
+		if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
+			if (!(data[3] & 7)) {
+				grip->mode[i] = GRIP_MODE_BD;
+				continue;
+			}
+			if (!(data[2] & 0xf0)) {
+				grip->mode[i] = GRIP_MODE_XT;
+				continue;
+			}
+			grip->mode[i] = GRIP_MODE_DC;
+			continue;
+		}
+	}
+
+	if (!grip->mode[0] && !grip->mode[1])
+		goto fail2;
+
+	for (i = 0; i < 2; i++)
+		if (grip->mode[i]) {
+
+			grip->dev[i].private = grip;
+
+			grip->dev[i].open = grip_open;
+			grip->dev[i].close = grip_close;
+
+			grip->dev[i].name = grip_name[grip->mode[i]];
+			grip->dev[i].idbus = BUS_GAMEPORT;
+			grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
+			grip->dev[i].idproduct = grip->mode[i];
+			grip->dev[i].idversion = 0x0100;
+
+			grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+			for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
+
+				set_bit(t, grip->dev[i].absbit);
+
+				if (j < grip_cen[grip->mode[i]]) {
+					grip->dev[i].absmin[t] = 14;
+					grip->dev[i].absmax[t] = 52;
+					grip->dev[i].absfuzz[t] = 1;
+					grip->dev[i].absflat[t] = 2;
+					continue;
+				}
+
+				if (j < grip_anx[grip->mode[i]]) {
+					grip->dev[i].absmin[t] = 3;
+					grip->dev[i].absmax[t] = 57;
+					grip->dev[i].absfuzz[t] = 1;
+					continue;
+				}
+
+				grip->dev[i].absmin[t] = -1;
+				grip->dev[i].absmax[t] = 1;
+			}
+
+			for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
+				if (t > 0)
+					set_bit(t, grip->dev[i].keybit);
+
+			input_register_device(grip->dev + i);
+
+			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+				grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
+		}
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:	kfree(grip);
+}
+
+static void grip_disconnect(struct gameport *gameport)
+{
+	int i;
+
+	struct grip *grip = gameport->private;
+	for (i = 0; i < 2; i++)
+		if (grip->mode[i])
+			input_unregister_device(grip->dev + i);
+	gameport_close(gameport);
+	kfree(grip);
+}
+
+static struct gameport_dev grip_dev = {
+	connect:	grip_connect,
+	disconnect:	grip_disconnect,
+};
+
+int __init grip_init(void)
+{
+	gameport_register_device(&grip_dev);
+	return 0;
+}
+
+void __exit grip_exit(void)
+{
+	gameport_unregister_device(&grip_dev);
+}
+
+module_init(grip_init);
+module_exit(grip_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/iforce.c b/drivers/input/joystick/iforce.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,1224 @@
+/*
+ * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/serio.h>
+#include <linux/config.h>
+
+/* FF: This module provides arbitrary resource management routines.
+ * I use it to manage the device's memory.
+ * Despite the name of this module, I am *not* going to access the ioports.
+ */
+#include <linux/ioport.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
+
+#define IFORCE_MAX_LENGTH	16
+
+#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE)
+#define IFORCE_232	1
+#endif
+#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE)
+#define IFORCE_USB	2
+#endif
+
+#define FF_EFFECTS_MAX	32
+
+/* Each force feedback effect is made of one core effect, which can be
+ * associated to at most to effect modifiers
+ */
+#define FF_MOD1_IS_USED		0
+#define FF_MOD2_IS_USED		1
+#define FF_CORE_IS_USED		2
+#define FF_CORE_IS_PLAYED	3
+#define FF_MODCORE_MAX		3
+
+struct iforce_core_effect {
+	/* Information about where modifiers are stored in the device's memory */
+	struct resource mod1_chunk;
+	struct resource mod2_chunk;
+	unsigned long flags[NBITS(FF_MODCORE_MAX)];
+};
+
+#define FF_CMD_EFFECT		0x010e
+#define FF_CMD_SHAPE		0x0208
+#define FF_CMD_MAGNITUDE	0x0303
+#define FF_CMD_PERIOD		0x0407
+#define FF_CMD_INTERACT		0x050a
+
+#define FF_CMD_AUTOCENTER	0x4002
+#define FF_CMD_PLAY		0x4103
+#define FF_CMD_ENABLE		0x4201
+#define FF_CMD_GAIN		0x4301
+
+#define FF_CMD_QUERY		0xff01
+
+static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
+	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
+static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
+	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
+static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
+	FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
+
+static struct iforce_device {
+	u16 idvendor;
+	u16 idproduct;
+	char *name;
+	signed short *btn;
+	signed short *abs;
+	signed short *ff;
+} iforce_device[] = {
+	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },
+	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },
+	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
+	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
+};
+
+struct iforce {
+	struct input_dev dev;		/* Input device interface */
+	struct iforce_device *type;
+	char name[64];
+	int open;
+	int bus;
+
+	unsigned char data[IFORCE_MAX_LENGTH];
+	unsigned char edata[IFORCE_MAX_LENGTH];
+	u16 ecmd;
+	u16 expect_packet;
+
+#ifdef IFORCE_232
+	struct serio *serio;		/* RS232 transfer */
+	int idx, pkt, len, id;
+	unsigned char csum;
+#endif
+#ifdef IFORCE_USB
+	struct usb_device *usbdev;	/* USB transfer */
+	struct urb *irq, *out, *ctrl;
+	struct usb_ctrlrequest dr;
+#endif
+					/* Force Feedback */
+	wait_queue_head_t wait;
+	struct resource device_memory;
+	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
+};
+
+static struct {
+	__s32 x;
+	__s32 y;
+} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+/* Encode a time value */
+#define TIME_SCALE(a)	((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
+
+static void dump_packet(char *msg, u16 cmd, unsigned char *data)
+{
+	int i;
+
+	printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
+	for (i = 0; i < LO(cmd); i++)
+		printk("%02x ", data[i]);
+	printk(")\n");
+}
+
+/*
+ * Send a packet of bytes to the device
+ */
+static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
+{
+	switch (iforce->bus) {
+
+#ifdef IFORCE_232
+		case IFORCE_232: {
+
+			int i;
+			unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
+
+			serio_write(iforce->serio, 0x2b);
+			serio_write(iforce->serio, HI(cmd));
+			serio_write(iforce->serio, LO(cmd));
+
+			for (i = 0; i < LO(cmd); i++) {
+				serio_write(iforce->serio, data[i]);
+				csum = csum ^ data[i];
+			}
+
+			serio_write(iforce->serio, csum);
+			return;
+		}
+#endif
+#ifdef IFORCE_USB
+		case IFORCE_USB: {
+
+			DECLARE_WAITQUEUE(wait, current);
+			int timeout = HZ; /* 1 second */
+
+			memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+			((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+			iforce->out->transfer_buffer_length = LO(cmd) + 2;
+			iforce->out->dev = iforce->usbdev;
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&iforce->wait, &wait);
+
+			if (usb_submit_urb(iforce->out)) {
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&iforce->wait, &wait);
+				return;
+			}
+
+			while (timeout && iforce->out->status == -EINPROGRESS)
+				timeout = schedule_timeout(timeout);
+
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&iforce->wait, &wait);
+
+			if (!timeout)
+				usb_unlink_urb(iforce->out);
+
+			return;
+		}
+#endif
+	}
+}
+
+static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+{
+	struct input_dev *dev = &iforce->dev;
+	int i;
+
+#ifdef IFORCE_232
+	if (HI(iforce->expect_packet) == HI(cmd)) {
+		iforce->expect_packet = 0;
+		iforce->ecmd = cmd;
+		memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
+		if (waitqueue_active(&iforce->wait))
+			wake_up(&iforce->wait);
+	}
+#endif
+
+	if (!iforce->type)
+		return;
+
+	switch (HI(cmd)) {
+
+		case 0x01:	/* joystick position data */
+		case 0x03:	/* wheel position data */
+
+			if (HI(cmd) == 1) {
+				input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
+				input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
+				input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
+			} else {
+				input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
+				input_report_abs(dev, ABS_GAS,   255 - data[2]);
+				input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
+			}
+
+			input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
+			input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
+
+			for (i = 0; iforce->type->btn[i] >= 0; i++)
+				input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
+
+			break;
+
+		case 0x02:	/* status report */
+
+			input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+			break;
+	}
+}
+
+static int get_id_packet(struct iforce *iforce, char *packet)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = HZ; /* 1 second */
+
+	switch (iforce->bus) {
+
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+
+			iforce->dr.bRequest = packet[0];
+			iforce->ctrl->dev = iforce->usbdev;
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&iforce->wait, &wait);
+
+			if (usb_submit_urb(iforce->ctrl)) {
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&iforce->wait, &wait);
+				return -1;
+			}
+
+			while (timeout && iforce->ctrl->status == -EINPROGRESS)
+				timeout = schedule_timeout(timeout);
+
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&iforce->wait, &wait);
+
+			if (!timeout) {
+				usb_unlink_urb(iforce->ctrl);
+				return -1;
+			}
+
+			break;
+#endif
+#ifdef IFORCE_232
+		case IFORCE_232:
+
+			iforce->expect_packet = FF_CMD_QUERY;
+			send_packet(iforce, FF_CMD_QUERY, packet);
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&iforce->wait, &wait);
+
+			while (timeout && iforce->expect_packet)
+				timeout = schedule_timeout(timeout);
+
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&iforce->wait, &wait);
+
+			if (!timeout) {
+				iforce->expect_packet = 0;
+				return -1;
+			}
+
+			break;
+#endif
+	}
+
+	return -(iforce->edata[0] != packet[0]);
+}
+
+static int iforce_open(struct input_dev *dev)
+{
+	struct iforce *iforce = dev->private;
+
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			if (iforce->open++)
+				break;
+			iforce->irq->dev = iforce->usbdev;
+			if (usb_submit_urb(iforce->irq))
+					return -EIO;
+			break;
+#endif
+	}
+	return 0;
+}
+
+static void iforce_close(struct input_dev *dev)
+{
+	struct iforce *iforce = dev->private;
+
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			if (!--iforce->open)
+				usb_unlink_urb(iforce->irq);
+			break;
+#endif
+	}
+}
+
+/*
+ * Start or stop playing an effect
+ */
+
+static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct iforce* iforce = (struct iforce*)(dev->private);
+	unsigned char data[3];
+
+	printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
+
+	if (type != EV_FF)
+		return -1;
+
+	switch (code) {
+
+		case FF_GAIN:
+
+			data[0] = value >> 9;
+			send_packet(iforce, FF_CMD_GAIN, data);
+
+			return 0;
+
+		case FF_AUTOCENTER:
+
+			data[0] = 0x03;
+			data[1] = value >> 9;
+			send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			data[0] = 0x04;
+			data[1] = 0x01;
+			send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			return 0;
+
+		default: /* Play an effect */
+
+			if (code >= iforce->dev.ff_effects_max)
+				return -1;
+
+			data[0] = LO(code);
+			data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
+			data[2] = LO(value);
+			send_packet(iforce, FF_CMD_PLAY, data);
+
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * Set the magnitude of a constant force effect
+ * Return error code
+ *
+ * Note: caller must ensure exclusive access to device
+ */
+
+static int make_magnitude_modifier(struct iforce* iforce,
+	struct resource* mod_chunk, __s16 level)
+{
+	unsigned char data[3];
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+	data[2] = HI(level);
+
+	send_packet(iforce, FF_CMD_MAGNITUDE, data);
+
+	return 0;
+}
+
+/*
+ * Upload the component of an effect dealing with the period, phase and magnitude
+ */
+
+static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk,
+	__s16 magnitude, __s16 offset, u16 period, u16 phase)
+{
+	unsigned char data[7];
+
+	period = TIME_SCALE(period);
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = HI(magnitude);
+	data[3] = HI(offset);
+	data[4] = HI(phase);
+
+	data[5] = LO(period);
+	data[6] = HI(period);
+
+	send_packet(iforce, FF_CMD_PERIOD, data);
+
+	return 0;
+}
+
+/*
+ * Uploads the part of an effect setting the shape of the force
+ */
+
+static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
+	u16 attack_duration, __s16 initial_level,
+	u16 fade_duration, __s16 final_level)
+{
+	unsigned char data[8];
+
+	attack_duration = TIME_SCALE(attack_duration);
+	fade_duration = TIME_SCALE(fade_duration);
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = LO(attack_duration);
+	data[3] = HI(attack_duration);
+	data[4] = HI(initial_level);
+
+	data[5] = LO(fade_duration);
+	data[6] = HI(fade_duration);
+	data[7] = HI(final_level);
+
+	send_packet(iforce, FF_CMD_SHAPE, data);
+
+	return 0;
+}
+
+/*
+ * Component of spring, friction, inertia... effects
+ */
+
+static int make_interactive_modifier(struct iforce* iforce,
+	struct resource* mod_chunk,
+	__s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
+{
+	unsigned char data[10];
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = HI(rk);
+	data[3] = HI(lk);
+
+	data[4] = LO(center);
+	data[5] = HI(center);
+
+	data[6] = LO(db);
+	data[7] = HI(db);
+
+	data[8] = HI(rsat);
+	data[9] = HI(lsat);
+
+	send_packet(iforce, FF_CMD_INTERACT, data);
+
+	return 0;
+}
+
+static unsigned char find_button(struct iforce *iforce, signed short button)
+{
+	int i;
+	for (i = 1; iforce->type->btn[i] >= 0; i++)
+		if (iforce->type->btn[i] == button)
+			return i + 1;
+	return 0;
+}
+
+/*
+ * Send the part common to all effects to the device
+ */
+
+static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
+	u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,
+	u16 interval, u16 direction)
+{
+	unsigned char data[14];
+
+	duration = TIME_SCALE(duration);
+	delay    = TIME_SCALE(delay);
+	interval = TIME_SCALE(interval);
+
+	data[0]  = LO(id);
+	data[1]  = effect_type;
+	data[2]  = LO(axes) | find_button(iforce, button);
+
+	data[3]  = LO(duration);
+	data[4]  = HI(duration);
+
+	data[5]  = HI(direction);
+
+	data[6]  = LO(interval);
+	data[7]  = HI(interval);
+
+	data[8]  = LO(mod_id1);
+	data[9]  = HI(mod_id1);
+	data[10] = LO(mod_id2);
+	data[11] = HI(mod_id2);
+
+	data[12] = LO(delay);
+	data[13] = HI(delay);
+
+	send_packet(iforce, FF_CMD_EFFECT, data);
+
+	return 0;
+}
+
+/*
+ * Upload a periodic effect to the device
+ */
+
+static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
+{
+	u8 wave_code;
+	int core_id = effect->id;
+	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+	struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
+	struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
+	int err = 0;
+
+	err = make_period_modifier(iforce, mod1_chunk,
+		effect->u.periodic.magnitude, effect->u.periodic.offset,
+		effect->u.periodic.period, effect->u.periodic.phase);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	err = make_shape_modifier(iforce, mod2_chunk,
+		effect->u.periodic.shape.attack_length,
+		effect->u.periodic.shape.attack_level,
+		effect->u.periodic.shape.fade_length,
+		effect->u.periodic.shape.fade_level);
+	if (err) return err;
+	set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+	switch (effect->u.periodic.waveform) {
+		case FF_SQUARE:		wave_code = 0x20; break;
+		case FF_TRIANGLE:	wave_code = 0x21; break;
+		case FF_SINE:		wave_code = 0x22; break;
+		case FF_SAW_UP:		wave_code = 0x23; break;
+		case FF_SAW_DOWN:	wave_code = 0x24; break;
+		default:		wave_code = 0x20; break;
+	}
+
+	err = make_core(iforce, effect->id,
+		mod1_chunk->start,
+		mod2_chunk->start,
+		wave_code,
+		0x20,
+		effect->replay.length,
+		effect->replay.delay,
+		effect->trigger.button,
+		effect->trigger.interval,
+		effect->u.periodic.direction);
+
+	return err;
+}
+
+/*
+ * Upload a constant force effect
+ */
+static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
+{
+	int core_id = effect->id;
+	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+	struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
+	struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
+	int err = 0;
+
+	printk(KERN_DEBUG "iforce.c: make constant effect\n");
+
+	err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	err = make_shape_modifier(iforce, mod2_chunk,
+		effect->u.constant.shape.attack_length,
+		effect->u.constant.shape.attack_level,
+		effect->u.constant.shape.fade_length,
+		effect->u.constant.shape.fade_level);
+	if (err) return err;
+	set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+	err = make_core(iforce, effect->id,
+		mod1_chunk->start,
+		mod2_chunk->start,
+		0x00,
+		0x20,
+		effect->replay.length,
+		effect->replay.delay,
+		effect->trigger.button,
+		effect->trigger.interval,
+		effect->u.constant.direction);
+
+	return err;
+}
+
+/*
+ * Upload an interactive effect. Those are for example friction, inertia, springs...
+ */
+static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
+{
+	int core_id = effect->id;
+	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+	struct resource* mod_chunk = &(core_effect->mod1_chunk);
+	u8 type, axes;
+	u16 mod1, mod2, direction;
+	int err = 0;
+
+	printk(KERN_DEBUG "iforce.c: make interactive effect\n");
+
+	switch (effect->type) {
+		case FF_SPRING:		type = 0x40; break;
+		case FF_FRICTION:	type = 0x41; break;
+		default: return -1;
+	}
+
+	err = make_interactive_modifier(iforce, mod_chunk,
+		effect->u.interactive.right_saturation,
+		effect->u.interactive.left_saturation,
+		effect->u.interactive.right_coeff,
+		effect->u.interactive.left_coeff,
+		effect->u.interactive.deadband,
+		effect->u.interactive.center);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
+		test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
+		(!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
+
+		case 0: /* Only one axis, choose orientation */
+			mod1 = mod_chunk->start;
+			mod2 = 0xffff;
+			direction = effect->u.interactive.direction;
+			axes = 0x20;
+			break;
+
+		case 1:	/* Only X axis */
+			mod1 = mod_chunk->start;
+			mod2 = 0xffff;
+			direction = 0x5a00;
+			axes = 0x40;
+			break;
+
+		case 2: /* Only Y axis */
+			mod1 = 0xffff;
+			mod2 = mod_chunk->start;
+			direction = 0xb400;
+			axes = 0x80;
+			break;
+
+		case 3:	/* Both X and Y axes */
+			/* TODO: same setting for both axes is not mandatory */
+			mod1 = mod_chunk->start;
+			mod2 = mod_chunk->start;
+			direction = 0x6000;
+			axes = 0xc0;
+			break;
+
+		default:
+			return -1;
+	}
+
+	err = make_core(iforce, effect->id,
+		mod1, mod2,
+		type, axes,
+		effect->replay.length, effect->replay.delay,
+		effect->trigger.button, effect->trigger.interval,
+		direction);
+
+	return err;
+}
+
+/*
+ * Function called when an ioctl is performed on the event dev entry.
+ * It uploads an effect to the device
+ */
+static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+{
+	struct iforce* iforce = (struct iforce*)(dev->private);
+	int id;
+
+	printk(KERN_DEBUG "iforce.c: upload effect\n");
+
+/*
+ * Get a free id
+ */
+
+	for (id=0; id < FF_EFFECTS_MAX; ++id)
+		if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break;
+
+	if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max)
+		return -ENOMEM;
+
+	effect->id = id;
+	set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
+
+/*
+ * Upload the effect
+ */
+
+	switch (effect->type) {
+
+		case FF_PERIODIC:
+			return iforce_upload_periodic(iforce, effect);
+
+		case FF_CONSTANT:
+			return iforce_upload_constant(iforce, effect);
+
+		case FF_SPRING:
+		case FF_FRICTION:
+			return iforce_upload_interactive(iforce, effect);
+
+		default:
+			return -1;
+	}
+}
+
+/*
+ * Erases an effect: it frees the effect id and mark as unused the memory
+ * allocated for the parameters
+ */
+static int iforce_erase_effect(struct input_dev *dev, int effect_id)
+{
+	struct iforce* iforce = (struct iforce*)(dev->private);
+	int err = 0;
+	struct iforce_core_effect* core_effect;
+
+	printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
+
+	if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
+		return -EINVAL;
+
+	core_effect = iforce->core_effects + effect_id;
+
+	if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
+		err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
+
+	if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
+		err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
+
+	/*TODO: remember to change that if more FF_MOD* bits are added */
+	core_effect->flags[0] = 0;
+
+	return err;
+}
+static int iforce_init_device(struct iforce *iforce)
+{
+	unsigned char c[] = "CEOV";
+	int i;
+
+	init_waitqueue_head(&iforce->wait);
+	iforce->dev.ff_effects_max = 10;
+
+/*
+ * Input device fields.
+ */
+
+	iforce->dev.idbus = BUS_USB;
+	iforce->dev.private = iforce;
+	iforce->dev.name = iforce->name;
+	iforce->dev.open = iforce_open;
+	iforce->dev.close = iforce_close;
+	iforce->dev.event = iforce_input_event;
+	iforce->dev.upload_effect = iforce_upload_effect;
+	iforce->dev.erase_effect = iforce_erase_effect;
+
+/*
+ * On-device memory allocation.
+ */
+
+	iforce->device_memory.name = "I-Force device effect memory";
+	iforce->device_memory.start = 0;
+	iforce->device_memory.end = 200;
+	iforce->device_memory.flags = IORESOURCE_MEM;
+	iforce->device_memory.parent = NULL;
+	iforce->device_memory.child = NULL;
+	iforce->device_memory.sibling = NULL;
+
+/*
+ * Wait until device ready - until it sends its first response.
+ */
+
+	for (i = 0; i < 20; i++)
+		if (!get_id_packet(iforce, "O"))
+			break;
+
+	if (i == 20) { /* 5 seconds */
+		printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
+		iforce_close(&iforce->dev);
+		return -1;
+	}
+
+/*
+ * Get device info.
+ */
+
+	if (!get_id_packet(iforce, "M"))
+		iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "P"))
+		iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "B"))
+		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "N"))
+		iforce->dev.ff_effects_max = iforce->edata[1];
+
+/*
+ * Display additional info.
+ */
+
+	for (i = 0; c[i]; i++)
+		if (!get_id_packet(iforce, c + i))
+			dump_packet("info", iforce->ecmd, iforce->edata);
+
+/*
+ * Disable spring, enable force feedback.
+ * FIXME: We should use iforce_set_autocenter() et al here.
+ */
+
+	send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
+	send_packet(iforce, FF_CMD_ENABLE, "\004");
+
+/*
+ * Find appropriate device entry
+ */
+
+	for (i = 0; iforce_device[i].idvendor; i++)
+		if (iforce_device[i].idvendor == iforce->dev.idvendor &&
+		    iforce_device[i].idproduct == iforce->dev.idproduct)
+			break;
+
+	iforce->type = iforce_device + i;
+
+	sprintf(iforce->name, iforce->type->name,
+		iforce->dev.idproduct, iforce->dev.idvendor);
+
+/*
+ * Set input device bitfields and ranges.
+ */
+
+	iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
+
+	for (i = 0; iforce->type->btn[i] >= 0; i++) {
+		signed short t = iforce->type->btn[i];
+		set_bit(t, iforce->dev.keybit);
+		if (t != BTN_DEAD)
+			set_bit(FF_BTN(t), iforce->dev.ffbit);
+	}
+
+	for (i = 0; iforce->type->abs[i] >= 0; i++) {
+
+		signed short t = iforce->type->abs[i];
+		set_bit(t, iforce->dev.absbit);
+
+		switch (t) {
+
+			case ABS_X:
+			case ABS_Y:
+			case ABS_WHEEL:
+
+				iforce->dev.absmax[t] =  1920;
+				iforce->dev.absmin[t] = -1920;
+				iforce->dev.absflat[t] = 128;
+				iforce->dev.absfuzz[t] = 16;
+
+				set_bit(FF_ABS(t), iforce->dev.ffbit);
+				break;
+
+			case ABS_THROTTLE:
+			case ABS_GAS:
+			case ABS_BRAKE:
+
+				iforce->dev.absmax[t] = 255;
+				iforce->dev.absmin[t] = 0;
+				break;
+
+			case ABS_HAT0X:
+			case ABS_HAT0Y:
+				iforce->dev.absmax[t] =  1;
+				iforce->dev.absmin[t] = -1;
+				break;
+		}
+	}
+
+	for (i = 0; iforce->type->ff[i] >= 0; i++)
+		set_bit(iforce->type->ff[i], iforce->dev.ffbit);
+
+/*
+ * Register input device.
+ */
+
+	input_register_device(&iforce->dev);
+
+	return 0;
+}
+
+#ifdef IFORCE_USB
+
+static void iforce_usb_irq(struct urb *urb)
+{
+	struct iforce *iforce = urb->context;
+	if (urb->status) return;
+	iforce_process_packet(iforce,
+		(iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+}
+
+static void iforce_usb_out(struct urb *urb)
+{
+	struct iforce *iforce = urb->context;
+	if (urb->status) return;
+	if (waitqueue_active(&iforce->wait))
+		wake_up(&iforce->wait);
+}
+
+static void iforce_usb_ctrl(struct urb *urb)
+{
+	struct iforce *iforce = urb->context;
+	if (urb->status) return;
+	iforce->ecmd = 0xff00 | urb->actual_length;
+	if (waitqueue_active(&iforce->wait))
+		wake_up(&iforce->wait);
+}
+
+static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
+				const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *epirq, *epout;
+	struct iforce *iforce;
+
+	epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+	epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
+
+	if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
+	memset(iforce, 0, sizeof(struct iforce));
+
+	iforce->irq = usb_alloc_urb(0);
+	if (!iforce->irq) {
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->out = usb_alloc_urb(0);
+	if (!iforce->out) {
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->ctrl = usb_alloc_urb(0);
+	if (!iforce->ctrl) {
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+
+	iforce->bus = IFORCE_USB;
+	iforce->usbdev = dev;
+
+	iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+	iforce->dr.wIndex = 0;
+	iforce->dr.wLength = 16;
+
+	FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+
+	FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+			iforce + 1, 32, iforce_usb_out, iforce);
+
+	FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+			(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
+
+	if (iforce_init_device(iforce)) {
+		usb_free_urb(iforce->ctrl);
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+
+	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
+		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+		iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
+
+	return iforce;
+}
+
+static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct iforce *iforce = ptr;
+	usb_unlink_urb(iforce->irq);
+	input_unregister_device(&iforce->dev);
+	usb_free_urb(iforce->ctrl);
+	usb_free_urb(iforce->out);
+	usb_free_urb(iforce->irq);
+	kfree(iforce);
+}
+
+static struct usb_device_id iforce_usb_ids [] = {
+	{ USB_DEVICE(0x046d, 0xc281) },		/* Logitech WingMan Force */
+	{ USB_DEVICE(0x046d, 0xc291) },		/* Logitech WingMan Formula Force */
+	{ USB_DEVICE(0x05ef, 0x020a) },		/* AVB Top Shot Pegasus */
+	{ USB_DEVICE(0x05ef, 0x8884) },		/* AVB Mag Turbo Force */
+	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
+
+static struct usb_driver iforce_usb_driver = {
+	name:		"iforce",
+	probe:		iforce_usb_probe,
+	disconnect:	iforce_usb_disconnect,
+	id_table:	iforce_usb_ids,
+};
+
+#endif
+
+#ifdef IFORCE_232
+
+static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct iforce* iforce = serio->private;
+
+	if (!iforce->pkt) {
+		if (data != 0x2b) {
+			return;
+		}
+		iforce->pkt = 1;
+		return;
+	}
+
+	if (!iforce->id) {
+		if (data > 3 && data != 0xff) {
+			iforce->pkt = 0;
+			return;
+		}
+		iforce->id = data;
+		return;
+	}
+
+	if (!iforce->len) {
+		if (data > IFORCE_MAX_LENGTH) {
+			iforce->pkt = 0;
+			iforce->id = 0;
+			return;
+		}
+		iforce->len = data;
+		return;
+	}
+
+	if (iforce->idx < iforce->len) {
+		iforce->csum += iforce->data[iforce->idx++] = data;
+		return;
+	}
+
+	if (iforce->idx == iforce->len) {
+		iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
+		iforce->pkt = 0;
+		iforce->id  = 0;
+		iforce->len = 0;
+		iforce->idx = 0;
+		iforce->csum = 0;
+	}
+}
+
+static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct iforce *iforce;
+	if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
+		return;
+
+	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
+	memset(iforce, 0, sizeof(struct iforce));
+
+	iforce->bus = IFORCE_232;
+	iforce->serio = serio;
+	serio->private = iforce;
+
+	if (serio_open(serio, dev)) {
+		kfree(iforce);
+		return;
+	}
+
+	if (iforce_init_device(iforce)) {
+		serio_close(serio);
+		kfree(iforce);
+		return;
+	}
+
+	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
+		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+		iforce->device_memory.end, serio->number);
+}
+
+static void iforce_serio_disconnect(struct serio *serio)
+{
+	struct iforce* iforce = serio->private;
+
+	input_unregister_device(&iforce->dev);
+	serio_close(serio);
+	kfree(iforce);
+}
+
+static struct serio_dev iforce_serio_dev = {
+	interrupt:	iforce_serio_irq,
+	connect:	iforce_serio_connect,
+	disconnect:	iforce_serio_disconnect,
+};
+
+#endif
+
+static int __init iforce_init(void)
+{
+#ifdef IFORCE_USB
+	usb_register(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+	serio_register_device(&iforce_serio_dev);
+#endif
+	return 0;
+}
+
+static void __exit iforce_exit(void)
+{
+#ifdef IFORCE_USB
+	usb_deregister(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+	serio_unregister_device(&iforce_serio_dev);
+#endif
+}
+
+module_init(iforce_init);
+module_exit(iforce_exit);
diff -Nru a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/interact.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,308 @@
+/*
+ * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
+ *
+ *  Copyright (c) 2000 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Toby Deshane
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * InterAct digital gamepad/joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define INTERACT_MAX_START	400	/* 400 us */
+#define INTERACT_MAX_STROBE	40	/* 40 us */
+#define INTERACT_MAX_LENGTH	32	/* 32 bits */
+#define INTERACT_REFRESH_TIME	HZ/50	/* 20 ms */
+
+#define INTERACT_TYPE_HHFX	0	/* HammerHead/FX */
+#define INTERACT_TYPE_PP8D	1	/* ProPad 8 */
+
+struct interact {
+	struct gameport *gameport;
+	struct input_dev dev;
+	struct timer_list timer;
+	int used;
+	int bads;
+	int reads;
+	unsigned char type;
+	unsigned char length;
+};
+
+static short interact_abs_hhfx[] = 
+	{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
+static short interact_abs_pp8d[] =
+	{ ABS_X, ABS_Y, -1 };
+
+static short interact_btn_hhfx[] =
+	{ BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
+static short interact_btn_pp8d[] =
+	{ BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
+
+struct interact_type {
+	int id;
+	short *abs;
+	short *btn;
+	char *name;
+	unsigned char length;
+	unsigned char b8;
+};
+
+static struct interact_type interact_type[] = {
+	{ 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX",    32, 4 },
+	{ 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
+	{ 0 }};
+
+/*
+ * interact_read_packet() reads and InterAct joystick data.
+ */
+
+static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
+{
+	unsigned long flags;
+	unsigned char u, v;
+	unsigned int t, s;
+	int i;
+
+	i = 0;
+	data[0] = data[1] = data[2] = 0;
+	t = gameport_time(gameport, INTERACT_MAX_START);
+	s = gameport_time(gameport, INTERACT_MAX_STROBE);
+
+	__save_flags(flags);
+	__cli();
+	gameport_trigger(gameport);
+	v = gameport_read(gameport);
+
+	while (t > 0 && i < length) {
+		t--;
+		u = v; v = gameport_read(gameport);
+		if (v & ~u & 0x40) {
+			data[0] = (data[0] << 1) | ((v >> 4) & 1);
+			data[1] = (data[1] << 1) | ((v >> 5) & 1);
+			data[2] = (data[2] << 1) | ((v >> 7) & 1);
+			i++;
+			t = s;
+		}
+	}
+
+	__restore_flags(flags);
+
+	return i;
+}
+
+/*
+ * interact_timer() reads and analyzes InterAct joystick data.
+ */
+
+static void interact_timer(unsigned long private)
+{
+	struct interact *interact = (struct interact *) private;
+	struct input_dev *dev = &interact->dev;
+	u32 data[3];
+	int i;
+
+	interact->reads++;
+
+	if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
+		interact->bads++;
+	} else
+
+	for (i = 0; i < 3; i++)
+		data[i] <<= INTERACT_MAX_LENGTH - interact->length;
+
+	switch (interact->type) {
+
+		case INTERACT_TYPE_HHFX:
+
+			for (i = 0; i < 4; i++)
+				input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
+
+			for (i = 0; i < 2; i++)
+				input_report_abs(dev, ABS_HAT0Y - i,
+					((data[1] >> ((i << 1) + 17)) & 1)  - ((data[1] >> ((i << 1) + 16)) & 1));
+
+			for (i = 0; i < 8; i++)
+				input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
+
+			for (i = 0; i < 4; i++)
+				input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
+
+			break;
+
+		case INTERACT_TYPE_PP8D:
+
+			for (i = 0; i < 2; i++)
+				input_report_abs(dev, interact_abs_pp8d[i], 
+					((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
+
+			for (i = 0; i < 8; i++)
+				input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
+
+			break;
+	}
+
+	mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+
+}
+
+/*
+ * interact_open() is a callback from the input open routine.
+ */
+
+static int interact_open(struct input_dev *dev)
+{
+	struct interact *interact = dev->private;
+	if (!interact->used++)
+		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * interact_close() is a callback from the input close routine.
+ */
+
+static void interact_close(struct input_dev *dev)
+{
+	struct interact *interact = dev->private;
+	if (!--interact->used)
+		del_timer(&interact->timer);
+}
+
+/*
+ * interact_connect() probes for InterAct joysticks.
+ */
+
+static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct interact *interact;
+	__u32 data[3];
+	int i, t;
+
+	if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
+		return;
+	memset(interact, 0, sizeof(struct interact));
+
+	gameport->private = interact;
+
+	interact->gameport = gameport;
+	init_timer(&interact->timer);
+	interact->timer.data = (long) interact;
+	interact->timer.function = interact_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
+
+	if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
+		goto fail2;
+	}
+
+	for (i = 0; interact_type[i].length; i++)
+		if (interact_type[i].id == (data[2] >> 16))
+			break;
+
+	if (!interact_type[i].length) {
+		printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
+			gameport->number, i, data[0], data[1], data[2]);
+		goto fail2;	
+	}
+
+	interact->type = i;
+	interact->length = interact_type[i].length;
+
+	interact->dev.private = interact;
+	interact->dev.open = interact_open;
+	interact->dev.close = interact_close;
+
+	interact->dev.name = interact_type[i].name;
+	interact->dev.idbus = BUS_GAMEPORT;
+	interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
+	interact->dev.idproduct = interact_type[i].id;
+	interact->dev.idversion = 0x0100;
+
+	interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
+		set_bit(t, interact->dev.absbit);
+		if (i < interact_type[interact->type].b8) {
+			interact->dev.absmin[t] = 0;
+			interact->dev.absmax[t] = 255;
+		} else {
+			interact->dev.absmin[t] = -1;
+			interact->dev.absmax[t] = 1;
+		}
+	}
+
+	for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
+		set_bit(t, interact->dev.keybit);
+
+	input_register_device(&interact->dev);
+	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+		interact->dev.number, interact_type[interact->type].name, gameport->number);
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:  kfree(interact);
+}
+
+static void interact_disconnect(struct gameport *gameport)
+{
+	struct interact *interact = gameport->private;
+	input_unregister_device(&interact->dev);
+	gameport_close(gameport);
+	kfree(interact);
+}
+
+static struct gameport_dev interact_dev = {
+	connect:	interact_connect,
+	disconnect:	interact_disconnect,
+};
+
+int __init interact_init(void)
+{
+	gameport_register_device(&interact_dev);
+	return 0;
+}
+
+void __exit interact_exit(void)
+{
+	gameport_unregister_device(&interact_dev);
+}
+
+module_init(interact_init);
+module_exit(interact_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/magellan.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,212 @@
+/*
+ * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Magellan and Space Mouse 6dof controller driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	MAGELLAN_MAX_LENGTH	32
+
+static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
+static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *magellan_name = "LogiCad3D Magellan";
+
+/*
+ * Per-Magellan data.
+ */
+
+struct magellan {
+	struct input_dev dev;
+	int idx;
+	unsigned char data[MAGELLAN_MAX_LENGTH];
+};
+
+/*
+ * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
+ * have correct upper nibbles for the lower ones, if not, the packet will
+ * be thrown away. It also strips these upper halves to simplify further
+ * processing.
+ */
+
+static int magellan_crunch_nibbles(unsigned char *data, int count)
+{
+	static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
+
+	do {
+		if (data[count] == nibbles[data[count] & 0xf])
+			data[count] = data[count] & 0xf;
+		else
+			return -1;
+	} while (--count);
+
+	return 0;
+}
+
+static void magellan_process_packet(struct magellan* magellan)
+{
+	struct input_dev *dev = &magellan->dev;
+	unsigned char *data = magellan->data;
+	int i, t;
+
+	if (!magellan->idx) return;
+
+	switch (magellan->data[0]) {
+
+		case 'd':				/* Axis data */
+			if (magellan->idx != 25) return;
+			if (magellan_crunch_nibbles(data, 24)) return;
+			for (i = 0; i < 6; i++)
+				input_report_abs(dev, magellan_axes[i],
+					(data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
+					 data[(i << 2) + 3] <<  4 | data[(i << 2) + 4]) - 32768);
+			break;
+
+		case 'k':				/* Button data */
+			if (magellan->idx != 4) return;
+			if (magellan_crunch_nibbles(data, 3)) return;
+			t = (data[1] << 1) | (data[2] << 5) | data[3];
+			for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
+			break;
+	}
+}
+
+static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct magellan* magellan = serio->private;
+
+	if (data == '\r') {
+		magellan_process_packet(magellan);
+		magellan->idx = 0;
+	} else {
+		if (magellan->idx < MAGELLAN_MAX_LENGTH)
+			magellan->data[magellan->idx++] = data;
+	} 
+}
+
+/*
+ * magellan_disconnect() is the opposite of magellan_connect()
+ */
+
+static void magellan_disconnect(struct serio *serio)
+{
+	struct magellan* magellan = serio->private;
+	input_unregister_device(&magellan->dev);
+	serio_close(serio);
+	kfree(magellan);
+}
+
+/*
+ * magellan_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Magellan, and if found, registers
+ * it as an input device.
+ */
+
+static void magellan_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct magellan *magellan;
+	int i, t;
+
+	if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
+		return;
+
+	if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
+		return;
+
+	memset(magellan, 0, sizeof(struct magellan));
+
+	magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+
+	for (i = 0; i < 9; i++)
+		set_bit(magellan_buttons[i], &magellan->dev.keybit);
+
+	for (i = 0; i < 6; i++) {
+		t = magellan_axes[i];
+		set_bit(t, magellan->dev.absbit);
+		magellan->dev.absmin[t] = -360;
+		magellan->dev.absmax[t] =  360;
+	}
+
+	magellan->dev.private = magellan;
+	magellan->dev.name = magellan_name;
+	magellan->dev.idbus = BUS_RS232;
+	magellan->dev.idvendor = SERIO_MAGELLAN;
+	magellan->dev.idproduct = 0x0001;
+	magellan->dev.idversion = 0x0100;
+	
+	serio->private = magellan;
+
+	if (serio_open(serio, dev)) {
+		kfree(magellan);
+		return;
+	}
+
+	input_register_device(&magellan->dev);
+
+	printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev magellan_dev = {
+	interrupt:	magellan_interrupt,
+	connect:	magellan_connect,
+	disconnect:	magellan_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init magellan_init(void)
+{
+	serio_register_device(&magellan_dev);
+	return 0;
+}
+
+void __exit magellan_exit(void)
+{
+	serio_unregister_device(&magellan_dev);
+}
+
+module_init(magellan_init);
+module_exit(magellan_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/sidewinder.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,761 @@
+/*
+ * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Microsoft SideWinder joystick family driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+/*
+ * These are really magic values. Changing them can make a problem go away,
+ * as well as break everything.
+ */
+
+#undef SW_DEBUG
+
+#define SW_START	400	/* The time we wait for the first bit [400 us] */
+#define SW_STROBE	45	/* Max time per bit [45 us] */
+#define SW_TIMEOUT	4000	/* Wait for everything to settle [4 ms] */
+#define SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
+#define SW_END		8	/* Number of bits before end of packet to kick */
+#define SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
+#define SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
+#define SW_OK		64	/* Number of packet read successes to switch optimization back on */
+#define SW_LENGTH	512	/* Max number of bits in a packet */
+#define SW_REFRESH	HZ/50	/* Time to wait between updates of joystick data [20 ms] */
+
+#ifdef SW_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+/*
+ * SideWinder joystick types ...
+ */
+
+#define SW_ID_3DP	0
+#define SW_ID_GP	1
+#define SW_ID_PP	2
+#define SW_ID_FFP	3
+#define SW_ID_FSP	4
+#define SW_ID_FFW	5
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *sw_name[] = {	"3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
+				"Force Feedback Wheel" };
+
+static char sw_abs[][7] = {
+	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+	{ ABS_X, ABS_Y },
+	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+	{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+	{ ABS_X, ABS_Y,         ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+	{ ABS_RX, ABS_RUDDER,   ABS_THROTTLE }};
+
+static char sw_bit[][7] = {
+	{ 10, 10,  9, 10,  1,  1 },
+	{  1,  1                 },
+	{ 10, 10,  6,  7,  1,  1 },
+	{ 10, 10,  6,  7,  1,  1 },
+	{ 10, 10,  6,  1,  1     },
+	{ 10,  7,  7,  1,  1     }};
+
+static short sw_btn[][12] = {
+	{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
+	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
+	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
+	{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
+
+static struct {
+	int x;
+	int y;
+} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+struct sw {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct input_dev dev[4];
+	char name[64];
+	int length;
+	int type;
+	int bits;
+	int number;
+	int fail;
+	int ok;
+	int reads;
+	int bads;
+	int used;
+};
+
+/*
+ * sw_read_packet() is a function which reads either a data packet, or an
+ * identification packet from a SideWinder joystick. The protocol is very,
+ * very, very braindamaged. Microsoft patented it in US patent #5628686.
+ */
+
+static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
+{
+	unsigned long flags;
+	int timeout, bitout, sched, i, kick, start, strobe;
+	unsigned char pending, u, v;
+
+	i = -id;						/* Don't care about data, only want ID */
+	timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0;	/* Set up global timeout for ID packet */
+	kick = id ? gameport_time(gameport, SW_KICK) : 0;	/* Set up kick timeout for ID packet */
+	start = gameport_time(gameport, SW_START);
+	strobe = gameport_time(gameport, SW_STROBE);
+	bitout = start;
+	pending = 0;
+	sched = 0;
+
+        __save_flags(flags);					/* Quiet, please */
+        __cli();
+
+	gameport_trigger(gameport);				/* Trigger */
+	v = gameport_read(gameport);
+
+	do {
+		bitout--;
+		u = v;
+		v = gameport_read(gameport);
+	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */
+
+	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */
+
+	while ((timeout > 0 || bitout > 0) && (i < length)) {
+
+		timeout--;
+		bitout--;					/* Decrement timers */
+		sched--;
+
+		u = v;
+		v = gameport_read(gameport);
+
+		if ((~u & v & 0x10) && (bitout > 0)) {		/* Rising edge on clock - data bit */
+			if (i >= 0)				/* Want this data */
+				buf[i] = v >> 5;		/* Store it */
+			i++;					/* Advance index */
+			bitout = strobe;			/* Extend timeout for next bit */
+		} 
+
+		if (kick && (~v & u & 0x01)) {			/* Falling edge on axis 0 */
+			sched = kick;				/* Schedule second trigger */
+			kick = 0;				/* Don't schedule next time on falling edge */
+			pending = 1;				/* Mark schedule */
+		} 
+
+		if (pending && sched < 0 && (i > -SW_END)) {	/* Second trigger time */
+			gameport_trigger(gameport);		/* Trigger */
+			bitout = start;				/* Long bit timeout */
+			pending = 0;				/* Unmark schedule */
+			timeout = 0;				/* Switch from global to bit timeouts */ 
+		}
+	}
+
+	__restore_flags(flags);					/* Done - relax */
+
+#ifdef SW_DEBUG
+	{
+		int j;
+		printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
+		for (j = 0; j < i; j++) printk("%d", buf[j]);
+		printk("]\n");
+	}
+#endif
+
+	return i;
+}
+
+/*
+ * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
+ * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
+ * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
+ * is number of bits per triplet.
+ */
+
+#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
+
+static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
+{
+	__u64 data = 0;
+	int tri = pos % bits;						/* Start position */
+	int i   = pos / bits;
+	int bit = 0;
+
+	while (num--) {
+		data |= (__u64)((buf[i] >> tri++) & 1) << bit++;	/* Transfer bit */
+		if (tri == bits) {
+			i++;						/* Next triplet */
+			tri = 0;
+		}
+	}
+
+	return data;
+}
+
+/*
+ * sw_init_digital() initializes a SideWinder 3D Pro joystick
+ * into digital mode.
+ */
+
+static void sw_init_digital(struct gameport *gameport)
+{
+	int seq[] = { 140, 140+725, 140+300, 0 };
+	unsigned long flags;
+	int i, t;
+
+        __save_flags(flags);
+        __cli();
+
+	i = 0;
+        do {
+                gameport_trigger(gameport);			/* Trigger */
+		t = gameport_time(gameport, SW_TIMEOUT);
+		while ((gameport_read(gameport) & 1) && t) t--;	/* Wait for axis to fall back to 0 */
+                udelay(seq[i]);					/* Delay magic time */
+        } while (seq[++i]);
+
+	gameport_trigger(gameport);				/* Last trigger */
+
+	__restore_flags(flags);
+}
+
+/*
+ * sw_parity() computes parity of __u64
+ */
+
+static int sw_parity(__u64 t)
+{
+	int x = t ^ (t >> 32);
+	x ^= x >> 16;
+	x ^= x >> 8;
+	x ^= x >> 4;
+	x ^= x >> 2;
+	x ^= x >> 1;
+	return x & 1;
+}
+
+/*
+ * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
+ */
+
+static int sw_check(__u64 t)
+{
+	unsigned char sum = 0;
+
+	if ((t & 0x8080808080808080ULL) ^ 0x80)			/* Sync */
+		return -1;
+
+	while (t) {						/* Sum */
+		sum += t & 0xf;
+		t >>= 4;
+	}
+
+	return sum & 0xf;
+}
+
+/*
+ * sw_parse() analyzes SideWinder joystick data, and writes the results into
+ * the axes and buttons arrays.
+ */
+
+static int sw_parse(unsigned char *buf, struct sw *sw)
+{
+	int hat, i, j;
+	struct input_dev *dev = sw->dev;
+
+	switch (sw->type) {
+
+		case SW_ID_3DP:
+
+			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+
+			input_report_abs(dev, ABS_X,        (GB( 3,3) << 7) | GB(16,7));
+			input_report_abs(dev, ABS_Y,        (GB( 0,3) << 7) | GB(24,7));
+			input_report_abs(dev, ABS_RZ,       (GB(35,2) << 7) | GB(40,7));
+			input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
+
+			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+			for (j = 0; j < 7; j++)
+				input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
+
+			input_report_key(dev, BTN_BASE4, !GB(38,1));
+			input_report_key(dev, BTN_BASE5, !GB(37,1));
+
+			return 0;
+
+		case SW_ID_GP:
+
+			for (i = 0; i < sw->number; i ++) {
+
+				if (sw_parity(GB(i*15,15))) return -1;
+
+				input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
+				input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
+
+				for (j = 0; j < 10; j++)
+					input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+			}
+
+			return 0;
+
+		case SW_ID_PP:
+		case SW_ID_FFP:
+
+			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+
+			input_report_abs(dev, ABS_X,        GB( 9,10));
+			input_report_abs(dev, ABS_Y,        GB(19,10));
+			input_report_abs(dev, ABS_RZ,       GB(36, 6));
+			input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
+
+			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+			for (j = 0; j < 9; j++)
+				input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
+
+			return 0;
+
+		case SW_ID_FSP:
+
+			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+
+			input_report_abs(dev, ABS_X,        GB( 0,10));
+			input_report_abs(dev, ABS_Y,        GB(16,10));
+			input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
+
+			input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+			input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+			for (j = 0; j < 6; j++)
+				input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
+
+			input_report_key(dev, BTN_TR,     GB(26,1));
+			input_report_key(dev, BTN_START,  GB(27,1));
+			input_report_key(dev, BTN_MODE,   GB(38,1));
+			input_report_key(dev, BTN_SELECT, GB(39,1));
+
+			return 0;
+
+		case SW_ID_FFW:
+
+			if (!sw_parity(GB(0,33))) return -1;
+
+			input_report_abs(dev, ABS_RX,       GB( 0,10));
+			input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
+			input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
+
+			for (j = 0; j < 8; j++)
+				input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
+
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * sw_read() reads SideWinder joystick data, and reinitializes
+ * the joystick in case of persistent problems. This is the function that is
+ * called from the generic code to poll the joystick.
+ */
+
+static int sw_read(struct sw *sw)
+{
+	unsigned char buf[SW_LENGTH];
+	int i;
+
+	i = sw_read_packet(sw->gameport, buf, sw->length, 0);
+
+	if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) {		/* Broken packet, try to fix */
+
+		if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) {		/* Last init failed, 1 bit mode */
+			printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
+				" - going to reinitialize.\n", sw->gameport->number);
+			sw->fail = SW_FAIL;					/* Reinitialize */
+			i = 128;						/* Bogus value */
+		}
+
+		if (i < 66 && GB(0,64) == GB(i*3-66,64))			/* 1 == 3 */
+			i = 66;							/* Everything is fine */
+
+		if (i < 66 && GB(0,64) == GB(66,64))				/* 1 == 2 */
+			i = 66;							/* Everything is fine */
+
+		if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) {		/* 2 == 3 */
+			memmove(buf, buf + i - 22, 22);				/* Move data */
+			i = 66;							/* Carry on */
+		}
+	}
+
+	if (i == sw->length && !sw_parse(buf, sw)) {				/* Parse data */
+
+		sw->fail = 0;
+		sw->ok++;
+
+		if (sw->type == SW_ID_3DP && sw->length == 66			/* Many packets OK */
+			&& sw->ok > SW_OK) {
+
+			printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
+				" - enabling optimization again.\n", sw->gameport->number);
+			sw->length = 22;
+		}
+
+		return 0;
+	}
+
+	sw->ok = 0;
+	sw->fail++;
+
+	if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) {	/* Consecutive bad packets */
+
+		printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
+			" - disabling optimization.\n", sw->gameport->number);
+		sw->length = 66;
+	}
+
+	if (sw->fail < SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
+
+	printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
+		" - reinitializing joystick.\n", sw->gameport->number);
+
+	if (!i && sw->type == SW_ID_3DP) {					/* 3D Pro can be in analog mode */
+		udelay(3 * SW_TIMEOUT);
+		sw_init_digital(sw->gameport);
+	}
+
+	udelay(SW_TIMEOUT);
+	i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);			/* Read normal data packet */
+	udelay(SW_TIMEOUT);
+	sw_read_packet(sw->gameport, buf, SW_LENGTH, i);			/* Read ID packet, this initializes the stick */
+
+	sw->fail = SW_FAIL;
+	
+	return -1;
+}
+
+static void sw_timer(unsigned long private)
+{
+	struct sw *sw = (void *) private;
+	
+	sw->reads++;
+	if (sw_read(sw)) sw->bads++;
+	mod_timer(&sw->timer, jiffies + SW_REFRESH);
+}
+
+static int sw_open(struct input_dev *dev)
+{
+	struct sw *sw = dev->private;
+	if (!sw->used++)
+		mod_timer(&sw->timer, jiffies + SW_REFRESH);
+	return 0;
+}
+
+static void sw_close(struct input_dev *dev)
+{
+	struct sw *sw = dev->private;
+	if (!--sw->used)
+		del_timer(&sw->timer);
+}
+
+/*
+ * sw_print_packet() prints the contents of a SideWinder packet.
+ */
+
+static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
+{
+	int i;
+
+	printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
+	for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
+		printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
+	printk("]\n");
+}
+
+/*
+ * sw_3dp_id() translates the 3DP id into a human legible string.
+ * Unfortunately I don't know how to do this for the other SW types.
+ */
+
+static void sw_3dp_id(unsigned char *buf, char *comment)
+{
+	int i;
+	char pnp[8], rev[9];
+
+	for (i = 0; i < 7; i++)						/* ASCII PnP ID */
+		pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
+
+	for (i = 0; i < 8; i++)						/* ASCII firmware revision */
+		rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
+
+	pnp[7] = rev[8] = 0;
+
+	sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |		/* Two 6-bit values */
+			sw_get_bits(buf, 16, 6, 1)) / 100,
+		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
+			sw_get_bits(buf, 16, 6, 1)) % 100,
+		 pnp, rev);
+}
+
+/*
+ * sw_guess_mode() checks the upper two button bits for toggling -
+ * indication of that the joystick is in 3-bit mode. This is documented
+ * behavior for 3DP ID packet, and for example the FSP does this in
+ * normal packets instead. Fun ...
+ */
+
+static int sw_guess_mode(unsigned char *buf, int len)
+{
+	int i;
+	unsigned char xor = 0;
+	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+	return !!xor * 2 + 1;
+}
+
+/*
+ * sw_connect() probes for SideWinder type joysticks.
+ */
+
+static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct sw *sw;
+	int i, j, k, l;
+	unsigned char buf[SW_LENGTH];
+	unsigned char idbuf[SW_LENGTH];
+	unsigned char m = 1;
+	char comment[40];
+
+	comment[0] = 0;
+
+	if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
+	memset(sw, 0, sizeof(struct sw));
+
+	gameport->private = sw;
+
+	sw->gameport = gameport;
+	init_timer(&sw->timer);
+	sw->timer.data = (long) sw;
+	sw->timer.function = sw_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	dbg("Init 0: Opened gameport %d, io %#x, speed %d",
+		gameport->number, gameport->io, gameport->speed);
+
+	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
+	m |= sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
+	udelay(SW_TIMEOUT);
+	dbg("Init 1: Mode %d. Length %d.", m , i);
+
+	if (!i) {							/* No data. 3d Pro analog mode? */
+		sw_init_digital(gameport);				/* Switch to digital */
+		udelay(SW_TIMEOUT);
+		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
+		udelay(SW_TIMEOUT);
+		dbg("Init 1b: Length %d.", i);
+		if (!i) goto fail2;					/* No data -> FAIL */
+	}
+
+	j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);		/* Read ID. This initializes the stick */
+	m |= sw_guess_mode(idbuf, j);					/* ID packet should carry mode info [3DP] */
+	dbg("Init 2: Mode %d. ID Length %d.", m , j);
+
+	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
+		udelay(SW_TIMEOUT);
+		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
+		dbg("Init 2b: Mode %d. Length %d.", m, i);
+		if (!i) goto fail2;
+		udelay(SW_TIMEOUT);
+		j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);	/* Retry reading ID */
+		dbg("Init 2c: ID Length %d.", j);
+	}
+
+	sw->type = -1;
+	k = SW_FAIL;							/* Try SW_FAIL times */
+	l = 0;
+
+	do {
+		k--;
+		udelay(SW_TIMEOUT);
+		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Read data packet */
+		dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
+
+		if (i > l) {						/* Longer? As we can only lose bits, it makes */
+									/* no sense to try detection for a packet shorter */
+			l = i;						/* than the previous one */
+
+			sw->number = 1;
+			sw->gameport = gameport;
+			sw->length = i;
+			sw->bits = m;
+
+			dbg("Init 3a: Case %d.\n", i * m);
+
+			switch (i * m) {
+				case 60:
+					sw->number++;
+				case 45:				/* Ambiguous packet length */
+					if (j <= 40) {			/* ID length less or eq 40 -> FSP */	
+				case 43:
+						sw->type = SW_ID_FSP;
+						break;
+					}
+					sw->number++;
+				case 30:
+					sw->number++;
+				case 15:
+					sw->type = SW_ID_GP;
+					break;
+				case 33:
+				case 31:
+					sw->type = SW_ID_FFW;
+					break;
+				case 48:				/* Ambiguous */
+					if (j == 14) {			/* ID length 14*3 -> FFP */
+						sw->type = SW_ID_FFP;
+						sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
+					} else
+					sw->type = SW_ID_PP;
+					break;
+				case 198:
+					sw->length = 22;
+				case 64:
+					sw->type = SW_ID_3DP;
+					if (j == 160) sw_3dp_id(idbuf, comment);
+					break;
+			}
+		}
+
+	} while (k && (sw->type == -1));
+
+	if (sw->type == -1) {
+		printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
+			"on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
+		sw_print_packet("ID", j * 3, idbuf, 3);
+		sw_print_packet("Data", i * m, buf, m);
+		goto fail2;
+	}
+
+#ifdef SW_DEBUG
+	sw_print_packet("ID", j * 3, idbuf, 3);
+	sw_print_packet("Data", i * m, buf, m);
+#endif
+
+	k = i;
+	l = j;
+
+	for (i = 0; i < sw->number; i++) {
+		int bits, code;
+
+		sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
+
+		sw->dev[i].private = sw;
+
+		sw->dev[i].open = sw_open;
+		sw->dev[i].close = sw_close;
+
+		sw->dev[i].name = sw->name;
+		sw->dev[i].idbus = BUS_GAMEPORT;
+		sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
+		sw->dev[i].idproduct = sw->type;
+		sw->dev[i].idversion = 0x0100;
+
+		sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+		for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
+			code = sw_abs[sw->type][j];
+			set_bit(code, sw->dev[i].absbit);
+			sw->dev[i].absmax[code] = (1 << bits) - 1;
+			sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
+			sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
+			if (code != ABS_THROTTLE)
+				sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
+		}
+
+		for (j = 0; (code = sw_btn[sw->type][j]); j++)
+			set_bit(code, sw->dev[i].keybit);
+
+		input_register_device(sw->dev + i);
+		printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
+			sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
+	}
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:	kfree(sw);
+}
+
+static void sw_disconnect(struct gameport *gameport)
+{
+	int i;
+
+	struct sw *sw = gameport->private;
+	for (i = 0; i < sw->number; i++)
+		input_unregister_device(sw->dev + i);
+	gameport_close(gameport);
+	kfree(sw);
+}
+
+static struct gameport_dev sw_dev = {
+	connect:	sw_connect,
+	disconnect:	sw_disconnect,
+};
+
+int __init sw_init(void)
+{
+	gameport_register_device(&sw_dev);
+	return 0;
+}
+
+void __exit sw_exit(void)
+{
+	gameport_unregister_device(&sw_dev);
+}
+
+module_init(sw_init);
+module_exit(sw_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/spaceball.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,238 @@
+/*
+ * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *  	David Thompson
+ *  	Joseph Krahn
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * SpaceTec SpaceBall 4000 FLX driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define JS_SBALL_MAX_LENGTH	128
+static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
+static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; 
+
+/*
+ * Per-Ball data.
+ */
+
+struct spaceball {
+	struct input_dev dev;
+	struct serio *serio;
+	int idx;
+	int escape;
+	unsigned char data[JS_SBALL_MAX_LENGTH];
+};
+
+/*
+ * spaceball_process_packet() decodes packets the driver receives from the
+ * SpaceBall.
+ */
+
+static void spaceball_process_packet(struct spaceball* spaceball)
+{
+	struct input_dev *dev = &spaceball->dev;
+	unsigned char *data = spaceball->data;
+	int i;
+
+	if (spaceball->idx < 2) return;
+
+	printk("%c %d\n", spaceball->data[0], spaceball->idx);
+
+	switch (spaceball->data[0]) {
+
+		case '@':					/* Reset packet */
+			spaceball->data[spaceball->idx - 1] = 0;
+			for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
+			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
+				spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
+			break;
+
+		case 'D':					/* Ball data */
+			if (spaceball->idx != 15) return;
+			for (i = 0; i < 6; i++) {
+				input_report_abs(dev, spaceball_axes[i], 
+					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+			}
+			break;
+
+		case '.':				/* Button data, part2 */
+			if (spaceball->idx != 3) return;
+			input_report_key(dev, BTN_0,  data[2] & 1);
+			input_report_key(dev, BTN_1, data[2] & 2);
+			break;
+
+		case '?':				/* Error packet */
+			spaceball->data[spaceball->idx - 1] = 0;
+			printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
+			break;
+	}
+}
+
+/*
+ * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
+ * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
+ * can occur in the axis values.
+ */
+
+static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct spaceball *spaceball = serio->private;
+
+	switch (data) {
+		case 0xd:
+			spaceball_process_packet(spaceball);
+			spaceball->idx = 0;
+			spaceball->escape = 0;
+			return;
+		case '^':
+			if (!spaceball->escape) {
+				spaceball->escape = 1;
+				return;
+			}
+			spaceball->escape = 0;
+		case 'M':
+		case 'Q':
+		case 'S':
+			if (spaceball->escape) {
+				spaceball->escape = 0;
+				data &= 0x1f;
+			}
+		default:
+			if (spaceball->escape) {
+				spaceball->escape = 0;
+				printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
+			}
+			if (spaceball->idx < JS_SBALL_MAX_LENGTH)
+				spaceball->data[spaceball->idx++] = data;
+			return;
+	}
+}
+
+/*
+ * spaceball_disconnect() is the opposite of spaceball_connect()
+ */
+
+static void spaceball_disconnect(struct serio *serio)
+{
+	struct spaceball* spaceball = serio->private;
+	input_unregister_device(&spaceball->dev);
+	serio_close(serio);
+	kfree(spaceball);
+}
+
+/*
+ * spaceball_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Magellan, and if found, registers
+ * it as an input device.
+ */
+
+static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct spaceball *spaceball;
+	int i, t;
+
+	if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
+		return;
+
+	if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
+		return;
+	memset(spaceball, 0, sizeof(struct spaceball));
+
+	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
+
+	for (i = 0; i < 6; i++) {
+		t = spaceball_axes[i];
+		set_bit(t, spaceball->dev.absbit);
+		spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
+		spaceball->dev.absmax[t] = i < 3 ?  8000 :  1600;
+		spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
+		spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
+	}
+
+	spaceball->serio = serio;
+	spaceball->dev.private = spaceball;
+
+	spaceball->dev.name = spaceball_name;
+	spaceball->dev.idbus = BUS_RS232;
+	spaceball->dev.idvendor = SERIO_SPACEBALL;
+	spaceball->dev.idproduct = 0x0001;
+	spaceball->dev.idversion = 0x0100;
+	
+	serio->private = spaceball;
+
+	if (serio_open(serio, dev)) {
+		kfree(spaceball);
+		return;
+	}
+
+	input_register_device(&spaceball->dev);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev spaceball_dev = {
+	interrupt:	spaceball_interrupt,
+	connect:	spaceball_connect,
+	disconnect:	spaceball_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init spaceball_init(void)
+{
+	serio_register_device(&spaceball_dev);
+	return 0;
+}
+
+void __exit spaceball_exit(void)
+{
+	serio_unregister_device(&spaceball_dev);
+}
+
+module_init(spaceball_init);
+module_exit(spaceball_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/spaceorb.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,227 @@
+/*
+ * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ * 
+ *  Based on the work of:
+ *  	David Thompson
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define SPACEORB_MAX_LENGTH	64
+
+static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
+static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *spaceorb_name = "SpaceTec SpaceOrb 360";
+
+/*
+ * Per-Orb data.
+ */
+
+struct spaceorb {
+	struct input_dev dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[SPACEORB_MAX_LENGTH];
+};
+
+static unsigned char spaceorb_xor[] = "SpaceWare";
+
+static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
+		"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; 
+
+/*
+ * spaceorb_process_packet() decodes packets the driver receives from the
+ * SpaceOrb.
+ */
+
+static void spaceorb_process_packet(struct spaceorb *spaceorb)
+{
+	struct input_dev *dev = &spaceorb->dev;
+	unsigned char *data = spaceorb->data;
+	unsigned char c = 0;
+	int axes[6];
+	int i;
+
+	if (spaceorb->idx < 2) return;
+	for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
+	if (c) return;
+
+	switch (data[0]) {
+
+		case 'R':				/* Reset packet */
+			spaceorb->data[spaceorb->idx - 1] = 0;
+			for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
+			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
+				 spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
+			break;
+
+		case 'D':				/* Ball + button data */
+			if (spaceorb->idx != 12) return;
+			for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; 
+			axes[0] = ( data[2]	 << 3) | (data[ 3] >> 4);
+			axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
+			axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
+			axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
+			axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
+			axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
+			for (i = 0; i < 6; i++)
+				input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
+			for (i = 0; i < 8; i++)
+				input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
+			break;
+
+		case 'K':				/* Button data */
+			if (spaceorb->idx != 5) return;
+			for (i = 0; i < 7; i++)
+				input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
+
+			break;
+
+		case 'E':				/* Error packet */
+			if (spaceorb->idx != 4) return;
+			printk(KERN_ERR "joy-spaceorb: Device error. [ ");
+			for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
+			printk("]\n");
+			break;
+	}
+}
+
+static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct spaceorb* spaceorb = serio->private;
+
+	if (~data & 0x80) {
+		if (spaceorb->idx) spaceorb_process_packet(spaceorb);
+		spaceorb->idx = 0;
+	}
+	if (spaceorb->idx < SPACEORB_MAX_LENGTH)
+		spaceorb->data[spaceorb->idx++] = data & 0x7f;
+}
+
+/*
+ * spaceorb_disconnect() is the opposite of spaceorb_connect()
+ */
+
+static void spaceorb_disconnect(struct serio *serio)
+{
+	struct spaceorb* spaceorb = serio->private;
+	input_unregister_device(&spaceorb->dev);
+	serio_close(serio);
+	kfree(spaceorb);
+}
+
+/*
+ * spaceorb_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
+ * it as an input device.
+ */
+
+static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct spaceorb *spaceorb;
+	int i, t;
+
+	if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
+		return;
+
+	if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
+		return;
+	memset(spaceorb, 0, sizeof(struct spaceorb));
+
+	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+
+	for (i = 0; i < 7; i++)
+		set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
+
+	for (i = 0; i < 6; i++) {
+		t = spaceorb_axes[i];
+		set_bit(t, spaceorb->dev.absbit);
+		spaceorb->dev.absmin[t] = -508;
+		spaceorb->dev.absmax[t] =  508;
+	}
+
+	spaceorb->serio = serio;
+	spaceorb->dev.private = spaceorb;
+
+	spaceorb->dev.name = spaceorb_name;
+	spaceorb->dev.idbus = BUS_RS232;
+	spaceorb->dev.idvendor = SERIO_SPACEORB;
+	spaceorb->dev.idproduct = 0x0001;
+	spaceorb->dev.idversion = 0x0100;
+	
+	serio->private = spaceorb;
+
+	if (serio_open(serio, dev)) {
+		kfree(spaceorb);
+		return;
+	}
+
+	input_register_device(&spaceorb->dev);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev spaceorb_dev = {
+	interrupt:	spaceorb_interrupt,
+	connect:	spaceorb_connect,
+	disconnect:	spaceorb_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init spaceorb_init(void)
+{
+	serio_register_device(&spaceorb_dev);
+	return 0;
+}
+
+void __exit spaceorb_exit(void)
+{
+	serio_unregister_device(&spaceorb_dev);
+}
+
+module_init(spaceorb_init);
+module_exit(spaceorb_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/stinger.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,202 @@
+/*
+ * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2000 Mark Fletcher
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Gravis Stinger gamepad driver for Linux
+ */
+
+/*
+ * This program is free warftware; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define STINGER_MAX_LENGTH 8
+
+static char *stinger_name = "Gravis Stinger";
+
+/*
+ * Per-Stinger data.
+ */
+
+struct stinger {
+	struct input_dev dev;
+	int idx;
+	unsigned char data[STINGER_MAX_LENGTH];
+};
+
+/*
+ * stinger_process_packet() decodes packets the driver receives from the
+ * Stinger. It updates the data accordingly.
+ */
+
+static void stinger_process_packet(struct stinger *stinger)
+{
+	struct input_dev *dev = &stinger->dev;
+	unsigned char *data = stinger->data;
+
+	if (!stinger->idx) return;
+
+	input_report_key(dev, BTN_A,	  ((data[0] & 0x20) >> 5));
+	input_report_key(dev, BTN_B,	  ((data[0] & 0x10) >> 4));
+	input_report_key(dev, BTN_C,	  ((data[0] & 0x08) >> 3));
+	input_report_key(dev, BTN_X,	  ((data[0] & 0x04) >> 2));
+	input_report_key(dev, BTN_Y,	  ((data[3] & 0x20) >> 5));
+	input_report_key(dev, BTN_Z,	  ((data[3] & 0x10) >> 4));
+	input_report_key(dev, BTN_TL,     ((data[3] & 0x08) >> 3));
+	input_report_key(dev, BTN_TR,     ((data[3] & 0x04) >> 2));
+	input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
+	input_report_key(dev, BTN_START,   (data[3] & 0x01));
+
+	input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
+	input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
+
+	return;
+}
+
+/*
+ * stinger_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct stinger* stinger = serio->private;
+
+	/* All Stinger packets are 4 bytes */
+
+	if (stinger->idx < STINGER_MAX_LENGTH)
+		stinger->data[stinger->idx++] = data;
+
+	if (stinger->idx == 4) {
+		stinger_process_packet(stinger);
+		stinger->idx = 0;
+	}
+
+	return;
+}
+
+/*
+ * stinger_disconnect() is the opposite of stinger_connect()
+ */
+
+static void stinger_disconnect(struct serio *serio)
+{
+	struct stinger* stinger = serio->private;
+	input_unregister_device(&stinger->dev);
+	serio_close(serio);
+	kfree(stinger);
+}
+
+/*
+ * stinger_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Stinger, and if found, registers
+ * it as an input device.
+ */
+
+static void stinger_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct stinger *stinger;
+	int i;
+
+	if (serio->type != (SERIO_RS232 | SERIO_STINGER))
+		return;
+
+	if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
+		return;
+
+	memset(stinger, 0, sizeof(struct stinger));
+
+	stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
+					   BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
+					   BIT(BTN_START) | BIT(BTN_SELECT);
+	stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+	stinger->dev.name = stinger_name;
+	stinger->dev.idbus = BUS_RS232;
+	stinger->dev.idvendor = SERIO_STINGER;
+	stinger->dev.idproduct = 0x0001;
+	stinger->dev.idversion = 0x0100;
+
+	for (i = 0; i < 2; i++) {
+		stinger->dev.absmax[ABS_X+i] =  64;	
+		stinger->dev.absmin[ABS_X+i] = -64;	
+		stinger->dev.absflat[ABS_X+i] = 4;
+	}
+
+	stinger->dev.private = stinger;
+	
+	serio->private = stinger;
+
+	if (serio_open(serio, dev)) {
+		kfree(stinger);
+		return;
+	}
+
+	input_register_device(&stinger->dev);
+
+	printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev stinger_dev = {
+	interrupt:	stinger_interrupt,
+	connect:	stinger_connect,
+	disconnect:	stinger_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init stinger_init(void)
+{
+	serio_register_device(&stinger_dev);
+	return 0;
+}
+
+void __exit stinger_exit(void)
+{
+	serio_unregister_device(&stinger_dev);
+}
+
+module_init(stinger_init);
+module_exit(stinger_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/tmdc.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,378 @@
+/*
+ * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ *
+ *   Based on the work of:
+ *	Trystan Larey-Williams 
+ *
+ */
+
+/*
+ * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define TMDC_MAX_START		400	/* 400 us */
+#define TMDC_MAX_STROBE		45	/* 45 us */
+#define TMDC_MAX_LENGTH		13
+#define TMDC_REFRESH_TIME	HZ/50	/* 20 ms */
+
+#define TMDC_MODE_M3DI		1
+#define TMDC_MODE_3DRP		3
+#define TMDC_MODE_AT		4
+#define TMDC_MODE_FM		8
+#define TMDC_MODE_FGP		163
+
+#define TMDC_BYTE_ID		10
+#define TMDC_BYTE_REV		11
+#define TMDC_BYTE_DEF		12
+
+#define TMDC_ABS		7	
+#define TMDC_ABS_HAT		4
+#define TMDC_BTN		16
+
+static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
+static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
+
+static signed char tmdc_abs[TMDC_ABS] =
+	{ ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
+static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
+	{ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static signed char tmdc_abs_at[TMDC_ABS] =
+	{ ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
+static signed char tmdc_abs_fm[TMDC_ABS] =
+	{ ABS_RX, ABS_RY, ABS_X, ABS_Y };
+
+static short tmdc_btn_pad[TMDC_BTN] =
+	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
+static short tmdc_btn_joy[TMDC_BTN] =
+	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
+ 	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+static short tmdc_btn_fm[TMDC_BTN] =
+        { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
+static short tmdc_btn_at[TMDC_BTN] =
+        { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
+          BTN_BASE3, BTN_BASE2, BTN_BASE };
+
+static struct {
+        int x;
+        int y;
+} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
+
+struct tmdc {
+	struct gameport *gameport;
+	struct timer_list timer;
+	struct input_dev dev[2];
+	char name[2][64];
+	int mode[2];
+	signed char *abs[2];
+	short *btn[2];
+	unsigned char absc[2];
+	unsigned char btnc[2][4];
+	unsigned char btno[2][4];
+	int used;
+	int reads;
+	int bads;	
+	unsigned char exists;
+};
+
+/*
+ * tmdc_read_packet() reads a ThrustMaster packet.
+ */
+
+static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
+{
+	unsigned char u, v, w, x;
+	unsigned long flags;
+	int i[2], j[2], t[2], p, k;
+
+	p = gameport_time(gameport, TMDC_MAX_STROBE);
+
+	for (k = 0; k < 2; k++) {
+		t[k] = gameport_time(gameport, TMDC_MAX_START);
+		i[k] = j[k] = 0;
+	}
+
+	__save_flags(flags);
+	__cli();
+	gameport_trigger(gameport);
+	
+	w = gameport_read(gameport) >> 4;
+
+	do {
+		x = w;
+		w = gameport_read(gameport) >> 4;
+
+		for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
+			if (~v & u & 2) {
+				if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
+				t[k] = p;
+				if (j[k] == 0) {				 /* Start bit */
+					if (~v & 1) t[k] = 0;
+					data[k][i[k]] = 0; j[k]++; continue;
+				}
+				if (j[k] == 9) {				/* Stop bit */
+					if (v & 1) t[k] = 0;
+					j[k] = 0; i[k]++; continue;
+				}
+				data[k][i[k]] |= (~v & 1) << (j[k]++ - 1);	/* Data bit */
+			}
+			t[k]--; 
+		}
+	} while (t[0] > 0 || t[1] > 0);
+
+	__restore_flags(flags);
+
+	return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
+}
+
+/*
+ * tmdc_read() reads and analyzes ThrustMaster joystick data.
+ */
+
+static void tmdc_timer(unsigned long private)
+{
+	unsigned char data[2][TMDC_MAX_LENGTH];
+	struct tmdc *tmdc = (void *) private;
+	struct input_dev *dev;
+	unsigned char r, bad = 0;
+	int i, j, k, l;
+
+	tmdc->reads++;
+
+	if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
+		bad = 1;
+
+	for (j = 0; j < 2; j++) 
+		if (r & (1 << j) & tmdc->exists) {
+
+			if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
+				bad = 1;
+				continue;
+			}
+
+			dev = tmdc->dev + j;
+
+			for (i = 0; i < tmdc->absc[j]; i++) {
+				if (tmdc->abs[j][i] < 0) continue;
+				input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
+			}
+
+			switch (tmdc->mode[j]) {
+
+				case TMDC_MODE_M3DI:
+
+					i = tmdc_byte_d[0];
+					input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
+					input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i]       & 1));
+					break;
+
+				case TMDC_MODE_AT:
+
+					i = tmdc_byte_a[3];
+					input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
+					input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
+					break;
+
+			}
+
+			for (k = l = 0; k < 4; k++) {
+				for (i = 0; i < tmdc->btnc[j][k]; i++)
+					input_report_key(dev, tmdc->btn[j][i + l],
+						((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
+				l += tmdc->btnc[j][k];
+			}
+	}
+
+	tmdc->bads += bad;
+
+	mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
+}
+
+static int tmdc_open(struct input_dev *dev)
+{
+	struct tmdc *tmdc = dev->private;
+	if (!tmdc->used++)
+		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);	
+	return 0;
+}
+
+static void tmdc_close(struct input_dev *dev)
+{
+	struct tmdc *tmdc = dev->private;
+	if (!--tmdc->used)
+		del_timer(&tmdc->timer);
+}
+
+/*
+ * tmdc_probe() probes for ThrustMaster type joysticks.
+ */
+
+static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct models {
+		unsigned char id;
+		char *name;
+		char abs;
+		char hats;
+		char btnc[4];
+		char btno[4];
+		signed char *axes;
+		short *buttons;
+	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor",	  6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
+			{   3, "ThrustMaster Rage 3D Gamepad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+			{   4, "ThrustMaster Attack Throttle",		  5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
+			{   8, "ThrustMaster FragMaster",		  4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
+			{ 163, "Thrustmaster Fusion GamePad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+			{   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
+
+	unsigned char data[2][TMDC_MAX_LENGTH];
+	struct tmdc *tmdc;
+	int i, j, k, l, m;
+
+	if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
+		return;
+	memset(tmdc, 0, sizeof(struct tmdc));
+
+	gameport->private = tmdc;
+
+	tmdc->gameport = gameport;
+	init_timer(&tmdc->timer);
+	tmdc->timer.data = (long) tmdc;
+	tmdc->timer.function = tmdc_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
+		goto fail2;
+
+	for (j = 0; j < 2; j++)
+		if (tmdc->exists & (1 << j)) {
+
+			tmdc->mode[j] = data[j][TMDC_BYTE_ID];
+
+			for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
+
+			tmdc->abs[j] = models[m].axes;
+			tmdc->btn[j] = models[m].buttons;
+
+			if (!models[m].id) {
+				models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
+				for (k = 0; k < 4; k++)
+					models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
+			}
+
+			tmdc->absc[j] = models[m].abs;
+			for (k = 0; k < 4; k++) {
+				tmdc->btnc[j][k] = models[m].btnc[k];
+				tmdc->btno[j][k] = models[m].btno[k];
+			}
+
+			sprintf(tmdc->name[j], models[m].name, models[m].abs,
+				(data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
+
+			tmdc->dev[j].private = tmdc;
+			tmdc->dev[j].open = tmdc_open;
+			tmdc->dev[j].close = tmdc_close;
+
+			tmdc->dev[j].name = tmdc->name[j];
+			tmdc->dev[j].idbus = BUS_GAMEPORT;
+			tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
+			tmdc->dev[j].idproduct = models[m].id;
+			tmdc->dev[j].idversion = 0x0100;
+
+			tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
+				if (tmdc->abs[i] < 0) continue;
+				set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
+				tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
+				tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
+				tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
+				tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
+			}
+
+			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
+				set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
+				tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
+				tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
+			}
+
+			for (k = l = 0; k < 4; k++) {
+				for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
+					set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
+				l += models[m].btnc[k];
+			}
+
+			input_register_device(tmdc->dev + j);
+			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+				tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
+		}
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:	kfree(tmdc);
+}
+
+static void tmdc_disconnect(struct gameport *gameport)
+{
+	struct tmdc *tmdc = gameport->private;
+	int i;
+	for (i = 0; i < 2; i++)
+		if (tmdc->exists & (1 << i)) 
+			input_unregister_device(tmdc->dev + i);
+	gameport_close(gameport);
+	kfree(tmdc);
+}
+
+static struct gameport_dev tmdc_dev = {
+	connect:	tmdc_connect,
+	disconnect:	tmdc_disconnect,
+};
+
+int __init tmdc_init(void)
+{
+	gameport_register_device(&tmdc_dev);
+	return 0;
+}
+
+void __exit tmdc_exit(void)
+{
+	gameport_unregister_device(&tmdc_dev);
+}
+
+module_init(tmdc_init);
+module_exit(tmdc_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/turbografx.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,259 @@
+/*
+ * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
+ *
+ *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Steffen Schwenke
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * TurboGraFX parallel port interface driver for Linux.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(tgfx, "2-8i");
+MODULE_PARM(tgfx_2, "2-8i");
+MODULE_PARM(tgfx_3, "2-8i");
+
+#define TGFX_REFRESH_TIME	HZ/100	/* 10 ms */
+
+#define TGFX_TRIGGER		0x08
+#define TGFX_UP			0x10
+#define TGFX_DOWN		0x20	
+#define TGFX_LEFT		0x40
+#define TGFX_RIGHT		0x80
+
+#define TGFX_THUMB		0x02
+#define TGFX_THUMB2		0x04
+#define TGFX_TOP		0x01
+#define TGFX_TOP2		0x08
+
+static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+
+static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
+static char *tgfx_name = "TurboGraFX Multisystem joystick";
+
+struct tgfx {
+	struct pardevice *pd;
+	struct timer_list timer;
+	struct input_dev dev[7];
+	int sticks;
+	int used;
+} *tgfx_base[3];
+
+/*
+ * tgfx_timer() reads and analyzes TurboGraFX joystick data.
+ */
+
+static void tgfx_timer(unsigned long private)
+{
+	struct tgfx *tgfx = (void *) private;
+	struct input_dev *dev;
+	int data1, data2, i;
+
+	for (i = 0; i < 7; i++)
+		if (tgfx->sticks & (1 << i)) {
+
+ 			dev = tgfx->dev + i;
+
+			parport_write_data(tgfx->pd->port, ~(1 << i));
+			data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
+			data2 = parport_read_control(tgfx->pd->port) ^ 0x04;	/* CAVEAT parport */
+
+			input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT));
+			input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP  ));
+
+			input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER));
+			input_report_key(dev, BTN_THUMB,   (data2 & TGFX_THUMB  ));
+			input_report_key(dev, BTN_THUMB2,  (data2 & TGFX_THUMB2 ));
+			input_report_key(dev, BTN_TOP,     (data2 & TGFX_TOP    ));
+			input_report_key(dev, BTN_TOP2,    (data2 & TGFX_TOP2   ));
+		}
+
+	mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+}
+
+static int tgfx_open(struct input_dev *dev)
+{
+        struct tgfx *tgfx = dev->private;
+        if (!tgfx->used++) {
+		parport_claim(tgfx->pd);
+		parport_write_control(tgfx->pd->port, 0x04);
+                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); 
+	}
+        return 0;
+}
+
+static void tgfx_close(struct input_dev *dev)
+{
+        struct tgfx *tgfx = dev->private;
+        if (!--tgfx->used) {
+                del_timer(&tgfx->timer);
+		parport_write_control(tgfx->pd->port, 0x00);
+        	parport_release(tgfx->pd);
+	}
+}
+
+/*
+ * tgfx_probe() probes for tg gamepads.
+ */
+
+static struct tgfx __init *tgfx_probe(int *config)
+{
+	struct tgfx *tgfx;
+	struct parport *pp;
+	int i, j;
+
+	if (config[0] < 0)
+		return NULL;
+
+	for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+		config[0]--;
+
+	if (!pp) {
+		printk(KERN_ERR "turbografx.c: no such parport\n");
+		return NULL;
+	}
+
+	if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL)))
+		return NULL;
+	memset(tgfx, 0, sizeof(struct tgfx));
+
+	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+	if (!tgfx->pd) {
+		printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
+		kfree(tgfx);
+		return NULL;
+	}
+
+	init_timer(&tgfx->timer);
+	tgfx->timer.data = (long) tgfx;
+	tgfx->timer.function = tgfx_timer;
+
+	tgfx->sticks = 0;
+
+	for (i = 0; i < 7; i++)
+		if (config[i+1] > 0 && config[i+1] < 6) {
+
+			tgfx->sticks |= (1 << i);
+
+			tgfx->dev[i].private = tgfx;
+			tgfx->dev[i].open = tgfx_open;
+			tgfx->dev[i].close = tgfx_close;
+
+			tgfx->dev[i].name = tgfx_name;
+			tgfx->dev[i].idbus = BUS_PARPORT;
+			tgfx->dev[i].idvendor = 0x0003;
+			tgfx->dev[i].idproduct = config[i+1];
+			tgfx->dev[i].idversion = 0x0100;
+
+			tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+			tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+			for (j = 0; j < config[i+1]; j++)
+				set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); 
+
+			tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
+			tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
+
+			input_register_device(tgfx->dev + i);
+			printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n",
+				tgfx->dev[i].number, config[i+1], tgfx->pd->port->name);
+		}
+
+        if (!tgfx->sticks) {
+		parport_unregister_device(tgfx->pd);
+		kfree(tgfx);
+		return NULL;
+        }
+		
+	return tgfx;
+}
+
+#ifndef MODULE
+int __init tgfx_setup(char *str)
+{
+	int i, ints[9];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1];
+	return 1;
+}
+int __init tgfx_setup_2(char *str)
+{
+	int i, ints[9];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1];
+	return 1;
+}
+int __init tgfx_setup_3(char *str)
+{
+	int i, ints[9];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1];
+	return 1;
+}
+__setup("tgfx=", tgfx_setup);
+__setup("tgfx_2=", tgfx_setup_2);
+__setup("tgfx_3=", tgfx_setup_3);
+#endif
+
+int __init tgfx_init(void)
+{
+	tgfx_base[0] = tgfx_probe(tgfx);
+	tgfx_base[1] = tgfx_probe(tgfx_2);
+	tgfx_base[2] = tgfx_probe(tgfx_3);
+
+	if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
+		return 0;
+
+	return -ENODEV;
+}
+
+void __exit tgfx_exit(void)
+{
+	int i, j;
+
+	for (i = 0; i < 3; i++) 
+		if (tgfx_base[i]) {
+			for (j = 0; j < 7; j++)
+				if (tgfx_base[i]->sticks & (1 << j))
+					input_unregister_device(tgfx_base[i]->dev + j);
+		parport_unregister_device(tgfx_base[i]->pd);
+	}
+}
+
+module_init(tgfx_init);
+module_exit(tgfx_exit);
diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/warrior.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,214 @@
+/*
+ * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * Logitech WingMan Warrior joystick driver for Linux
+ */
+
+/*
+ * This program is free warftware; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define WARRIOR_MAX_LENGTH	16
+static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; 
+static char *warrior_name = "Logitech WingMan Warrior";
+
+/*
+ * Per-Warrior data.
+ */
+
+struct warrior {
+	struct input_dev dev;
+	int idx, len;
+	unsigned char data[WARRIOR_MAX_LENGTH];
+};
+
+/*
+ * warrior_process_packet() decodes packets the driver receives from the
+ * Warrior. It updates the data accordingly.
+ */
+
+static void warrior_process_packet(struct warrior *warrior)
+{
+	struct input_dev *dev = &warrior->dev;
+	unsigned char *data = warrior->data;
+
+	if (!warrior->idx) return;
+
+	switch ((data[0] >> 4) & 7) {
+		case 1:					/* Button data */
+			input_report_key(dev, BTN_TRIGGER,  data[3]       & 1);
+			input_report_key(dev, BTN_THUMB,   (data[3] >> 1) & 1);
+			input_report_key(dev, BTN_TOP,     (data[3] >> 2) & 1);
+			input_report_key(dev, BTN_TOP2,    (data[3] >> 3) & 1);
+			return;
+		case 3:					/* XY-axis info->data */
+			input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
+			input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
+			return;
+		case 5:					/* Throttle, spinner, hat info->data */
+			input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
+			input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
+			input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
+			input_report_rel(dev, REL_DIAL,  (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
+			return;
+	}
+}
+
+/*
+ * warrior_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct warrior* warrior = serio->private;
+
+	if (data & 0x80) {
+		if (warrior->idx) warrior_process_packet(warrior);
+		warrior->idx = 0;
+		warrior->len = warrior_lengths[(data >> 4) & 7];
+	}
+
+	if (warrior->idx < warrior->len)
+		warrior->data[warrior->idx++] = data;
+
+	if (warrior->idx == warrior->len) {
+		if (warrior->idx) warrior_process_packet(warrior);	
+		warrior->idx = 0;
+		warrior->len = 0;
+	}
+}
+
+/*
+ * warrior_disconnect() is the opposite of warrior_connect()
+ */
+
+static void warrior_disconnect(struct serio *serio)
+{
+	struct warrior* warrior = serio->private;
+	input_unregister_device(&warrior->dev);
+	serio_close(serio);
+	kfree(warrior);
+}
+
+/*
+ * warrior_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Warrior, and if found, registers
+ * it as an input device.
+ */
+
+static void warrior_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct warrior *warrior;
+	int i;
+
+	if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
+		return;
+
+	if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
+		return;
+
+	memset(warrior, 0, sizeof(struct warrior));
+
+	warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);	
+	warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
+	warrior->dev.relbit[0] = BIT(REL_DIAL);
+	warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
+
+	warrior->dev.name = warrior_name;
+	warrior->dev.idbus = BUS_RS232;
+	warrior->dev.idvendor = SERIO_WARRIOR;
+	warrior->dev.idproduct = 0x0001;
+	warrior->dev.idversion = 0x0100;
+
+	for (i = 0; i < 2; i++) {
+		warrior->dev.absmax[ABS_X+i] = -64;	
+		warrior->dev.absmin[ABS_X+i] =  64;	
+		warrior->dev.absflat[ABS_X+i] = 8;	
+	}
+
+	warrior->dev.absmax[ABS_THROTTLE] = -112;	
+	warrior->dev.absmin[ABS_THROTTLE] =  112;	
+
+	for (i = 0; i < 2; i++) {
+		warrior->dev.absmax[ABS_HAT0X+i] = -1;	
+		warrior->dev.absmin[ABS_HAT0X+i] =  1;	
+	}
+
+	warrior->dev.private = warrior;
+	
+	serio->private = warrior;
+
+	if (serio_open(serio, dev)) {
+		kfree(warrior);
+		return;
+	}
+
+	input_register_device(&warrior->dev);
+
+	printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev warrior_dev = {
+	interrupt:	warrior_interrupt,
+	connect:	warrior_connect,
+	disconnect:	warrior_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init warrior_init(void)
+{
+	serio_register_device(&warrior_dev);
+	return 0;
+}
+
+void __exit warrior_exit(void)
+{
+	serio_unregister_device(&warrior_dev);
+}
+
+module_init(warrior_init);
+module_exit(warrior_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/serio/Config.help b/drivers/input/serio/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/Config.help	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,26 @@
+CONFIG_SERIO
+  Say Yes here if you have any input device that uses serial I/O to
+  communicate with the system. This includes the 
+		* standard AT keyboard and PS/2 mouse *
+  as well as serial mice, Sun keyboards, some joysticks and 6dof
+  devices and more.
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called serio.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_SERPORT
+  Say Y here if you plan to use an input device (mouse, joystick,
+  tablet, 6dof) that communicates over the RS232 serial (COM) port.
+ 
+  More information is available: <file:Documentation/input/input.txt>
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called serport.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/Config.in	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,7 @@
+#
+# Input core configuration
+#
+
+tristate 'Serial i/o support' CONFIG_SERIO
+
+dep_tristate '  Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO 
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/Makefile	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for the input core drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET	:= seriodrv.o
+
+# Objects that export symbols.
+
+export-objs	:= serio.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_SERIO)		+= serio.o
+obj-$(CONFIG_SERIO_SERPORT)	+= serport.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/serio.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,133 @@
+/*
+ * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ *  The Serio abstraction module
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_register_device);
+EXPORT_SYMBOL(serio_unregister_device);
+EXPORT_SYMBOL(serio_open);
+EXPORT_SYMBOL(serio_close);
+EXPORT_SYMBOL(serio_rescan);
+
+static struct serio *serio_list;
+static struct serio_dev *serio_dev;
+static int serio_number;
+
+static void serio_find_dev(struct serio *serio)
+{
+        struct serio_dev *dev = serio_dev;
+
+        while (dev && !serio->dev) {
+		if (dev->connect)
+                	dev->connect(serio, dev);
+                dev = dev->next;
+        }
+}
+
+void serio_rescan(struct serio *serio)
+{
+	if (serio->dev && serio->dev->disconnect)
+		serio->dev->disconnect(serio);
+	serio_find_dev(serio);
+}
+
+void serio_register_port(struct serio *serio)
+{
+	serio->number = serio_number++;
+	serio->next = serio_list;	
+	serio_list = serio;
+	serio_find_dev(serio);
+}
+
+void serio_unregister_port(struct serio *serio)
+{
+        struct serio **serioptr = &serio_list;
+
+        while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
+        *serioptr = (*serioptr)->next;
+
+	if (serio->dev && serio->dev->disconnect)
+		serio->dev->disconnect(serio);
+
+	serio_number--;
+}
+
+void serio_register_device(struct serio_dev *dev)
+{
+	struct serio *serio = serio_list;
+
+	dev->next = serio_dev;	
+	serio_dev = dev;
+
+	while (serio) {
+		if (!serio->dev && dev->connect)
+			dev->connect(serio, dev);
+		serio = serio->next;
+	}
+}
+
+void serio_unregister_device(struct serio_dev *dev)
+{
+        struct serio_dev **devptr = &serio_dev;
+	struct serio *serio = serio_list;
+
+        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
+        *devptr = (*devptr)->next;
+
+	while (serio) {
+		if (serio->dev == dev && dev->disconnect)
+			dev->disconnect(serio);
+		serio_find_dev(serio);
+		serio = serio->next;
+	}
+}
+
+int serio_open(struct serio *serio, struct serio_dev *dev)
+{
+	if (serio->open(serio))
+		return -1;
+	serio->dev = dev;
+	return 0;
+}
+
+void serio_close(struct serio *serio)
+{
+	serio->close(serio);
+	serio->dev = NULL;
+}
diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/serport.c	Tue Feb  5 19:17:21 2002
@@ -0,0 +1,226 @@
+/*
+ * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module that converts a tty line into a much simpler
+ * 'serial io port' abstraction that the input device drivers use.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/tty.h>
+
+struct serport {
+	struct tty_struct *tty;
+	wait_queue_head_t wait;
+	struct serio serio;
+};
+
+/*
+ * Callback functions from the serio code.
+ */
+
+static int serport_serio_write(struct serio *serio, unsigned char data)
+{
+	struct serport *serport = serio->driver;
+	return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
+}
+
+static int serport_serio_open(struct serio *serio)
+{
+        return 0;
+}
+
+static void serport_serio_close(struct serio *serio)
+{
+	struct serport *serport = serio->driver;
+	wake_up_interruptible(&serport->wait);
+}
+
+/*
+ * serport_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty. It looks for the Mag, and if found, registers
+ * it as a joystick device.
+ */
+
+static int serport_ldisc_open(struct tty_struct *tty)
+{
+	struct serport *serport;
+
+	MOD_INC_USE_COUNT;
+
+	if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	memset(serport, 0, sizeof(struct serport));
+
+	serport->tty = tty;
+	tty->disc_data = serport;
+
+	serport->serio.type = SERIO_RS232;
+	serport->serio.write = serport_serio_write;
+	serport->serio.open = serport_serio_open;
+	serport->serio.close = serport_serio_close;
+	serport->serio.driver = serport;
+
+	init_waitqueue_head(&serport->wait);
+
+	return 0;
+}
+
+/*
+ * serport_ldisc_close() is the opposite of serport_ldisc_open()
+ */
+
+static void serport_ldisc_close(struct tty_struct *tty)
+{
+	struct serport *serport = (struct serport*) tty->disc_data;
+	kfree(serport);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * serport_ldisc_receive() is called by the low level tty driver when characters
+ * are ready for us. We forward the characters, one by one to the 'interrupt'
+ * routine.
+ */
+
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct serport *serport = (struct serport*) tty->disc_data;
+	int i;
+	for (i = 0; i < count; i++)
+		if (serport->serio.dev)
+			serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
+}
+
+/*
+ * serport_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, and 256 seems to be reasonable.
+ */
+
+static int serport_ldisc_room(struct tty_struct *tty)
+{
+	return 256;
+}
+
+/*
+ * serport_ldisc_read() just waits indefinitely if everything goes well. 
+ * However, when the serio driver closes the serio port, it finishes,
+ * returning 0 characters.
+ */
+
+static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
+{
+	struct serport *serport = (struct serport*) tty->disc_data;
+	DECLARE_WAITQUEUE(wait, current);
+	char name[32];
+
+#ifdef CONFIG_DEVFS_FS
+	sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
+#else
+	sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
+#endif
+
+	serio_register_port(&serport->serio);
+
+	printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
+
+	add_wait_queue(&serport->wait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	while(serport->serio.type && !signal_pending(current)) schedule();
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&serport->wait, &wait);
+
+	serio_unregister_port(&serport->serio);
+
+	return 0;
+}
+
+/*
+ * serport_ldisc_ioctl() allows to set the port protocol, and device ID
+ */
+
+static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct serport *serport = (struct serport*) tty->disc_data;
+	
+	switch (cmd) {
+		case SPIOCSTYPE:
+			return get_user(serport->serio.type, (unsigned long *) arg);
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc serport_ldisc = {
+	name:		"input",
+	open:		serport_ldisc_open,
+	close:		serport_ldisc_close,
+	read:		serport_ldisc_read,
+	ioctl:		serport_ldisc_ioctl,
+	receive_buf:	serport_ldisc_receive,
+	receive_room:	serport_ldisc_room,
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init serport_init(void)
+{
+        if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
+                printk(KERN_ERR "serport.c: Error registering line discipline.\n");
+		return -ENODEV;
+	}
+
+	return  0;
+}
+
+void __exit serport_exit(void)
+{
+	tty_register_ldisc(N_MOUSE, NULL);
+}
+
+module_init(serport_init);
+module_exit(serport_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
--- a/drivers/isdn/hisax/elsa.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/hisax/elsa.c	Tue Feb  5 19:17:21 2002
@@ -396,7 +396,8 @@
 	}
 	if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) {
 		val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
-		if (!(val & ELSA_PCI_IRQ_MASK))
+		if (!test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags) && 
+		    !(val & ELSA_PCI_IRQ_MASK))
 			return;
 	}
 #if ARCOFI_USE
@@ -868,7 +869,7 @@
 {
 	long flags;
 	int bytecnt;
-	u_char val;
+	u_char val, pci_rev;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
@@ -992,6 +993,7 @@
 			cs->irq = dev_qs1000->irq;
 			cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
 			cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+			pci_read_config_byte(dev_qs1000, PCI_REVISION_ID, &pci_rev);
 		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
 			PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
 			if (pci_enable_device(dev_qs3000))
@@ -1000,6 +1002,7 @@
 			cs->irq = dev_qs3000->irq;
 			cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
 			cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+			pci_read_config_byte(dev_qs1000, PCI_REVISION_ID, &pci_rev);
 		} else {
 			printk(KERN_WARNING "Elsa: No PCI card found\n");
 			return(0);
@@ -1013,15 +1016,9 @@
 			printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
 			return(0);
 		}
-		if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
-			printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
-			printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
-			printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
-			printk(KERN_WARNING "Elsa: Waiting 5 sec to sync discs\n");
-			save_flags(flags);
-			sti();
-			HZDELAY(500);	/* wait 500*10 ms */
-			restore_flags(flags);
+		if (cs->hw.elsa.cfg & 0x80 && pci_rev == 1) {
+			printk(KERN_INFO "Elsa: PLX9050 rev1 workaround activated");
+			set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags);
 		}
 		cs->hw.elsa.ale  = cs->hw.elsa.base;
 		cs->hw.elsa.isac = cs->hw.elsa.base +1;
diff -Nru a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
--- a/drivers/isdn/hisax/gazel.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/hisax/gazel.c	Tue Feb  5 19:17:21 2002
@@ -382,12 +382,16 @@
 			outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
 			break;
 		case R753:
-			plxcntrl = inl(addr + PLX_CNTRL);
+			if (test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags))
+				/* we can't read, assume the default */
+				plxcntrl = 0x18784db6;
+			else
+				plxcntrl = inl(addr + PLX_CNTRL);
 			plxcntrl |= (RESET_9050 + RESET_GAZEL);
 			outl(plxcntrl, addr + PLX_CNTRL);
-			plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
 			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
 			HZDELAY(4);
+			plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
 			outl(plxcntrl, addr + PLX_CNTRL);
 			HZDELAY(10);
 			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
@@ -549,6 +553,7 @@
 	u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
 	u_char pci_irq = 0, found;
 	u_int nbseek, seekcard;
+	u_char pci_rev;
 
 	printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
 
@@ -623,6 +628,18 @@
 			printk(KERN_INFO
 			    "Gazel: config irq:%d ipac:0x%X  cfg:0x%X\n",
 			cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
+			/* 
+			 * Erratum for PLX9050, revision 1:
+			 * If bit 7 of BAR 0/1 is set, local config registers
+			 * can not be read (write is okay)
+			 */
+			if (cs->hw.gazel.cfg_reg & 0x80) {
+				pci_read_config_byte(dev_tel, PCI_REVISION_ID, &pci_rev);
+				if (pci_rev == 1) {
+					printk(KERN_INFO "Gazel: PLX9050 rev1 workaround activated");
+					set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags);
+				}
+			}
 			break;
 	}
 
diff -Nru a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
--- a/drivers/isdn/hisax/hisax.h	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/hisax/hisax.h	Tue Feb  5 19:17:21 2002
@@ -859,6 +859,7 @@
 #define FLG_ARCOFI_TIMER	8
 #define FLG_ARCOFI_ERROR	9
 #define FLG_HW_L1_UINT		10
+#define FLG_BUGGY_PLX9050       11
 
 struct IsdnCardState {
 	unsigned char typ;
diff -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c	Tue Feb  5 19:17:21 2002
@@ -20,6 +20,7 @@
  *
  * o POWER PC
  * o clean up debugging
+ * o tx_skb at PH_DEACTIVATE time
  */
 
 #include <linux/version.h>
@@ -368,10 +369,7 @@
 	unsigned long flags;
 	unsigned char *p;
 
-	DBG(0x40, "hdlc_fill_fifo");
-
-	if (!skb)
-		BUG();
+	DBG(0x40, "");
 
 	if (skb->len == 0)
 		BUG();
@@ -581,14 +579,14 @@
 		adapter->write_ctrl(bcs, 5);
 		break;
 	case L1_MODE_TRANS:
-		bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
-		adapter->write_ctrl(bcs, 5);
-		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
-		adapter->write_ctrl(bcs, 1);
-		bcs->ctrl.sr.cmd = 0;
-		break;
 	case L1_MODE_HDLC:
-		bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+		bcs->rcvidx = 0;
+		bcs->tx_cnt = 0;
+		bcs->tx_skb = NULL;
+		if (mode == L1_MODE_TRANS)
+			bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+		else
+			bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
 		adapter->write_ctrl(bcs, 5);
 		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
 		adapter->write_ctrl(bcs, 1);
diff -Nru a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
--- a/drivers/isdn/isdn_audio.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/isdn_audio.c	Tue Feb  5 19:17:21 2002
@@ -227,8 +227,10 @@
 	:	"0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
 	:	"memory", "ax");
 #else
-	while (n--)
-		*buff++ = table[*(unsigned char *)buff];
+	while (n--) {
+		*buff = table[*buff];
+		buff++;
+	}
 #endif
 }
 
diff -Nru a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
--- a/drivers/isdn/isdn_common.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/isdn_common.c	Tue Feb  5 19:17:21 2002
@@ -2178,7 +2178,6 @@
 
 static void isdn_unregister_devfs(int k)
 {
-	devfs_unregister (dev->devfs_handle_isdnX[k]);
 	devfs_unregister (dev->devfs_handle_isdnctrlX[k]);
 }
 
@@ -2226,22 +2225,18 @@
 #else   /* CONFIG_DEVFS_FS */
 static void isdn_register_devfs(int dummy)
 {
-	return;
 }
 
 static void isdn_unregister_devfs(int dummy)
 {
-	return;
 }
 
 static void isdn_init_devfs(void)
 {
-    return;
 }
 
 static void isdn_cleanup_devfs(void)
 {
-    return;
 }
 
 #endif  /* CONFIG_DEVFS_FS */
diff -Nru a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
--- a/drivers/isdn/isdn_net.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/isdn/isdn_net.c	Tue Feb  5 19:17:21 2002
@@ -369,8 +369,7 @@
 							       l->name, l->chargetime, l->chargeint);
 							isdn_net_hangup(&p->dev);
 						}
-					} else
-						isdn_net_hangup(&p->dev);
+					}
 				} else if (l->hupflags & ISDN_INHUP)
 					isdn_net_hangup(&p->dev);
 			}
@@ -2872,7 +2871,7 @@
 		else
 			lp->hupflags &= ~ISDN_INHUP;
 		if (cfg->chargeint > 10) {
-			lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+			lp->hupflags |= ISDN_HAVECHARGE | ISDN_MANCHARGE;
 			lp->chargeint = cfg->chargeint * HZ;
 		}
 		if (cfg->p_encap != lp->p_encap) {
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Tue Feb  5 19:17:21 2002
+++ b/drivers/net/Config.in	Tue Feb  5 19:17:21 2002
@@ -73,7 +73,6 @@
    fi
    dep_tristate '  Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC $CONFIG_SBUS $CONFIG_EXPERIMENTAL
    dep_tristate '  Sun QuadEthernet support' CONFIG_SUNQE $CONFIG_SBUS
-   dep_tristate '  Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
    dep_tristate '  Sun GEM support' CONFIG_SUNGEM $CONFIG_PCI
    bool '  3COM cards' CONFIG_NET_VENDOR_3COM
    if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
diff -Nru a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
--- a/drivers/parport/ChangeLog	Tue Feb  5 19:17:21 2002
+++ b/drivers/parport/ChangeLog	Tue Feb  5 19:17:21 2002
@@ -1,3 +1,61 @@
+2002-01-21  Tim Waugh  <twaugh@redhat.com>
+
+	* daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select
+	work for ECP/EPP modes.
+
+2002-01-04  Tim Waugh  <twaugh@redhat.com>
+
+	* share.c (parport_claim_or_block): Sleep interruptibly to prevent
+	a possible deadlock.
+
+2002-01-13  Niels Kristian Bech Jensen  <nkbj@image.dk>
+
+	* parport_pc.c: Change some occurrences of frob_set_mode to
+	ECR_WRITE.  This fixes PLIP.
+
+2001-10-25  Damian Gruszka  <damian.gruszka@VisionSystems.de>
+
+	* parport_pc.c (ECR_WRITE): Define.  If there are forbidden bits
+	in the ECR register for some chips, this will be a useful place to
+	put that knowledge.
+	(change_mode): Use ECR_WRITE.
+	(parport_pc_restore_state): Likewise.
+	(parport_ECPPS2_supported): Likewise.
+	(parport_ECPEPP_supported): Likewise.
+	(irq_probe_EPP): Likewise.
+	(programmable_irq_support): Likewise.
+	(programmable_dma_support): Likewise.
+	(parport_pc_probe_port): Likewise.
+
+	(frob_set_mode): New function.  Set the mode bits of the ECR.
+	(get_fifo_residue): Use frob_set_mode.
+	(parport_pc_ecpepp_read_data): Likewise.
+	(parport_pc_ecpepp_write_data): Likewise.
+	(parport_pc_ecpepp_read_addr): Likewise.
+	(parport_pc_ecpepp_write_addr): Likewise.
+	(parport_pc_compat_write_block_pio): Likewise.
+	(parport_pc_ecp_write_block_pio): Likewise.
+	(parport_ECR_present): Likewise.
+	(parport_ECP_supported): Likewise.
+	(parport_EPP_supported): Likewise.
+	(parport_ECPEPP_supported): Likewise.
+	(programmable_irq_support): Likewise.
+	(irq_probe_ECP): Likewise.
+	(programmable_dma_support): Likewise.
+
+	(parport_pc_enable_irq): Only enable interrupts if we know which
+	IRQ line they will come from.
+	(parport_pc_init_state): Set nErrIntrEn at initialisation.
+	(parport_pc_restore_state): Only write writable bits of CTR.
+	(parport_irq_probe): If no IRQ is found, take ackIntEn out of the
+	writable bit set.
+
+2001-10-25  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_fifo_write_block_pio): Correct typo.
+	(parport_pc_init_state): Only set ackIntEn if we know which IRQ
+	line the interrupts will come from.
+
 2001-12-07  Tim Waugh  <twaugh@redhat.com>
 
 	* ieee1284_ops.c (parport_ieee1284_epp_write_addr,
diff -Nru a/drivers/parport/daisy.c b/drivers/parport/daisy.c
--- a/drivers/parport/daisy.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/parport/daisy.c	Tue Feb  5 19:17:21 2002
@@ -406,8 +406,33 @@
 
 int parport_daisy_select (struct parport *port, int daisy, int mode)
 {
-	/* mode is currently ignored. FIXME? */
-	return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+	switch (mode)
+	{
+		// For these modes we should switch to EPP mode:
+		case IEEE1284_MODE_EPP:
+		case IEEE1284_MODE_EPPSL:
+		case IEEE1284_MODE_EPPSWE:
+			return (cpp_daisy (port, 0x20 + daisy) &
+				PARPORT_STATUS_ERROR);
+
+		// For these modes we should switch to ECP mode:
+		case IEEE1284_MODE_ECP:
+		case IEEE1284_MODE_ECPRLE:
+		case IEEE1284_MODE_ECPSWE: 
+			return (cpp_daisy (port, 0xd0 + daisy) &
+				PARPORT_STATUS_ERROR);
+
+		// Nothing was told for BECP in Daisy chain specification.
+		// May be it's wise to use ECP?
+		case IEEE1284_MODE_BECP:
+		// Others use compat mode
+		case IEEE1284_MODE_NIBBLE:
+		case IEEE1284_MODE_BYTE:
+		case IEEE1284_MODE_COMPAT:
+		default:
+			return (cpp_daisy (port, 0xe0 + daisy) &
+				PARPORT_STATUS_ERROR);
+	}
 }
 
 static int mux_present (struct parport *port)
diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
--- a/drivers/parport/parport_pc.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/parport/parport_pc.c	Tue Feb  5 19:17:21 2002
@@ -73,6 +73,8 @@
 #define ECR_VND 05
 #define ECR_TST 06
 #define ECR_CNF 07
+#define ECR_MODE_MASK 0xe0
+#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))
 
 #undef DEBUG
 
@@ -100,13 +102,22 @@
 static void frob_econtrol (struct parport *pb, unsigned char m,
 			   unsigned char v)
 {
-	unsigned char ectr = inb (ECONTROL (pb));
+	unsigned char ectr = 0;
+
+	if (m != 0xff)
+		ectr = inb (ECONTROL (pb));
+
 	DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
 		m, v, ectr, (ectr & ~m) ^ v);
 
 	outb ((ectr & ~m) ^ v, ECONTROL (pb));
 }
 
+static void __inline__ frob_set_mode (struct parport *p, int mode)
+{
+	frob_econtrol (p, ECR_MODE_MASK, mode << 5);
+}
+
 #ifdef CONFIG_PARPORT_PC_FIFO
 /* Safely change the mode bits in the ECR 
    Returns:
@@ -117,7 +128,6 @@
 static int change_mode(struct parport *p, int m)
 {
 	const struct parport_pc_private *priv = p->physport->private_data;
-	int ecr = ECONTROL(p);
 	unsigned char oecr;
 	int mode;
 
@@ -129,7 +139,7 @@
 	}
 
 	/* Bits <7:5> contain the mode. */
-	oecr = inb (ecr);
+	oecr = inb (ECONTROL (p));
 	mode = (oecr >> 5) & 0x7;
 	if (mode == m) return 0;
 
@@ -166,13 +176,13 @@
 		/* We have to go through mode 001 */
 		oecr &= ~(7 << 5);
 		oecr |= ECR_PS2 << 5;
-		outb (oecr, ecr);
+		ECR_WRITE (p, oecr);
 	}
 
 	/* Set the mode. */
 	oecr &= ~(7 << 5);
 	oecr |= m << 5;
-	outb (oecr, ecr);
+	ECR_WRITE (p, oecr);
 	return 0;
 }
 
@@ -197,10 +207,10 @@
 		residue);
 
 	/* Reset the FIFO. */
-	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (p, ECR_PS2);
 
 	/* Now change to config mode and clean up. FIXME */
-	frob_econtrol (p, 0xe0, ECR_CNF << 5);
+	frob_set_mode (p, ECR_CNF);
 	cnfga = inb (CONFIGA (p));
 	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
 
@@ -213,7 +223,7 @@
 	 * PWord != 1 byte. */
 
 	/* Back to PS2 mode. */
-	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (p, ECR_PS2);
 
 	DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p)));
 	return residue;
@@ -331,7 +341,8 @@
 
 void parport_pc_enable_irq(struct parport *p)
 {
-	__parport_pc_frob_control (p, 0x10, 0x10);
+	if (p->irq != PARPORT_IRQ_NONE)
+		__parport_pc_frob_control (p, 0x10, 0x10);
 }
 
 void parport_pc_data_forward (struct parport *p)
@@ -346,8 +357,14 @@
 
 void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
 {
-	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
-	s->u.pc.ecr = 0x24;
+	s->u.pc.ctr = 0xc;
+	if (dev->irq_func &&
+	    dev->port->irq != PARPORT_IRQ_NONE)
+		/* Set ackIntEn */
+		s->u.pc.ctr |= 0x10;
+
+	s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24;
+			     * D.Gruszka VScom */
 }
 
 void parport_pc_save_state(struct parport *p, struct parport_state *s)
@@ -361,10 +378,11 @@
 void parport_pc_restore_state(struct parport *p, struct parport_state *s)
 {
 	struct parport_pc_private *priv = p->physport->private_data;
-	outb (s->u.pc.ctr, CONTROL (p));
-	priv->ctr = s->u.pc.ctr;
+	register unsigned char c = s->u.pc.ctr & priv->ctr_writable;
+	outb (c, CONTROL (p));
+	priv->ctr = c;
 	if (priv->ecr)
-		outb (s->u.pc.ecr, ECONTROL (p));
+		ECR_WRITE (p, s->u.pc.ecr);
 }
 
 #ifdef CONFIG_PARPORT_1284
@@ -516,11 +534,11 @@
 {
 	size_t got;
 
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	frob_set_mode (port, ECR_EPP);
 	parport_pc_data_reverse (port);
 	parport_pc_write_control (port, 0x4);
 	got = parport_pc_epp_read_data (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (port, ECR_PS2);
 
 	return got;
 }
@@ -531,11 +549,11 @@
 {
 	size_t written;
 
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	frob_set_mode (port, ECR_EPP);
 	parport_pc_write_control (port, 0x4);
 	parport_pc_data_forward (port);
 	written = parport_pc_epp_write_data (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (port, ECR_PS2);
 
 	return written;
 }
@@ -545,11 +563,11 @@
 {
 	size_t got;
 
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	frob_set_mode (port, ECR_EPP);
 	parport_pc_data_reverse (port);
 	parport_pc_write_control (port, 0x4);
 	got = parport_pc_epp_read_addr (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (port, ECR_PS2);
 
 	return got;
 }
@@ -560,11 +578,11 @@
 {
 	size_t written;
 
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	frob_set_mode (port, ECR_EPP);
 	parport_pc_write_control (port, 0x4);
 	parport_pc_data_forward (port);
 	written = parport_pc_epp_write_addr (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+	frob_set_mode (port, ECR_PS2);
 
 	return written;
 }
@@ -612,7 +630,7 @@
 			/* FIFO is full. Wait for interrupt. */
 
 			/* Clear serviceIntr */
-			outb (ecrval & ~(1<<2), ECONTROL (port));
+			ECR_WRITE (port, ecrval & ~(1<<2));
 		false_alarm:
 			ret = parport_wait_event (port, HZ);
 			if (ret < 0) break;
@@ -663,7 +681,7 @@
 		left--;
         }
 
-dump_parport_state ("leave fifo_write_block_dma", port);
+dump_parport_state ("leave fifo_write_block_pio", port);
 	return length - left;
 }
 
@@ -837,7 +855,7 @@
 		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
 		/* Prevent further data transfer. */
-		frob_econtrol (port, 0xe0, ECR_TST << 5);
+		frob_set_mode (port, ECR_TST);
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
@@ -849,7 +867,7 @@
 		}
 
 		/* Reset the FIFO and return to PS2 mode. */
-		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+		frob_set_mode (port, ECR_PS2);
 	}
 
 	r = parport_wait_peripheral (port,
@@ -934,7 +952,7 @@
 		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
 		/* Prevent further data transfer. */
-		frob_econtrol (port, 0xe0, ECR_TST << 5);
+		frob_set_mode (port, ECR_TST);
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
@@ -946,7 +964,7 @@
 		}
 
 		/* Reset the FIFO and return to PS2 mode. */
-		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+		frob_set_mode (port, ECR_PS2);
 
 		/* Host transfer recovery. */
 		parport_pc_data_reverse (port); /* Must be in PS2 mode */
@@ -1113,7 +1131,7 @@
 			}
 
 			/* Clear serviceIntr */
-			outb (ecrval & ~(1<<2), ECONTROL (port));
+			ECR_WRITE (port, ecrval & ~(1<<2));
 		false_alarm:
 dump_parport_state ("waiting", port);
 			ret = parport_wait_event (port, HZ);
@@ -1716,7 +1734,7 @@
 	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
 		goto no_reg;
 
-	outb (0x34, ECONTROL (pb));
+	ECR_WRITE (pb, 0x34);
 	if (inb (ECONTROL (pb)) != 0x35)
 		goto no_reg;
 
@@ -1724,7 +1742,7 @@
 	outb (0xc, CONTROL (pb));
 	
 	/* Go to mode 000 */
-	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+	frob_set_mode (pb, ECR_SPP);
 
 	return 1;
 
@@ -1794,8 +1812,8 @@
 		return 0;
 
 	/* Find out FIFO depth */
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+	ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
+	ECR_WRITE (pb, ECR_TST << 5); /* TEST FIFO */
 	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
 		outb (0xaa, FIFO (pb));
 
@@ -1804,7 +1822,7 @@
 	 * it doesn't support ECP or FIFO MODE
 	 */
 	if (i == 1024) {
-		outb (ECR_SPP << 5, ECONTROL (pb));
+		ECR_WRITE (pb, ECR_SPP << 5);
 		return 0;
 	}
 
@@ -1834,9 +1852,9 @@
 	priv->writeIntrThreshold = i;
 
 	/* Find out readIntrThreshold */
-	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */
+	frob_set_mode (pb, ECR_PS2); /* Reset FIFO and enable PS2 */
 	parport_pc_data_reverse (pb); /* Must be in PS2 mode */
-	frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+	frob_set_mode (pb, ECR_TST); /* Test FIFO */
 	frob_econtrol (pb, 1<<2, 1<<2);
 	frob_econtrol (pb, 1<<2, 0);
 	for (i = 1; i <= priv->fifo_depth; i++) {
@@ -1855,8 +1873,8 @@
 
 	priv->readIntrThreshold = i;
 
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+	ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
+	ECR_WRITE (pb, 0xf4); /* Configuration mode */
 	config = inb (CONFIGA (pb));
 	pword = (config >> 4) & 0x7;
 	switch (pword) {
@@ -1901,7 +1919,7 @@
 	}
 
 	/* Go back to mode 000 */
-	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+	frob_set_mode (pb, ECR_SPP);
 
 	return 1;
 }
@@ -1917,11 +1935,9 @@
 		return 0;
 
 	oecr = inb (ECONTROL (pb));
-	outb (ECR_PS2 << 5, ECONTROL (pb));
-	
+	ECR_WRITE (pb, ECR_PS2 << 5);
 	result = parport_PS2_supported(pb);
-
-	outb (oecr, ECONTROL (pb));
+	ECR_WRITE (pb, oecr);
 	return result;
 }
 
@@ -1953,7 +1969,7 @@
 	if (priv->ecr) {
 		unsigned char i;
 		for (i = 0x00; i < 0x80; i += 0x20) {
-			outb (i, ECONTROL (pb));
+			ECR_WRITE (pb, i);
 			if (clear_epp_timeout (pb)) {
 				/* Phony EPP in ECP. */
 				return 0;
@@ -1984,11 +2000,11 @@
 
 	oecr = inb (ECONTROL (pb));
 	/* Search for SMC style EPP+ECP mode */
-	outb (0x80, ECONTROL (pb));
+	ECR_WRITE (pb, 0x80);
 	outb (0x04, CONTROL (pb));
 	result = parport_EPP_supported(pb);
 
-	outb (oecr, ECONTROL (pb));
+	ECR_WRITE (pb, oecr);
 
 	if (result) {
 		/* Set up access functions to use ECP+EPP hardware. */
@@ -2025,12 +2041,12 @@
 		PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
 	};
 
-	outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+	ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */
 
 	intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
 	irq = lookup[intrLine];
 
-	outb (oecr, ECONTROL (pb));
+	ECR_WRITE (pb, oecr);
 	return irq;
 }
 
@@ -2042,16 +2058,16 @@
 	sti();
 	irqs = probe_irq_on();
 		
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
-	outb (ECR_TST << 5, ECONTROL (pb));
+	ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */
+	ECR_WRITE (pb, (ECR_TST << 5) | 0x04);
+	ECR_WRITE (pb, ECR_TST << 5);
 
 	/* If Full FIFO sure that writeIntrThreshold is generated */
 	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
 		outb (0xaa, FIFO (pb));
 		
 	pb->irq = probe_irq_off(irqs);
-	outb (ECR_SPP << 5, ECONTROL (pb));
+	ECR_WRITE (pb, ECR_SPP << 5);
 
 	if (pb->irq <= 0)
 		pb->irq = PARPORT_IRQ_NONE;
@@ -2093,7 +2109,7 @@
 
 	pb->irq = probe_irq_off (irqs);
 	if (pb->modes & PARPORT_MODE_PCECR)
-		outb (oecr, ECONTROL (pb));
+		ECR_WRITE (pb, oecr);
 	parport_pc_write_control(pb, 0xc);
 
 	if (pb->irq <= 0)
@@ -2118,7 +2134,9 @@
  */
 static int __devinit parport_irq_probe(struct parport *pb)
 {
-	const struct parport_pc_private *priv = pb->private_data;
+	struct parport_pc_private *priv = pb->private_data;
+
+	priv->ctr_writable |= 0x10;
 
 	if (priv->ecr) {
 		pb->irq = programmable_irq_support(pb);
@@ -2144,6 +2162,9 @@
 	if (pb->irq == PARPORT_IRQ_NONE)
 		pb->irq = get_superio_irq(pb);
 
+	if (pb->irq == PARPORT_IRQ_NONE)
+		priv->ctr_writable &= ~0x10;
+
 	return pb->irq;
 }
 
@@ -2155,7 +2176,7 @@
 	unsigned char oecr = inb (ECONTROL (p));
 	int dma;
 
-	frob_econtrol (p, 0xe0, ECR_CNF << 5);
+	frob_set_mode (p, ECR_CNF);
 	
 	dma = inb (CONFIGB(p)) & 0x07;
 	/* 000: Indicates jumpered 8-bit DMA if read-only.
@@ -2163,7 +2184,7 @@
 	if ((dma & 0x03) == 0)
 		dma = PARPORT_DMA_NONE;
 
-	outb (oecr, ECONTROL (p));
+	ECR_WRITE (p, oecr);
 	return dma;
 }
 
@@ -2209,7 +2230,7 @@
 	}
 	memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
 	priv->ctr = 0xc;
-	priv->ctr_writable = 0xff;
+	priv->ctr_writable = ~0x10;
 	priv->ecr = 0;
 	priv->fifo_depth = 0;
 	priv->dma_buf = 0;
@@ -2371,7 +2392,7 @@
 		 * Put the ECP detected port in PS2 mode.
 		 * Do this also for ports that have ECR but don't do ECP.
 		 */
-		outb (0x34, ECONTROL (p));
+		ECR_WRITE (p, 0x34);
 
 	parport_pc_write_data(p, 0);
 	parport_pc_data_forward (p);
diff -Nru a/drivers/parport/share.c b/drivers/parport/share.c
--- a/drivers/parport/share.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/parport/share.c	Tue Feb  5 19:17:21 2002
@@ -1011,7 +1011,11 @@
 		/* If dev->waiting is clear now, an interrupt
 		   gave us the port and we would deadlock if we slept.  */
 		if (dev->waiting) {
-			sleep_on(&dev->wait_q);
+			interruptible_sleep_on (&dev->wait_q);
+			if (signal_pending (current)) {
+				restore_flags (flags);
+				return -EINTR;
+			}
 			r = 1;
 		} else {
 			r = 0;
@@ -1084,7 +1088,7 @@
 		if (pd->waiting & 2) { /* sleeping in claim_or_block */
 			parport_claim(pd);
 			if (waitqueue_active(&pd->wait_q))
-				wake_up(&pd->wait_q);
+				wake_up_interruptible(&pd->wait_q);
 			return;
 		} else if (pd->wakeup) {
 			pd->wakeup(pd->private);
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/pci/pci.c	Tue Feb  5 19:17:21 2002
@@ -1086,13 +1086,7 @@
 	child->parent = parent;
 	child->ops = parent->ops;
 	child->sysdata = parent->sysdata;
-
-	/* init generic fields */
-	child->iobus.self = &dev->dev;
-	child->iobus.parent = &parent->iobus;
-	dev->dev.subordinate = &child->iobus;
-
-	strcpy(child->iobus.name,dev->dev.name);
+	child->dev = &dev->dev;
 
 	/*
 	 * Set up the primary, secondary and subordinate
@@ -1361,16 +1355,11 @@
 	DBG("Scanning bus %02x\n", bus->number);
 	max = bus->secondary;
 
-	/* we should know for sure what the bus number is, so set the bus ID
-	 * for the bus and make sure it's registered in the device tree */
-	sprintf(bus->iobus.bus_id,"pci%d",bus->number);
-	iobus_register(&bus->iobus);
-
 	/* Create a device template */
 	memset(&dev0, 0, sizeof(dev0));
 	dev0.bus = bus;
 	dev0.sysdata = bus->sysdata;
-	dev0.dev.parent = &bus->iobus;
+	dev0.dev.parent = bus->dev;
 	dev0.dev.driver = &pci_device_driver;
 
 	/* Go find them, Rover! */
@@ -1430,9 +1419,11 @@
 		return NULL;
 	list_add_tail(&b->node, &pci_root_buses);
 
-	sprintf(b->iobus.bus_id,"pci%d",bus);
-	strcpy(b->iobus.name,"Host/PCI Bridge");
-	iobus_register(&b->iobus);
+	b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
+	memset(b->dev,0,sizeof(*(b->dev)));
+	sprintf(b->dev->bus_id,"pci%d",bus);
+	strcpy(b->dev->name,"Host/PCI Bridge");
+	device_register(b->dev);
 
 	b->number = b->secondary = bus;
 	b->resource[0] = &ioport_resource;
diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/pci/proc.c	Tue Feb  5 19:17:21 2002
@@ -371,6 +371,47 @@
 
 static struct proc_dir_entry *proc_bus_pci_dir;
 
+/* driverfs files */
+static ssize_t pci_show_irq(struct device * dev, char * buf, size_t count, loff_t off)
+{
+	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+	return off ? 0 : sprintf(buf,"%u",pci_dev->irq);
+}
+
+static struct driver_file_entry pci_irq_entry = {
+	name:	"irq",
+	mode:	S_IRUGO,
+	show:	pci_show_irq,
+};
+
+static ssize_t pci_show_resources(struct device * dev, char * buf, size_t count, loff_t off)
+{
+	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+	char * str = buf;
+	int i;
+
+	if (off && off < DEVICE_COUNT_RESOURCE) {
+		str += sprintf(str,LONG_FORMAT LONG_FORMAT LONG_FORMAT "\n",
+				       pci_resource_start(pci_dev,off),
+				       pci_resource_end(pci_dev,off),
+				       pci_resource_flags(pci_dev,off));
+	} else if (!off) {
+		for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(pci_dev,i); i++) {
+			str += sprintf(str,LONG_FORMAT LONG_FORMAT LONG_FORMAT "\n",
+				       pci_resource_start(pci_dev,i),
+				       pci_resource_end(pci_dev,i),
+				       pci_resource_flags(pci_dev,i));
+		}
+	}
+	return (str - buf);
+}
+
+static struct driver_file_entry pci_resource_entry = {
+	name:	"resources",
+	mode:	S_IRUGO,
+	show:	pci_show_resources,
+};
+
 int pci_proc_attach_device(struct pci_dev *dev)
 {
 	struct pci_bus *bus = dev->bus;
@@ -390,6 +431,9 @@
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
 	e->size = PCI_CFG_SPACE_SIZE;
+
+	device_create_file(&dev->dev,&pci_irq_entry);
+	device_create_file(&dev->dev,&pci_resource_entry);
 	return 0;
 }
 
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/scsi/esp.c	Tue Feb  5 19:17:21 2002
@@ -813,7 +813,7 @@
 	 * sanely maintain.
 	 */
 	if (request_irq(esp->ehost->irq, esp_intr,
-			SA_SHIRQ, "ESP SCSI", esp->ehost)) {
+			SA_SHIRQ, "ESP SCSI", esp)) {
 		printk("esp%d: Cannot acquire irq line\n",
 		       esp->esp_id);
 		return -1;
diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
--- a/drivers/scsi/megaraid.h	Tue Feb  5 19:17:21 2002
+++ b/drivers/scsi/megaraid.h	Tue Feb  5 19:17:21 2002
@@ -30,7 +30,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001\n)"
+#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001)\n"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/scsi/osst.c	Tue Feb  5 19:17:21 2002
@@ -125,8 +125,8 @@
 #define OSST_TIMEOUT (200 * HZ)
 #define OSST_LONG_TIMEOUT (1800 * HZ)
 
-#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
-#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
+#define TAPE_NR(x) (minor(x) & ~(128 | ST_MODE_MASK))
+#define TAPE_MODE(x) ((minor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
 
 /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
    24 bits) */
@@ -4021,7 +4021,7 @@
 		if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
 			STp->rew_at_close = 0;
 		else if (cmd_in == MTLOAD) {
-/*      		STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;  FIXME */
+/*      		STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0;  FIXME */
 			for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			    STp->ps[i].rw = ST_IDLE;
 			    STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
@@ -4103,7 +4103,7 @@
 		return (-EBUSY);
 	}
 	STp->in_use       = 1;
-	STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+	STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0;
 
 	if (STp->device->host->hostt->module)
 		 __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
@@ -4124,7 +4124,7 @@
 	flags = filp->f_flags;
 	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
-	STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
+	STp->raw = (minor(inode->i_rdev) & 0x40) != 0;
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
@@ -5407,7 +5407,7 @@
 #endif
 
 	tpnt->device = SDp;
-	tpnt->devt = MKDEV(MAJOR_NR, i);
+	tpnt->devt = mk_kdev(MAJOR_NR, i);
 	tpnt->dirty = 0;
 	tpnt->in_use = 0;
 	tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
diff -Nru a/drivers/sound/Config.in b/drivers/sound/Config.in
--- a/drivers/sound/Config.in	Tue Feb  5 19:17:21 2002
+++ b/drivers/sound/Config.in	Tue Feb  5 19:17:21 2002
@@ -34,14 +34,14 @@
 dep_mbool    '    Creative SBLive! MIDI' CONFIG_MIDI_EMU10K1 $CONFIG_SOUND_EMU10K1 $CONFIG_EXPERIMENTAL
 dep_tristate '  Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
 dep_tristate '  Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
-dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI
-dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI
-dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
+dep_tristate '  Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI $CONFIG_SOUND_GAMEPORT
+dep_tristate '  Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI $CONFIG_SOUND_GAMEPORT
+dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI
 dep_tristate '  RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
-dep_tristate '  S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
+dep_tristate '  S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate '  SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
 fi
diff -Nru a/drivers/usb/Config.help b/drivers/usb/Config.help
--- a/drivers/usb/Config.help	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/Config.help	Tue Feb  5 19:17:21 2002
@@ -578,14 +578,14 @@
   Support for anything but the X6 is experimental.
   Please report failures and successes.
   The scanner will appear as a scsi generic device to the rest
-  of the system. Scsi support is required for this driver to compile
-  and work. SANE 1.0.4 or newer is needed to make use of your scanner.
-  This driver can be compiled as a module.
+  of the system. Scsi support is required.
+  This driver can be compiled as a module, called microtek.o.
 
 CONFIG_USB_HPUSBSCSI
   Say Y here if you want support for the HP 53xx series of scanners
   and the Minolta Scan Dual. This driver is experimental.
   The scanner will be accessible as a SCSI device.
+  This can be compiled as a module, called hpusbscsi.o.
 
 CONFIG_USB_BLUETOOTH
   Say Y here if you want to connect a USB Bluetooth device to your
diff -Nru a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
--- a/drivers/usb/hcd/ohci-dbg.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci-dbg.c	Tue Feb  5 19:17:21 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
  */
  
@@ -74,27 +74,34 @@
 static inline struct ed *
 dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
 
+#ifdef OHCI_VERBOSE_DEBUG
 /* print non-empty branches of the periodic ed tree */
-void ep_print_int_eds (struct ohci_hcd *ohci, char * str)
+void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
 {
 	int i, j;
-	 __u32 * ed_p;
+	u32 *ed_p;
+	int printed = 0;
+
 	for (i= 0; i < 32; i++) {
 		j = 5;
 		ed_p = &(ohci->hcca->int_table [i]);
 		if (*ed_p == 0)
-		    continue;
-		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):",
-				str, i, i);
+			continue;
+		printed = 1;
+		printk (KERN_DEBUG "%s, ohci %s frame %2d:",
+				label, ohci->hcd.bus_name, i);
 		while (*ed_p != 0 && j--) {
 			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-			printk (" ed: %4x;", ed->hwINFO);
+			printk (" %p/%08x;", ed, ed->hwINFO);
 			ed_p = &ed->hwNextED;
 		}
 		printk ("\n");
 	}
+	if (!printed)
+		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
+				label, ohci->hcd.bus_name);
 }
-
+#endif
 
 static void ohci_dump_intr_mask (char *label, __u32 mask)
 {
@@ -137,8 +144,9 @@
 	__u32			temp;
 
 	temp = readl (&regs->revision) & 0xff;
-	if (temp != 0x10)
-		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+	dbg ("OHCI %d.%d, %s legacy support registers",
+		0x03 & (temp >> 4), (temp & 0x0f),
+		(temp & 0x10) ? "with" : "NO");
 
 	temp = readl (&regs->control);
 	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
@@ -225,8 +233,10 @@
 
 	// dumps some of the state we know about
 	ohci_dump_status (controller);
+#ifdef OHCI_VERBOSE_DEBUG
 	if (verbose)
-		ep_print_int_eds (controller, "hcca");
+		ohci_dump_periodic (controller, "hcca");
+#endif
 	dbg ("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub (controller, 1);
 }
diff -Nru a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
--- a/drivers/usb/hcd/ohci-hcd.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci-hcd.c	Tue Feb  5 19:17:21 2002
@@ -2,7 +2,7 @@
  * OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * [ Initialisation is based on Linus'  ]
  * [ uhci code and gregs ohci fragments ]
@@ -55,7 +55,7 @@
  * v2.0 1999/05/04 
  * v1.0 1999/04/27 initial release
  *
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
  */
  
@@ -74,10 +74,6 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>  /* for in_interrupt () */
 
-#ifndef CONFIG_USB_DEBUG
-	#define CONFIG_USB_DEBUG	/* this is still experimental! */
-#endif
-
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
 #else
@@ -258,7 +254,9 @@
 	if (ed->state != ED_OPER)
 		ep_link (ohci, ed);
 
-	/* fill the TDs and link it to the ed */
+	/* fill the TDs and link them to the ed; and
+	 * enable that part of the schedule, if needed
+	 */
 	td_submit_urb (urb);
 
 	spin_unlock_irqrestore (&ohci->lock, flags);
@@ -357,7 +355,9 @@
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
+#ifdef	OHCI_VERBOSE_DEBUG
 	dbg ("%s: ohci_get_frame", hcd->bus_name);
+#endif
 	return le16_to_cpu (ohci->hcca->frame_no);
 }
 
@@ -841,9 +841,10 @@
 			dl_done_list (ohci, dl_reverse_done_list (ohci));
 		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
 
-//		writel (OHCI_BLF, &ohci->regs->cmdstatus);
-//		writel (OHCI_CLF, &ohci->regs->cmdstatus);
-ohci_dump_status (ohci);
+		/* assume there are TDs on the bulk and control lists */
+		writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
+
+// ohci_dump_status (ohci);
 dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
 		break;
 
diff -Nru a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c
--- a/drivers/usb/hcd/ohci-hub.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci-hub.c	Tue Feb  5 19:17:21 2002
@@ -2,7 +2,7 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under GPL
  * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
diff -Nru a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c
--- a/drivers/usb/hcd/ohci-mem.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci-mem.c	Tue Feb  5 19:17:21 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
  */
 
@@ -42,7 +42,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
+#ifdef	CONFIG_DEBUG_SLAB
 #	define OHCI_MEM_FLAGS	SLAB_POISON
 #else
 #	define OHCI_MEM_FLAGS	0
@@ -64,16 +64,17 @@
 	return scan->virt;
 }
 
-static inline struct ed *
+static struct ed *
 dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
 {
 	return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
 				      ed_dma);
 }
 
-static inline struct td *
+static struct td *
 dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
 {
+	td_dma &= TD_MASK;
 	return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
 				      td_dma);
 }
@@ -214,7 +215,7 @@
 	return td;
 }
 
-static inline void
+static void
 td_free (struct ohci_hcd *hc, struct td *td)
 {
 	hash_free_td (hc, td);
@@ -242,7 +243,7 @@
 	return ed;
 }
 
-static inline void
+static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
 	hash_free_ed (hc, ed);
diff -Nru a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c
--- a/drivers/usb/hcd/ohci-q.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci-q.c	Tue Feb  5 19:17:21 2002
@@ -2,9 +2,9 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
  */
  
@@ -95,11 +95,11 @@
 	urb_print (urb, "RET", usb_pipeout (urb->pipe));
 #endif
 
-// FIXME:  but if urb->status says it was was unlinked ...
-
 	switch (usb_pipetype (urb->pipe)) {
   		case PIPE_INTERRUPT:
 #ifdef CONFIG_PCI
+// FIXME rewrite this resubmit path.  use pci_dma_sync_single()
+// and requeue more cheaply, and only if needed.
 			pci_unmap_single (hc->hcd.pdev,
 				urb_priv->td [0]->data_dma,
 				urb->transfer_buffer_length,
@@ -107,16 +107,22 @@
 					? PCI_DMA_TODEVICE
 					: PCI_DMA_FROMDEVICE);
 #endif
+			/* FIXME: MP race.  If another CPU partially unlinks
+			 * this URB (urb->status was updated, hasn't yet told
+			 * us to dequeue) before we call complete() here, an
+			 * extra "unlinked" completion will be reported...
+			 */
 			urb->complete (urb);
 
-			/* implicitly requeued */
+			/* always requeued, but ED_SKIP if complete() unlinks.
+			 * removed from periodic table only at SOF intr.
+			 */
   			urb->actual_length = 0;
-  			urb->status = -EINPROGRESS;
-  			if (urb_priv->state != URB_DEL) {
-				spin_lock_irqsave (&hc->lock, flags);
-  				td_submit_urb (urb);
-  				spin_unlock_irqrestore (&hc->lock, flags);
-			}
+			if (urb_priv->state != URB_DEL)
+				urb->status = -EINPROGRESS;
+			spin_lock_irqsave (&hc->lock, flags);
+			td_submit_urb (urb);
+			spin_unlock_irqrestore (&hc->lock, flags);
   			break;
 
 		case PIPE_ISOCHRONOUS:
@@ -126,7 +132,7 @@
 				continue;
 			if (urbt) { /* send the reply and requeue URB */	
 #ifdef CONFIG_PCI
-// FIXME this style unmap is only done on this route ...
+// FIXME rewrite this resubmit path too
 				pci_unmap_single (hc->hcd.pdev,
 					urb_priv->td [0]->data_dma,
 					urb->transfer_buffer_length,
@@ -290,8 +296,8 @@
 			ed->hwNextED = *ed_p; 
 			*ed_p = cpu_to_le32 (ed->dma);
 		}
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_INT");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "LINK_INT");
 #endif
 		break;
 
@@ -313,8 +319,8 @@
 			ed->ed_prev = NULL;
 		}	
 		ohci->ed_isotail = edi;  
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_ISO");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "LINK_ISO");
 #endif
 		break;
 	}	 	
@@ -336,7 +342,7 @@
 	int	interval;
 	__u32	*ed_p;
 
-	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+	ed->hwINFO |= ED_SKIP;
 
 	switch (ed->type) {
 	case PIPE_CONTROL:
@@ -394,8 +400,8 @@
 		}
 		for (i = int_branch; i < NUM_INTS; i += interval)
 		    ohci->ohci_int_load [i] -= ed->int_load;
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_INT");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "UNLINK_INT");
 #endif
 		break;
 
@@ -421,11 +427,15 @@
 				}
 			}	
 		}	
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_ISO");
+#ifdef OHCI_VERBOSE_DEBUG
+		ohci_dump_periodic (ohci, "UNLINK_ISO");
 #endif
 		break;
 	}
+
+	/* FIXME ED's "unlink" state is indeterminate;
+	 * the HC might still be caching it (till SOF).
+	 */
 	ed->state = ED_UNLINK;
 	return 0;
 }
@@ -478,7 +488,7 @@
 	}
 
 	if (ed->state == ED_NEW) {
-		ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+		ed->hwINFO = ED_SKIP;
   		/* dummy td; end of td list for ed */
 		td = td_alloc (ohci, SLAB_ATOMIC);
  		if (!td) {
@@ -492,8 +502,6 @@
 		ed->type = usb_pipetype (pipe);
 	}
 
-	ohci->dev [usb_pipedevice (pipe)] = udev;
-
 // FIXME:  don't do this if it's linked to the HC,
 // we might clobber data toggle or other state ...
 
@@ -531,7 +539,7 @@
 		return;
 	ed->state |= ED_URB_DEL;
 
-	ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+	ed->hwINFO |= ED_SKIP;
 
 	switch (ed->type) {
 		case PIPE_CONTROL: /* stop control list */
@@ -582,7 +590,7 @@
 
 	/* fill the old dummy TD */
 	td = urb_priv->td [index] = dma_to_td (ohci,
-			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+			le32_to_cpup (&urb_priv->ed->hwTailP));
 
 	td->ed = urb_priv->ed;
 	td->next_dl_td = NULL;
@@ -795,7 +803,7 @@
 
   	spin_lock_irqsave (&ohci->lock, flags);
 
-	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	td_list_hc = le32_to_cpup (&ohci->hcca->done_head);
 	ohci->hcca->done_head = 0;
 
 	while (td_list_hc) {		
@@ -806,26 +814,24 @@
 			dbg (" USB-error/status: %x : %p", 
 				TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
 				td_list);
-			if (td_list->ed->hwHeadP
-					& __constant_cpu_to_le32 (0x1)) {
+			/* typically the endpoint halted too */
+			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
 					td_list->ed->hwHeadP = 
 			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
-				    & __constant_cpu_to_le32 (0xfffffff0))
-			    | (td_list->ed->hwHeadP
-				    & __constant_cpu_to_le32 (0x2));
+				    & __constant_cpu_to_le32 (TD_MASK))
+			    | (td_list->ed->hwHeadP & ED_C);
 					urb_priv->td_cnt += urb_priv->length
 						- td_list->index - 1;
 				} else 
-					td_list->ed->hwHeadP &=
-					__constant_cpu_to_le32 (0xfffffff2);
+					td_list->ed->hwHeadP &= ~ED_H;
 			}
 		}
 
 		td_list->next_dl_td = td_rev;	
 		td_rev = td_list;
-		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
+		td_list_hc = le32_to_cpup (&td_list->hwNextTD);
 	}	
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return td_list;
@@ -851,10 +857,8 @@
 
 	for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
 
-		tdTailP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-		tdHeadP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP));
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
 		edINFO = le32_to_cpup (&ed->hwINFO);
 		td_p = &ed->hwHeadP;
 
@@ -863,7 +867,7 @@
 			urb_priv_t *urb_priv = td->urb->hcpriv;
 
 			td_next = dma_to_td (ohci,
-				le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+				le32_to_cpup (&td->hwNextTD));
 			if ((urb_priv->state == URB_DEL)) {
 				tdINFO = le32_to_cpup (&td->hwINFO);
 				if (TD_CC_GET (tdINFO) < 0xE)
@@ -882,17 +886,16 @@
 		}
 
 		ed->state &= ~ED_URB_DEL;
-		tdHeadP = dma_to_td (ohci,
-			le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
 
 		if (tdHeadP == tdTailP) {
 			if (ed->state == ED_OPER)
 				ep_unlink (ohci, ed);
 			td_free (ohci, tdTailP);
-			ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP);
+			ed->hwINFO = ED_SKIP;
 			ed->state = ED_NEW;
 		} else
-			ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP);
+			ed->hwINFO &= ~ED_SKIP;
 
 		switch (ed->type) {
 			case PIPE_CONTROL:
@@ -938,7 +941,7 @@
 	int		cc = 0;
 	struct urb	*urb;
 	urb_priv_t	*urb_priv;
- 	__u32		tdINFO, edHeadP, edTailP;
+ 	__u32		tdINFO;
 
  	unsigned long flags;
 
@@ -968,7 +971,7 @@
 			/*
 			 * Except for periodic transfers, both branches do
 			 * the same thing.  Periodic urbs get reissued until
-			 * they're "deleted" with usb_unlink_urb.
+			 * they're "deleted" (in SOF intr) by usb_unlink_urb.
 			 */
 			if ((ed->state & (ED_OPER | ED_UNLINK))
 					&& (urb_priv->state != URB_DEL)) {
@@ -983,13 +986,11 @@
 
   		spin_lock_irqsave (&ohci->lock, flags);
   		if (ed->state != ED_NEW) { 
-  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
-  			edTailP = le32_to_cpup (&ed->hwTailP);
-
-// FIXME:  ED_UNLINK is very fuzzy w.r.t. what the hc knows...
+  			u32 edHeadP = ed->hwHeadP;
 
 			/* unlink eds if they are not busy */
-     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+			edHeadP &= __constant_cpu_to_le32 (ED_MASK);
+     			if ((edHeadP == ed->hwTailP) && (ed->state == ED_OPER)) 
      				ep_unlink (ohci, ed);
      		}	
      		spin_unlock_irqrestore (&ohci->lock, flags);
diff -Nru a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h
--- a/drivers/usb/hcd/ohci.h	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/hcd/ohci.h	Tue Feb  5 19:17:21 2002
@@ -2,86 +2,102 @@
  * OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
- * This file is licenced under GPL
+ * This file is licenced under the GPL.
  * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
  */
  
-static const int cc_to_error [16] = { 
-
-/* map OHCI status to errno values */ 
-	/* No  Error  */               0,
-	/* CRC Error  */               -EILSEQ,
-	/* Bit Stuff  */               -EPROTO,
-	/* Data Togg  */               -EILSEQ,
-	/* Stall      */               -EPIPE,
-	/* DevNotResp */               -ETIMEDOUT,
-	/* PIDCheck   */               -EPROTO,
-	/* UnExpPID   */               -EPROTO,
-	/* DataOver   */               -EOVERFLOW,
-	/* DataUnder  */               -EREMOTEIO,
-	/* (for hw)   */               -EIO,
-	/* (for hw)   */               -EIO,
-	/* BufferOver */               -ECOMM,
-	/* BuffUnder  */               -ENOSR,
-	/* (for HCD)  */               -EALREADY,
-	/* (for HCD)  */               -EALREADY 
-};
-
-
-/* ED States */
-
+/*
+ * OHCI Endpoint Descriptor (ED) ... holds TD queue
+ * See OHCI spec, section 4.2
+ */
+struct ed {
+	/* first fields are hardware-specified, le32 */
+	__u32			hwINFO;       	/* endpoint config bitmap */
+#define ED_ISO		__constant_cpu_to_le32(1 << 15)
+#define ED_SKIP		__constant_cpu_to_le32(1 << 14)
+#define ED_LOWSPEED	__constant_cpu_to_le32(1 << 13)
+#define ED_OUT		__constant_cpu_to_le32(0x01 << 11)
+#define ED_IN		__constant_cpu_to_le32(0x10 << 11)
+	__u32			hwTailP;	/* tail of TD list */
+	__u32			hwHeadP;	/* head of TD list */
+#define ED_C		__constant_cpu_to_le32(0x02)	/* toggle carry */
+#define ED_H		__constant_cpu_to_le32(0x01)	/* halted */
+	__u32			hwNextED;	/* next ED in list */
+
+	/* rest are purely for the driver's use */
+	struct ed		*ed_prev;  
+	__u8			int_period;
+	__u8			int_branch;
+	__u8			int_load; 
+	__u8			int_interval;
+	__u8			state;			// ED_{NEW,UNLINK,OPER}
 #define ED_NEW 		0x00		/* unused, no dummy td */
 #define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
 #define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
+#define ED_URB_DEL  	0x08		/* for unlinking; masked in */
 
-#define ED_URB_DEL  	0x08		/* masked in */
+	__u8			type; 
+	__u16			last_iso;
+	struct ed		*ed_rm_list;
 
-/* usb_ohci_ed */
-struct ed {
-	/* first fields are hardware-specified */
-	__u32 hwINFO;       
-	__u32 hwTailP;
-	__u32 hwHeadP;
-	__u32 hwNextED;
-
-	struct ed * ed_prev;  
-	__u8 int_period;
-	__u8 int_branch;
-	__u8 int_load; 
-	__u8 int_interval;
-	__u8 state;			// ED_{NEW,UNLINK,OPER}
-	__u8 type; 
-	__u16 last_iso;
-	struct ed * ed_rm_list;
-
-	dma_addr_t dma;
-	__u32 unused [3];
-} __attribute((aligned(16)));
+	dma_addr_t		dma;			/* addr of ED */
+} __attribute__ ((aligned(16)));
+
+#define ED_MASK	((u32)~0x0f)		/* strip hw status in low addr bits */
 
  
-/* TD info field */
-#define TD_CC       0xf0000000
+/*
+ * OHCI Transfer Descriptor (TD) ... one per transfer segment
+ * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
+ * and 4.3.2 (iso)
+ */
+struct td {
+	/* first fields are hardware-specified, le32 */
+	__u32		hwINFO;		/* transfer info bitmask */
+#define TD_CC       0xf0000000			/* condition code */
 #define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC       0x0C000000
-#define TD_T        0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R        0x00040000
-#define TD_DI       0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP       0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
+//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000			/* error count */
+#define TD_T        0x03000000			/* data toggle state */
+#define TD_T_DATA0  0x02000000				/* DATA0 */
+#define TD_T_DATA1  0x03000000				/* DATA1 */
+#define TD_T_TOGGLE 0x00000000				/* uses ED_C */
+#define TD_DI       0x00E00000			/* frames before interrupt */
+//#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000			/* direction/pid */
+#define TD_DP_SETUP 0x00000000			/* SETUP pid */
+#define TD_DP_IN    0x00100000				/* IN pid */
+#define TD_DP_OUT   0x00080000				/* OUT pid */
+							/* 0x00180000 rsvd */
+#define TD_R        0x00040000			/* round: short packets OK? */
+					/* bits 0x1ffff are defined by HCD */
+#define TD_ISO	    0x00010000			/* copy of ED_ISO */
+
+  	__u32		hwCBP;		/* Current Buffer Pointer (or 0) */
+  	__u32		hwNextTD;	/* Next TD Pointer */
+  	__u32		hwBE;		/* Memory Buffer End Pointer */
+
+	/* PSW is only for ISO */
+#define MAXPSW 1		/* hardware allows 8 */
+  	__u16		hwPSW [MAXPSW];
 
-#define TD_ISO	    0x00010000
-#define TD_DEL      0x00020000
+	/* rest are purely for the driver's use */
+  	__u8		index;
+  	struct ed	*ed;
+  	struct td	*next_dl_td;
+  	struct urb	*urb;
 
-/* CC Codes */
+	dma_addr_t	td_dma;		/* addr of this TD */
+	dma_addr_t	data_dma;	/* addr of data it points to */
+} __attribute__ ((aligned(32)));	/* c/b/i need 16; only iso needs 32 */
+
+#define TD_MASK	((u32)~0x1f)		/* strip hw status in low addr bits */
+
+/*
+ * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW
+ */
 #define TD_CC_NOERROR      0x00
 #define TD_CC_CRC          0x01
 #define TD_CC_BITSTUFFING  0x02
@@ -99,57 +115,50 @@
 #define TD_NOTACCESSED     0x0F
 
 
-#define MAXPSW 1
-
-struct td {
-	/* first hardware fields are in all tds */
-	__u32		hwINFO;
-  	__u32		hwCBP;		/* Current Buffer Pointer */
-  	__u32		hwNextTD;	/* Next TD Pointer */
-  	__u32		hwBE;		/* Memory Buffer End Pointer */
-
-  	__u16		hwPSW [MAXPSW];	/* PSW is only for ISO */
-
-  	__u8		unused;
-  	__u8		index;
-  	struct ed	*ed;
-  	struct td	*next_dl_td;
-  	struct urb	*urb;
-
-	dma_addr_t	td_dma;
-	dma_addr_t	data_dma;
-	__u32		unused2 [2];
-} __attribute((aligned(32)));		/* iso needs 32 */
+/* map OHCI TD status codes (CC) to errno values */ 
+static const int cc_to_error [16] = { 
+	/* No  Error  */               0,
+	/* CRC Error  */               -EILSEQ,
+	/* Bit Stuff  */               -EPROTO,
+	/* Data Togg  */               -EILSEQ,
+	/* Stall      */               -EPIPE,
+	/* DevNotResp */               -ETIMEDOUT,
+	/* PIDCheck   */               -EPROTO,
+	/* UnExpPID   */               -EPROTO,
+	/* DataOver   */               -EOVERFLOW,
+	/* DataUnder  */               -EREMOTEIO,
+	/* (for hw)   */               -EIO,
+	/* (for hw)   */               -EIO,
+	/* BufferOver */               -ECOMM,
+	/* BuffUnder  */               -ENOSR,
+	/* (for HCD)  */               -EALREADY,
+	/* (for HCD)  */               -EALREADY 
+};
 
-#define OHCI_ED_SKIP	(1 << 14)
 
 /*
  * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. The host controller is
+ * structure defined section 4.4.1 of the OHCI spec. The HC is
  * told the base address of it.  It must be 256-byte aligned.
  */
-#define NUM_INTS 32	/* part of the OHCI standard */
 struct ohci_hcca {
-	__u32	int_table [NUM_INTS];	/* Interrupt ED table */
+#define NUM_INTS 32
+	__u32	int_table [NUM_INTS];	/* periodic schedule */
 	__u16	frame_no;		/* current frame number */
 	__u16	pad1;			/* set to 0 on each frame_no change */
 	__u32	done_head;		/* info returned for an interrupt */
 	u8	reserved_for_hc [116];
-} __attribute((aligned(256)));
+	u8	what [4];		/* spec only identifies 252 bytes :) */
+} __attribute__ ((aligned(256)));
 
   
 /*
- * Maximum number of root hub ports.  
- */
-#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
+ * This is the structure of the OHCI controller's memory mapped I/O region.
+ * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
+ * Layout is in section 7 (and appendix B) of the spec.
  */
 struct ohci_regs {
-	/* control and status registers */
+	/* control and status registers (section 7.1) */
 	__u32	revision;
 	__u32	control;
 	__u32	cmdstatus;
@@ -157,7 +166,7 @@
 	__u32	intrenable;
 	__u32	intrdisable;
 
-	/* memory pointers */
+	/* memory pointers (section 7.2) */
 	__u32	hcca;
 	__u32	ed_periodcurrent;
 	__u32	ed_controlhead;
@@ -166,23 +175,25 @@
 	__u32	ed_bulkcurrent;
 	__u32	donehead;
 
-	/* frame counters */
+	/* frame counters (section 7.3) */
 	__u32	fminterval;
 	__u32	fmremaining;
 	__u32	fmnumber;
 	__u32	periodicstart;
 	__u32	lsthresh;
 
-	/* Root hub ports */
+	/* Root hub ports (section 7.4) */
 	struct	ohci_roothub_regs {
 		__u32	a;
 		__u32	b;
 		__u32	status;
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports (RH_A_NDP) */
 		__u32	portstatus [MAX_ROOT_PORTS];
 	} roothub;
 
-	/* and some optional registers for legacy compatibility */
-} __attribute((aligned(32)));
+	/* and optional "legacy support" registers (appendix B) at 0x0100 */
+
+} __attribute__ ((aligned(32)));
 
 
 /* OHCI CONTROL AND STATUS REGISTER MASKS */
@@ -270,9 +281,8 @@
 #define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
 
 
-/* urb */
-typedef struct urb_priv
-{
+/* hcd-private per-urb state */
+typedef struct urb_priv {
 	struct ed		*ed;
 	__u16			length;		// # tds in this request
 	__u16			td_cnt;		// tds already serviced
@@ -345,7 +355,6 @@
 	int			sleeping;
 	int			ohci_int_load [NUM_INTS];
 	u32 			hc_control;	/* copy of hc control reg */
-	struct usb_device	*dev [128];
 
 	unsigned long		flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
diff -Nru a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
--- a/drivers/usb/kaweth.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/kaweth.c	Tue Feb  5 19:17:21 2002
@@ -155,6 +155,7 @@
  *     kaweth_driver
  ****************************************************************/
 static struct usb_driver kaweth_driver = {
+	owner:		THIS_MODULE,
 	name:		"kaweth",
 	probe:		kaweth_probe,
 	disconnect:	kaweth_disconnect,
@@ -238,8 +239,7 @@
 		return -EBUSY;
 	}
 
-	dr = kmalloc(sizeof(struct usb_ctrlrequest), 
-                     in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
 
 	if (!dr) {
 		kaweth_dbg("kmalloc() failed");
@@ -586,14 +586,10 @@
 {
 	struct kaweth_device *kaweth = urb->context;
 
-	spin_lock(&kaweth->device_lock);
-
-	if (urb->status)
+	if (unlikely(urb->status != 0))
 		kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
 
 	netif_wake_queue(kaweth->net);
-
-	spin_unlock(&kaweth->device_lock);
 }
 
 /****************************************************************
@@ -757,9 +753,7 @@
 	memset(kaweth, 0, sizeof(struct kaweth_device));
 
 	kaweth->dev = dev;
-	kaweth->status = 0;
-	kaweth->net = NULL;
-	kaweth->device_lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&kaweth->device_lock);
 		
 	kaweth_dbg("Resetting.");
 
@@ -824,6 +818,7 @@
 
 		/* Device will now disappear for a moment...  */
 		kaweth_info("Firmware loaded.  I'll be back...");
+		kfree(kaweth);
 		return NULL;
 	}
 
@@ -925,6 +920,8 @@
 		kaweth_warn("unregistering non-existant device");
 		return;
 	}
+	usb_unlink_urb(kaweth->tx_urb);
+	usb_unlink_urb(kaweth->rx_urb);
 
 	if(kaweth->net) {
 		if(kaweth->net->flags & IFF_UP) {
diff -Nru a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
--- a/drivers/usb/pegasus.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/pegasus.c	Tue Feb  5 19:17:21 2002
@@ -53,7 +53,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.22 (2001/12/07)"
+#define DRIVER_VERSION "v0.4.23 (2002/02/01)"
 #define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -115,7 +115,7 @@
 		case -ENOENT:
 			break;
 		default:
-			warn( __FUNCTION__ " status %d", urb->status);
+			warn("%s: status %d", __FUNCTION__, urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
 	wake_up(&pegasus->ctrl_wait );
@@ -158,7 +158,7 @@
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRLs %d", ret);
+		err("%s: BAD CTRLs %d", __FUNCTION__, ret);
 		goto out;
 	}
 
@@ -208,7 +208,7 @@
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRL %d", ret);
+		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 	
@@ -258,7 +258,7 @@
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRL %d", ret);
+		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 
@@ -288,7 +288,7 @@
 			  pegasus->eth_regs, 3, ctrl_callback, pegasus );
 
 	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
-		err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
+		err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
 
 	return	ret;
 }
@@ -313,7 +313,7 @@
 		*regd = le16_to_cpu(regdi);
 		return	0;
 	}
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 	
 	return 1;
 }
@@ -335,7 +335,7 @@
 	}
 	if ( i < REG_TIMEOUT )
 		return	0;
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 
 	return 1;
 }
@@ -361,7 +361,7 @@
 		*retdata = le16_to_cpu (retdatai);
 		return	0;
 	}
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 
 	return -1;
 }
@@ -405,7 +405,7 @@
 	disable_eprom_write( pegasus );
 	if ( i < REG_TIMEOUT )
 		return	0;
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 	return	-1;
 }
 #endif	/* PEGASUS_WRITE_EEPROM */
@@ -574,7 +574,7 @@
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
 	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
-		warn( __FUNCTION__ " failed submint rx_urb %d", res);
+		warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
 
@@ -722,14 +722,14 @@
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
 	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
-		warn( __FUNCTION__ " failed rx_urb %d", res );
+		warn("%s: failed rx_urb %d", __FUNCTION__, res);
 #ifdef	PEGASUS_USE_INTR
 	FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
 			usb_rcvintpipe(pegasus->usb, 3),
 			pegasus->intr_buff, sizeof(pegasus->intr_buff),
 			intr_callback, pegasus, pegasus->intr_interval );
 	if ( (res = usb_submit_urb(pegasus->intr_urb)) )
-		warn( __FUNCTION__ " failed intr_urb %d", res);
+		warn("%s: failed intr_urb %d", __FUNCTION__, res);
 #endif
 	netif_start_queue( net );
 	pegasus->flags |= PEGASUS_RUNNING;
@@ -885,6 +885,9 @@
 
 	net = init_etherdev( NULL, 0 );
 	if ( !net ) {
+		usb_free_urb (pegasus->tx_urb);
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
 		kfree( pegasus );
 		return	NULL;
 	}
@@ -910,6 +913,9 @@
 	if ( reset_mac(pegasus) ) {
 		err("can't reset MAC");
 		unregister_netdev( pegasus->net );
+		usb_free_urb (pegasus->tx_urb);
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
@@ -947,10 +953,14 @@
 	pegasus->flags |= PEGASUS_UNPLUG;
 	unregister_netdev( pegasus->net );
 	usb_dec_dev_use( dev );
-	usb_free_urb (pegasus->intr_urb);
-	usb_free_urb (pegasus->tx_urb);
-	usb_free_urb (pegasus->rx_urb);
-	usb_free_urb (pegasus->ctrl_urb);
+	usb_unlink_urb(pegasus->intr_urb);
+	usb_unlink_urb(pegasus->tx_urb);
+	usb_unlink_urb(pegasus->rx_urb);
+	usb_unlink_urb(pegasus->ctrl_urb);
+	usb_free_urb(pegasus->intr_urb);
+	usb_free_urb(pegasus->tx_urb);
+	usb_free_urb(pegasus->rx_urb);
+	usb_free_urb(pegasus->ctrl_urb);
 	kfree( pegasus->net );
 	kfree( pegasus );
 	pegasus = NULL;
diff -Nru a/drivers/usb/printer.c b/drivers/usb/printer.c
--- a/drivers/usb/printer.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/printer.c	Tue Feb  5 19:17:21 2002
@@ -20,6 +20,7 @@
  *	v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
  *	v0.8 - add devfs support
  *	v0.9 - fix unplug-while-open paths
+ *	v0.10- remove sleep_on, fix error on oom (oliver@neukum.org)
  */
 
 /*
@@ -54,7 +55,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.8"
+#define DRIVER_VERSION "v0.10"
 #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap"
 #define DRIVER_DESC "USB Printer Device Class driver"
 
@@ -95,6 +96,8 @@
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
 	int			minor;			/* minor number of device */
+	int			wcomplete;		/* writing is completed */
+	int			rcomplete;		/* reading is completed */		
 	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		bidir;			/* interface is bidirectional */
@@ -151,17 +154,31 @@
  * URB callback.
  */
 
-static void usblp_bulk(struct urb *urb)
+static void usblp_bulk_read(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
 
 	if (!usblp || !usblp->dev || !usblp->used)
 		return;
 
-	if (urb->status)
+	if (unlikely(urb->status))
 		warn("usblp%d: nonzero read/write bulk status received: %d",
 			usblp->minor, urb->status);
+	usblp->rcomplete = 1;
+	wake_up_interruptible(&usblp->wait);
+}
 
+static void usblp_bulk_write(struct urb *urb)
+{
+	struct usblp *usblp = urb->context;
+
+	if (!usblp || !usblp->dev || !usblp->used)
+		return;
+
+	if (unlikely(urb->status))
+		warn("usblp%d: nonzero read/write bulk status received: %d",
+			usblp->minor, urb->status);
+	usblp->wcomplete = 1;
 	wake_up_interruptible(&usblp->wait);
 }
 
@@ -238,6 +255,8 @@
 
 	usblp->writeurb.transfer_buffer_length = 0;
 	usblp->writeurb.status = 0;
+	usblp->wcomplete = 1; /* we begin writeable */
+	usblp->rcomplete = 0;
 
 	if (usblp->bidir) {
 		usblp->readcount = 0;
@@ -369,26 +388,33 @@
 
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	struct usblp *usblp = file->private_data;
 	int timeout, err = 0, writecount = 0;
 
 	while (writecount < count) {
-
-		// FIXME:  only use urb->status inside completion
-		// callbacks; this way is racey...
-		if (usblp->writeurb.status == -EINPROGRESS) {
-
+		if (!usblp->wcomplete) {
+			barrier();
 			if (file->f_flags & O_NONBLOCK)
 				return -EAGAIN;
 
 			timeout = USBLP_WRITE_TIMEOUT;
-			while (timeout && usblp->writeurb.status == -EINPROGRESS) {
+			add_wait_queue(&usblp->wait, &wait);
+			while ( 1==1 ) {
 
-				if (signal_pending(current))
+				if (signal_pending(current)) {
+					remove_wait_queue(&usblp->wait, &wait);
 					return writecount ? writecount : -EINTR;
-
-				timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
+				}
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (timeout && !usblp->wcomplete) {
+					timeout = schedule_timeout(timeout);
+				} else {
+					set_current_state(TASK_RUNNING);
+					break;
+				}
 			}
+			remove_wait_queue(&usblp->wait, &wait);
 		}
 
 		down (&usblp->sem);
@@ -399,7 +425,7 @@
 
 		if (usblp->writeurb.status != 0) {
 			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-				if (usblp->writeurb.status != -EINPROGRESS)
+				if (!usblp->wcomplete)
 					err("usblp%d: error %d writing to printer",
 						usblp->minor, usblp->writeurb.status);
 				err = usblp->writeurb.status;
@@ -429,7 +455,12 @@
 				usblp->writeurb.transfer_buffer_length)) return -EFAULT;
 
 		usblp->writeurb.dev = usblp->dev;
-		usb_submit_urb(&usblp->writeurb);
+		usblp->wcomplete = 0;
+		if (usb_submit_urb(&usblp->writeurb)) {
+			count = -EIO;
+			up (&usblp->sem);
+			break;
+		}
 		up (&usblp->sem);
 	}
 
@@ -439,6 +470,7 @@
 static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 
 	if (!usblp->bidir)
 		return -EINVAL;
@@ -449,7 +481,8 @@
 		goto done;
 	}
 
-	if (usblp->readurb.status == -EINPROGRESS) {
+	if (!usblp->rcomplete) {
+		barrier();
 
 		if (file->f_flags & O_NONBLOCK) {
 			count = -EAGAIN;
@@ -458,15 +491,24 @@
 
 		// FIXME:  only use urb->status inside completion
 		// callbacks; this way is racey...
-		while (usblp->readurb.status == -EINPROGRESS) {
+		add_wait_queue(&usblp->wait, &wait);
+		while (1==1) {
 			if (signal_pending(current)) {
 				count = -EINTR;
+				remove_wait_queue(&usblp->wait, &wait);
 				goto done;
 			}
 			up (&usblp->sem);
-			interruptible_sleep_on(&usblp->wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!usblp->rcomplete) {
+				schedule();
+			} else {
+				set_current_state(TASK_RUNNING);
+				break;
+			}
 			down (&usblp->sem);
 		}
+		remove_wait_queue(&usblp->wait, &wait);
 	}
 
 	if (!usblp->dev) {
@@ -495,7 +537,11 @@
 	if ((usblp->readcount += count) == usblp->readurb.actual_length) {
 		usblp->readcount = 0;
 		usblp->readurb.dev = usblp->dev;
-		usb_submit_urb(&usblp->readurb);
+		usblp->rcomplete = 0;
+		if (usb_submit_urb(&usblp->readurb)) {
+			count = -EIO;
+			goto done;
+		}
 	}
 
 done:
@@ -636,11 +682,11 @@
 	}
 
 	FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-		buf, 0, usblp_bulk, usblp);
+		buf, 0, usblp_bulk_write, usblp);
 
 	if (bidir)
 		FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
+			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp);
 
 	/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
 	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
@@ -715,6 +761,7 @@
 MODULE_DEVICE_TABLE (usb, usblp_ids);
 
 static struct usb_driver usblp_driver = {
+	owner:		THIS_MODULE,
 	name:		"usblp",
 	probe:		usblp_probe,
 	disconnect:	usblp_disconnect,
diff -Nru a/drivers/usb/stv680.c b/drivers/usb/stv680.c
--- a/drivers/usb/stv680.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/stv680.c	Tue Feb  5 19:17:21 2002
@@ -50,6 +50,12 @@
  *                         improve quality. Got rid of green line around 
  *                         frame. Fix brightness reset when changing size 
  *                         bug. Adjusted gamma filters slightly.
+ *
+ * ver 0.25 Jan, 2002 (kjs)
+ *			   Fixed a bug in which the driver sometimes attempted
+ *			   to set to a non-supported size. This allowed
+ *			   gnomemeeting to work.
+ *			   Fixed proc entry removal bug.
  */
 
 #include <linux/config.h>
@@ -87,7 +93,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.24"
+#define DRIVER_VERSION "v0.25"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -659,7 +665,7 @@
 	if (stv680_proc_entry == NULL)
 		return;
 
-	remove_proc_entry ("stv", video_proc_entry);
+	remove_proc_entry ("stv680", video_proc_entry);
 }
 #endif				/* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
@@ -862,20 +868,23 @@
 	if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
 		width = stv680->maxwidth / 2;
 		height = stv680->maxheight / 2;
-	} else if ((width >= 158) && (width <= 166)) {
+	} else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
 		width = 160;
 		height = 120;
-	} else if ((width >= 172) && (width <= 180)) {
+	} else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
 		width = 176;
 		height = 144;
-	} else if ((width >= 318) && (width <= 350)) {
+	} else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
 		width = 320;
 		height = 240;
-	} else if ((width >= 350) && (width <= 358)) {
+	} else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
 		width = 352;
 		height = 288;
+	} else {
+		PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+		return 1;
 	}
-
+	
 	/* Stop a current stream and start it again at the new size */
 	if (wasstreaming)
 		stv680_stop_stream (stv680);
diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c
--- a/drivers/usb/usb.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/usb.c	Tue Feb  5 19:17:21 2002
@@ -1100,7 +1100,7 @@
 	}
 
 	memset(urb, 0, sizeof(*urb));
-	atomic_inc(&urb->count);
+	urb->count = (atomic_t)ATOMIC_INIT(1);
 	spin_lock_init(&urb->lock);
 
 	return urb;
@@ -2283,7 +2283,7 @@
 	/* 9.4.10 says devices don't need this, if the interface
 	   only has one alternate setting */
 	if (iface->num_altsetting == 1) {
-		warn("ignoring set_interface for dev %d, iface %d, alt %d",
+		dbg("ignoring set_interface for dev %d, iface %d, alt %d",
 			dev->devnum, interface, alternate);
 		return 0;
 	}
diff -Nru a/drivers/usb/vicam.c b/drivers/usb/vicam.c
--- a/drivers/usb/vicam.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/usb/vicam.c	Tue Feb  5 19:17:21 2002
@@ -79,7 +79,7 @@
 static struct usb_driver vicam_driver;
 
 static char *buf, *buf2;
-static int change_pending = 0; 
+static volatile int change_pending = 0; 
 
 static int vicam_parameters(struct usb_vicam *vicam);
 
@@ -330,8 +330,14 @@
 
 static void synchronize(struct usb_vicam *vicam)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	change_pending = 1;
-	interruptible_sleep_on(&vicam->wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&vicam->wait, &wait);
+	if (change_pending)
+		schedule();
+	remove_wait_queue(&vicam->wait, &wait);
+	set_current_state(TASK_RUNNING);
 	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
 	mdelay(10);
 	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c	Tue Feb  5 19:17:21 2002
+++ b/drivers/video/neofb.c	Tue Feb  5 19:17:21 2002
@@ -46,7 +46,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/pci.h>
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/dir.c	Tue Feb  5 19:17:21 2002
@@ -402,6 +402,21 @@
 }
 
 /*
+ * A check for whether or not the parent directory has changed.
+ * In the case it has, we assume that the dentries are untrustworthy
+ * and may need to be looked up again.
+ */
+static inline
+int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
+{
+	if (IS_ROOT(dentry))
+		return 1;
+	if (nfs_revalidate_inode(NFS_SERVER(dir), dir))
+		return 0;
+	return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir));
+}
+
+/*
  * Whenever an NFS operation succeeds, we know that the dentry
  * is valid, so we update the revalidation timestamp.
  */
@@ -410,48 +425,31 @@
 	dentry->d_time = jiffies;
 }
 
-static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
+static inline
+int nfs_lookup_verify_inode(struct inode *inode, int flags)
 {
-	struct inode *inode = dentry->d_inode;
-	unsigned long timeout = NFS_ATTRTIMEO(inode);
-
+	struct nfs_server *server = NFS_SERVER(inode);
 	/*
-	 * If it's the last lookup in a series, we use a stricter
-	 * cache consistency check by looking at the parent mtime.
-	 *
-	 * If it's been modified in the last hour, be really strict.
-	 * (This still means that we can avoid doing unnecessary
-	 * work on directories like /usr/share/bin etc which basically
-	 * never change).
+	 * If we're interested in close-to-open cache consistency,
+	 * then we revalidate the inode upon lookup.
 	 */
-	if (!(flags & LOOKUP_CONTINUE)) {
-		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
-
-		if (diff < 15*60)
-			timeout = 0;
-	}
-	
-	return time_after(jiffies,dentry->d_time + timeout);
+	if (!(server->flags & NFS_MOUNT_NOCTO) && !(flags & LOOKUP_CONTINUE))
+		NFS_CACHEINV(inode);
+	return nfs_revalidate_inode(server, inode);
 }
 
 /*
  * We judge how long we want to trust negative
  * dentries by looking at the parent inode mtime.
  *
- * If mtime is close to present time, we revalidate
- * more often.
+ * If parent mtime has changed, we revalidate, else we wait for a
+ * period corresponding to the parent's attribute cache timeout value.
  */
-#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
-static inline int nfs_neg_need_reval(struct dentry *dentry)
+static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
-	unsigned long timeout = NFS_ATTRTIMEO(dir);
-	long diff = CURRENT_TIME - dir->i_mtime;
-
-	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
-		timeout = NFS_REVALIDATE_NEGATIVE;
-
-	return time_after(jiffies, dentry->d_time + timeout);
+	if (!nfs_check_verifier(dir, dentry))
+		return 1;
+	return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
 }
 
 /*
@@ -462,9 +460,8 @@
  * NOTE! The hit can be a negative hit too, don't assume
  * we have an inode!
  *
- * If the dentry is older than the revalidation interval, 
- * we do a new lookup and verify that the dentry is still
- * correct.
+ * If the parent directory is seen to have changed, we throw out the
+ * cached dentry and do a new lookup.
  */
 static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
@@ -477,13 +474,9 @@
 	lock_kernel();
 	dir = dentry->d_parent->d_inode;
 	inode = dentry->d_inode;
-	/*
-	 * If we don't have an inode, let's look at the parent
-	 * directory mtime to get a hint about how often we
-	 * should validate things..
-	 */
+
 	if (!inode) {
-		if (nfs_neg_need_reval(dentry))
+		if (nfs_neg_need_reval(dir, dentry))
 			goto out_bad;
 		goto out_valid;
 	}
@@ -494,48 +487,39 @@
 		goto out_bad;
 	}
 
-	if (!nfs_dentry_force_reval(dentry, flags))
+	/* Force a full look up iff the parent directory has changed */
+	if (nfs_check_verifier(dir, dentry)) {
+		if (nfs_lookup_verify_inode(inode, flags))
+			goto out_bad;
 		goto out_valid;
-
-	if (IS_ROOT(dentry)) {
-		__nfs_revalidate_inode(NFS_SERVER(inode), inode);
-		goto out_valid_renew;
 	}
 
-	/*
-	 * Do a new lookup and check the dentry attributes.
-	 */
+	if (NFS_STALE(inode))
+		goto out_bad;
+
 	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	if (error)
 		goto out_bad;
-
-	/* Inode number matches? */
-	if (!(fattr.valid & NFS_ATTR_FATTR) ||
-	    NFS_FSID(inode) != fattr.fsid ||
-	    NFS_FILEID(inode) != fattr.fileid)
+	if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
 		goto out_bad;
-
-	/* Ok, remember that we successfully checked it.. */
-	nfs_refresh_inode(inode, &fattr);
-
-	if (nfs_inode_is_stale(inode, &fhandle, &fattr))
+	if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
 		goto out_bad;
 
- out_valid_renew:
 	nfs_renew_times(dentry);
-out_valid:
+ out_valid:
 	unlock_kernel();
 	return 1;
-out_bad:
-	shrink_dcache_parent(dentry);
-	/* If we have submounts, don't unhash ! */
-	if (have_submounts(dentry))
-		goto out_valid;
-	d_drop(dentry);
-	/* Purge readdir caches. */
-	nfs_zap_caches(dir);
-	if (inode && S_ISDIR(inode->i_mode))
+ out_bad:
+	NFS_CACHEINV(dir);
+	if (inode && S_ISDIR(inode->i_mode)) {
+		/* Purge readdir caches. */
 		nfs_zap_caches(inode);
+		/* If we have submounts, don't unhash ! */
+		if (have_submounts(dentry))
+			goto out_valid;
+		shrink_dcache_parent(dentry);
+	}
+	d_drop(dentry);
 	unlock_kernel();
 	return 0;
 }
@@ -565,6 +549,7 @@
 {
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
 		lock_kernel();
+		inode->i_nlink--;
 		nfs_complete_unlink(dentry);
 		unlock_kernel();
 	}
@@ -604,9 +589,9 @@
 		if (inode) {
 	    no_entry:
 			d_add(dentry, inode);
-			nfs_renew_times(dentry);
 			error = 0;
 		}
+		nfs_renew_times(dentry);
 	}
 out:
 	return ERR_PTR(error);
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/inode.c	Tue Feb  5 19:17:21 2002
@@ -630,39 +630,18 @@
 	struct nfs_fh		*fh = desc->fh;
 	struct nfs_fattr	*fattr = desc->fattr;
 
-	if (NFS_FSID(inode) != fattr->fsid)
-		return 0;
 	if (NFS_FILEID(inode) != fattr->fileid)
 		return 0;
 	if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0)
 		return 0;
+	if (is_bad_inode(inode))
+		return 0;
 	/* Force an attribute cache update if inode->i_count == 0 */
 	if (!atomic_read(&inode->i_count))
 		NFS_CACHEINV(inode);
 	return 1;
 }
 
-int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
-{
-	/* Empty inodes are not stale */
-	if (!inode->i_mode)
-		return 0;
-
-	if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		return 1;
-
-	if (is_bad_inode(inode) || NFS_STALE(inode))
-		return 1;
-
-	/* Has the filehandle changed? If so is the old one stale? */
-	if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0 &&
-	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
-		return 1;
-
-	return 0;
-}
-
 /*
  * This is our own version of iget that looks up inodes by file handle
  * instead of inode number.  We use this technique instead of using
@@ -713,7 +692,6 @@
 		/* We can't support UPDATE_ATIME(), since the server will reset it */
 		NFS_FLAGS(inode) &= ~NFS_INO_NEW;
 		NFS_FILEID(inode) = fattr->fileid;
-		NFS_FSID(inode) = fattr->fsid;
 		memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
 		inode->i_flags |= S_NOATIME;
 		inode->i_mode = fattr->mode;
@@ -787,7 +765,7 @@
 	/*
 	 * Make sure the inode is up-to-date.
 	 */
-	error = nfs_revalidate(dentry);
+	error = nfs_revalidate_inode(NFS_SERVER(inode),inode);
 	if (error) {
 #ifdef NFS_PARANOIA
 printk("nfs_notify_change: revalidate failed, error=%d\n", error);
@@ -1025,12 +1003,11 @@
 			inode->i_sb->s_id, inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
-	if (NFS_FSID(inode) != fattr->fsid ||
-	    NFS_FILEID(inode) != fattr->fileid) {
+	if (NFS_FILEID(inode) != fattr->fileid) {
 		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
-		       "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n",
-		       (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode),
-		       (long long)fattr->fsid, (long long)fattr->fileid);
+		       "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
+		       inode->i_sb->s_id, (long long)NFS_FILEID(inode),
+		       inode->i_sb->s_id, (long long)fattr->fileid);
 		goto out_err;
 	}
 
@@ -1100,8 +1077,11 @@
 
 	inode->i_atime = new_atime;
 
-	NFS_CACHE_MTIME(inode) = new_mtime;
-	inode->i_mtime = nfs_time_to_secs(new_mtime);
+	if (NFS_CACHE_MTIME(inode) != new_mtime) {
+		NFS_MTIME_UPDATE(inode) = jiffies;
+		NFS_CACHE_MTIME(inode) = new_mtime;
+		inode->i_mtime = nfs_time_to_secs(new_mtime);
+	}
 
 	NFS_CACHE_ISIZE(inode) = new_size;
 	inode->i_size = new_isize;
@@ -1175,10 +1155,6 @@
 	if (!nfsi)
 		return NULL;
 	nfsi->flags = NFS_INO_NEW;
-	/* do we need the next 4 lines? */
-	nfsi->hash_next = NULL;
-	nfsi->hash_prev = NULL;
-	nfsi->nextscan = 0;
 	nfsi->mm_cred = NULL;
 	return &nfsi->vfs_inode;
 }
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/nfs3proc.c	Tue Feb  5 19:17:21 2002
@@ -80,7 +80,8 @@
 		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR,
 			 fhandle, fattr, 0);
 	dprintk("NFS reply lookup: %d\n", status);
-	nfs_refresh_inode(dir, &dir_attr);
+	if (status >= 0)
+		status = nfs_refresh_inode(dir, &dir_attr);
 	return status;
 }
 
diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/pagelist.c	Tue Feb  5 19:17:21 2002
@@ -53,7 +53,7 @@
 
 /**
  * nfs_create_request - Create an NFS read/write request.
- * @file: file that owns this request
+ * @cred: RPC credential to use
  * @inode: inode to which the request is attached
  * @page: page to write
  * @offset: starting offset within the page for the write
@@ -66,7 +66,7 @@
  * User should ensure it is safe to sleep in this function.
  */
 struct nfs_page *
-nfs_create_request(struct file *file, struct inode *inode,
+nfs_create_request(struct rpc_cred *cred, struct inode *inode,
 		   struct page *page,
 		   unsigned int offset, unsigned int count)
 {
@@ -107,34 +107,49 @@
 	req->wb_offset  = offset;
 	req->wb_bytes   = count;
 
-	/* If we have a struct file, use its cached credentials */
-	if (file) {
-		req->wb_file    = file;
-		get_file(file);
-		req->wb_cred	= nfs_file_cred(file);
-	}
+	if (cred)
+		req->wb_cred = get_rpccred(cred);
 	req->wb_inode   = inode;
 	req->wb_count   = 1;
 
 	return req;
 }
 
+/**
+ * nfs_clear_request - Free up all resources allocated to the request
+ * @req:
+ *
+ * Release all resources associated with a write request after it
+ * has completed.
+ */
+void nfs_clear_request(struct nfs_page *req)
+{
+	/* Release struct file or cached credential */
+	if (req->wb_file) {
+		fput(req->wb_file);
+		req->wb_file = NULL;
+	}
+	if (req->wb_cred) {
+		put_rpccred(req->wb_cred);
+		req->wb_cred = NULL;
+	}
+	if (req->wb_page) {
+		page_cache_release(req->wb_page);
+		req->wb_page = NULL;
+		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
+	}
+}
+
 
 /**
  * nfs_release_request - Release the count on an NFS read/write request
  * @req: request to release
  *
- * Release all resources associated with a write request after it
- * has been committed to stable storage
- *
  * Note: Should never be called with the spinlock held!
  */
 void
 nfs_release_request(struct nfs_page *req)
 {
-	struct inode		*inode = req->wb_inode;
-	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
-
 	spin_lock(&nfs_wreq_lock);
 	if (--req->wb_count) {
 		spin_unlock(&nfs_wreq_lock);
@@ -142,7 +157,6 @@
 	}
 	__nfs_del_lru(req);
 	spin_unlock(&nfs_wreq_lock);
-	atomic_dec(&cache->nr_requests);
 
 #ifdef NFS_PARANOIA
 	if (!list_empty(&req->wb_list))
@@ -151,16 +165,12 @@
 		BUG();
 	if (NFS_WBACK_BUSY(req))
 		BUG();
-	if (atomic_read(&cache->nr_requests) < 0)
+	if (atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0)
 		BUG();
 #endif
 
 	/* Release struct file or cached credential */
-	if (req->wb_file)
-		fput(req->wb_file);
-	else if (req->wb_cred)
-		put_rpccred(req->wb_cred);
-	page_cache_release(req->wb_page);
+	nfs_clear_request(req);
 	nfs_page_free(req);
 }
 
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/read.c	Tue Feb  5 19:17:21 2002
@@ -171,7 +171,7 @@
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page	*new;
 
-	new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
+	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
 	if (IS_ERR(new))
 		return PTR_ERR(new);
 	nfs_mark_request_read(new);
@@ -227,8 +227,9 @@
 		nfs_list_remove_request(req);
 		SetPageError(page);
 		UnlockPage(page);
-		nfs_unlock_request(req);
+		nfs_clear_request(req);
 		nfs_release_request(req);
+		nfs_unlock_request(req);
 	}
 }
 
@@ -433,6 +434,7 @@
                         (long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (long long)(page_offset(page) + req->wb_offset));
+		nfs_clear_request(req);
 		nfs_release_request(req);
 		nfs_unlock_request(req);
 	}
@@ -450,18 +452,8 @@
 int
 nfs_readpage(struct file *file, struct page *page)
 {
-	struct inode *inode;
+	struct inode *inode = page->mapping->host;
 	int		error;
-
-	if (!file) {
-		struct address_space *mapping = page->mapping;
-		if (!mapping)
-			BUG();
-		inode = mapping->host;
-	} else
-		inode = file->f_dentry->d_inode;
-	if (!inode)
-		BUG();
 
 	dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
 		page, PAGE_CACHE_SIZE, page->index);
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Tue Feb  5 19:17:21 2002
+++ b/fs/nfs/write.c	Tue Feb  5 19:17:21 2002
@@ -239,17 +239,11 @@
 int
 nfs_writepage(struct page *page)
 {
-	struct inode *inode;
+	struct inode *inode = page->mapping->host;
 	unsigned long end_index;
 	unsigned offset = PAGE_CACHE_SIZE;
 	int err;
-	struct address_space *mapping = page->mapping;
 
-	if (!mapping)
-		BUG();
-	inode = mapping->host;
-	if (!inode)
-		BUG();
 	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 
 	/* Ensure we've flushed out any previous writes */
@@ -354,6 +348,7 @@
 		iput(inode);
 	} else
 		spin_unlock(&nfs_wreq_lock);
+	nfs_clear_request(req);
 	nfs_release_request(req);
 }
 
@@ -684,9 +679,13 @@
 		}
 		spin_unlock(&nfs_wreq_lock);
 
-		new = nfs_create_request(file, inode, page, offset, bytes);
+		new = nfs_create_request(nfs_file_cred(file), inode, page, offset, bytes);
 		if (IS_ERR(new))
 			return new;
+		if (file) {
+			new->wb_file = file;
+			get_file(file);
+		}
 		/* If the region is locked, adjust the timeout */
 		if (region_locked(inode, new))
 			new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
@@ -764,7 +763,7 @@
 int
 nfs_flush_incompatible(struct file *file, struct page *page)
 {
-	struct inode	*inode = file->f_dentry->d_inode;
+	struct inode	*inode = page->mapping->host;
 	struct nfs_page	*req;
 	int		status = 0;
 	/*
@@ -794,7 +793,7 @@
 nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count)
 {
 	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
+	struct inode	*inode = page->mapping->host;
 	struct nfs_page	*req;
 	loff_t		end;
 	int		status = 0;
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/dir.c	Tue Feb  5 19:17:21 2002
@@ -76,7 +76,7 @@
 		
 	/* we must have found item, that is item of this directory, */
 	RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
-		"vs-9000: found item %h does not match to dir we readdir %k",
+		"vs-9000: found item %h does not match to dir we readdir %K",
 		ih, &pos_key);
 	RFALSE( item_num > B_NR_ITEMS (bh) - 1,
 		"vs-9005 item_num == %d, item amount == %d", 
diff -Nru a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
--- a/fs/reiserfs/fix_node.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/fix_node.c	Tue Feb  5 19:17:21 2002
@@ -2356,7 +2356,6 @@
     for ( n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++ ) { 
 	if ( (n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON ) {
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = check_balance (n_op_mode, p_s_tb, n_h, n_item_num,
@@ -2365,7 +2364,6 @@
 		/* No balancing for higher levels needed. */
 		if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
 		    goto repeat;
-		    return n_ret_value;
 		}
 		if ( n_h != MAX_HEIGHT - 1 )  
 		    p_s_tb->insert_size[n_h + 1] = 0;
@@ -2373,17 +2371,14 @@
 		break;
 	    }
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
 	    goto repeat;
-	    return n_ret_value;
 	}
 
 	if ( (n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON ) {
-	    goto repeat;
-	    return n_ret_value; /* No disk space, or schedule occurred and
+	    goto repeat;        /* No disk space, or schedule occurred and
 				   analysis may be invalid and needs to be redone. */
 	}
     
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/inode.c	Tue Feb  5 19:17:21 2002
@@ -743,7 +743,8 @@
 
 		retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
 		if (retval) {
-		    printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ;
+		    if ( retval != -ENOSPC )
+			printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ;
 		    if (allocated_block_nr)
 			reiserfs_free_block (&th, allocated_block_nr);
 		    goto failure ;
@@ -888,6 +889,8 @@
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
     inode->i_blksize = PAGE_SIZE;
 
+    INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));
+
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
 	unsigned long blocks;
@@ -1152,6 +1155,7 @@
 	/* a stale NFS handle can trigger this without it being an error */
 	pathrelse (&path_to_sd);
 	make_bad_inode(inode) ;
+	inode->i_nlink = 0;
 	return;
     }
 
@@ -1184,6 +1188,27 @@
 
 }
 
+/**
+ * reiserfs_find_actor() - "find actor" reiserfs supplies to iget4().
+ *
+ * @inode:    inode from hash table to check
+ * @inode_no: inode number we are looking for
+ * @opaque:   "cookie" passed to iget4(). This is &reiserfs_iget4_args.
+ *
+ * This function is called by iget4() to distinguish reiserfs inodes
+ * having the same inode numbers. Such inodes can only exist due to some
+ * error condition. One of them should be bad. Inodes with identical
+ * inode numbers (objectids) are distinguished by parent directory ids.
+ *
+ */
+static int reiserfs_find_actor( struct inode *inode, 
+				unsigned long inode_no, void *opaque )
+{
+    struct reiserfs_iget4_args *args;
+
+    args = opaque;
+    return INODE_PKEY( inode ) -> k_dir_id == args -> objectid;
+}
 
 struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key)
 {
@@ -1191,7 +1216,8 @@
     struct reiserfs_iget4_args args ;
 
     args.objectid = key->on_disk_key.k_dir_id ;
-    inode = iget4 (s, key->on_disk_key.k_objectid, 0, (void *)(&args));
+    inode = iget4 (s, key->on_disk_key.k_objectid, 
+		   reiserfs_find_actor, (void *)(&args));
     if (!inode) 
 	return ERR_PTR(-ENOMEM) ;
 
@@ -1532,6 +1558,7 @@
     REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
+    INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));
     REISERFS_I(inode)->i_flags = 0;
     REISERFS_I(inode)->i_prealloc_block = 0;
     REISERFS_I(inode)->i_prealloc_count = 0;
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/journal.c	Tue Feb  5 19:17:21 2002
@@ -797,7 +797,7 @@
   while(cn) {
     if (cn->blocknr != 0) {
       if (debug) {
-        printk("block %lu, bh is %d, state %d\n", cn->blocknr, cn->bh ? 1: 0, 
+        printk("block %lu, bh is %d, state %ld\n", cn->blocknr, cn->bh ? 1: 0, 
 	        cn->state) ;
       }
       cn->state = 0 ;
diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
--- a/fs/reiserfs/namei.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/namei.c	Tue Feb  5 19:17:21 2002
@@ -470,7 +470,7 @@
     if (gen_number != 0) {	/* we need to re-search for the insertion point */
       if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
             reiserfs_warning ("vs-7032: reiserfs_add_entry: "
-                            "entry with this key (%k) already exists\n", &entry_key);
+                            "entry with this key (%K) already exists\n", &entry_key);
 
 	    if (buffer != small_buf)
 		reiserfs_kfree (buffer, buflen, dir->i_sb);
diff -Nru a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
--- a/fs/reiserfs/procfs.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/procfs.c	Tue Feb  5 19:17:21 2002
@@ -465,7 +465,7 @@
  			"jp_journal_max_trans_age: \t%i\n"
 			/* incore fields */
 			"j_1st_reserved_block: \t%i\n"	  
-			"j_state: \t%i\n"			
+			"j_state: \t%li\n"			
 			"j_trans_id: \t%lu\n"
 			"j_mount_id: \t%lu\n"
 			"j_start: \t%lu\n"
diff -Nru a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
--- a/fs/reiserfs/stree.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/stree.c	Tue Feb  5 19:17:21 2002
@@ -126,19 +126,19 @@
   retval = comp_short_keys (le_key, cpu_key);
   if (retval)
       return retval;
-  if (le_key_k_offset (cpu_key->version, le_key) < cpu_key_k_offset (cpu_key))
+  if (le_key_k_offset (le_key_version(le_key), le_key) < cpu_key_k_offset (cpu_key))
       return -1;
-  if (le_key_k_offset (cpu_key->version, le_key) > cpu_key_k_offset (cpu_key))
+  if (le_key_k_offset (le_key_version(le_key), le_key) > cpu_key_k_offset (cpu_key))
       return 1;
 
   if (cpu_key->key_length == 3)
       return 0;
 
   /* this part is needed only when tail conversion is in progress */
-  if (le_key_k_type (cpu_key->version, le_key) < cpu_key_k_type (cpu_key))
+  if (le_key_k_type (le_key_version(le_key), le_key) < cpu_key_k_type (cpu_key))
     return -1;
 
-  if (le_key_k_type (cpu_key->version, le_key) > cpu_key_k_type (cpu_key))
+  if (le_key_k_type (le_key_version(le_key), le_key) > cpu_key_k_type (cpu_key))
     return 1;
 
   return 0;
@@ -166,7 +166,7 @@
     if (cpu_key_k_offset (key1) > cpu_key_k_offset (key2))
 	return 1;
 
-    reiserfs_warning ("comp_cpu_keys: type are compared for %k and %k\n",
+    reiserfs_warning ("comp_cpu_keys: type are compared for %K and %K\n",
 		      key1, key2);
 
     if (cpu_key_k_type (key1) < cpu_key_k_type (key2))
@@ -1338,8 +1338,10 @@
 	}
 	if (retval != ITEM_FOUND) {
 	    pathrelse (&path);
-	    reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found",
-			      key);
+	    // No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir
+	    if ( !( (unsigned long long) GET_HASH_VALUE (le_key_k_offset (le_key_version (key), key)) == 0 && \
+		 (unsigned long long) GET_GENERATION_NUMBER (le_key_k_offset (le_key_version (key), key)) == 1 ) )
+		reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found", key);
 	    break;
 	}
 	if (!tb_init) {
@@ -1522,7 +1524,7 @@
 	    set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);
 	    if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){
 		print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);
-		reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%k)", p_s_item_key);
+		reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)", p_s_item_key);
 	    }
 	    continue;
 	}
@@ -1716,7 +1718,7 @@
 	}
 
 	RFALSE( n_deleted > n_file_size,
-		"PAP-5670: reiserfs_truncate_file returns too big number: deleted %d, file_size %lu, item_key %k",
+		"PAP-5670: reiserfs_truncate_file returns too big number: deleted %d, file_size %lu, item_key %K",
 		n_deleted, n_file_size, &s_item_key);
 
 	/* Change key to search the last file item. */
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/super.c	Tue Feb  5 19:17:21 2002
@@ -284,7 +284,8 @@
     /* look for its place in the tree */
     retval = search_item (inode->i_sb, &key, &path);
     if (retval != ITEM_NOT_FOUND) {
-	reiserfs_warning ("vs-2100: add_save_link:"
+	if ( retval != -ENOSPC )
+	    reiserfs_warning ("vs-2100: add_save_link:"
 			  "search_by_key (%K) returned %d\n", &key, retval);
 	pathrelse (&path);
 	return;
@@ -746,6 +747,14 @@
 		s->s_id, bh->b_blocknr, s->s_blocksize);
 	brelse (bh);
 	return 1;
+    }
+
+    if ( rs->s_v1.s_root_block == -1 ) {
+       brelse(bh) ;
+       printk("dev %s: Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
+              "reiserfsck --rebuild-tree and wait for a completion. If that fais\n"
+              "get newer reiserfsprogs package\n", kdevname (s->s_dev));
+       return 1;
     }
 
     SB_BUFFER_WITH_SB (s) = bh;
diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c	Tue Feb  5 19:17:21 2002
+++ b/fs/reiserfs/tail_conversion.c	Tue Feb  5 19:17:21 2002
@@ -90,10 +90,10 @@
            last item of the file */
 	if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND )
 	    reiserfs_panic (sb, "PAP-14050: direct2indirect: "
-			    "direct item (%k) not found", &end_key);
+			    "direct item (%K) not found", &end_key);
 	p_le_ih = PATH_PITEM_HEAD (path);
 	RFALSE( !is_direct_le_ih (p_le_ih),
-	        "vs-14055: direct item expected(%k), found %h",
+	        "vs-14055: direct item expected(%K), found %h",
                 &end_key, p_le_ih);
         tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
             + ih_item_len(p_le_ih) - 1;
@@ -228,7 +228,7 @@
 	/* re-search indirect item */
 	if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND )
 	    reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: "
-			   "item to be converted %k does not exist", p_s_item_key);
+			   "item to be converted %K does not exist", p_s_item_key);
 	copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
 #ifdef CONFIG_REISERFS_CHECK
 	pos = le_ih_k_offset (&s_ih) - 1 + 
diff -Nru a/fs/ufs/file.c b/fs/ufs/file.c
--- a/fs/ufs/file.c	Tue Feb  5 19:17:21 2002
+++ b/fs/ufs/file.c	Tue Feb  5 19:17:21 2002
@@ -35,6 +35,7 @@
 #include <linux/locks.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
 
 /*
  * Make sure the offset never goes beyond the 32-bit mark..
diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h
--- a/include/asm-i386/pci.h	Tue Feb  5 19:17:21 2002
+++ b/include/asm-i386/pci.h	Tue Feb  5 19:17:21 2002
@@ -118,7 +118,7 @@
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 #define pci_unmap_addr(PTR, ADDR_NAME)		(0)
-#define pci_unmap_addr_SET(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
 #define pci_unmap_len(PTR, LEN_NAME)		(0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Tue Feb  5 19:17:21 2002
+++ b/include/asm-sparc/unistd.h	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.72 2001/10/18 08:27:05 davem Exp $ */
+/* $Id: unistd.h,v 1.73 2002/01/31 03:30:13 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -184,24 +184,24 @@
 /* #define __NR_exportfs        166    SunOS Specific                              */
 #define __NR_mount              167 /* Common                                      */
 #define __NR_ustat              168 /* Common                                      */
-/* #define __NR_semsys          169    SunOS Specific                              */
-/* #define __NR_msgsys          170    SunOS Specific                              */
-/* #define __NR_shmsys          171    SunOS Specific                              */
-/* #define __NR_auditsys        172    SunOS Specific                              */
-/* #define __NR_rfssys          173    SunOS Specific                              */
+#define __NR_setxattr           169 /* SunOS: semsys                               */
+#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define __NR_getxattr           172 /* SunOS: auditsys                             */
+#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
 #define __NR_getdents           174 /* Common                                      */
 #define __NR_setsid             175 /* Common                                      */
 #define __NR_fchdir             176 /* Common                                      */
-/* #define __NR_fchroot         177    SunOS Specific                              */
-/* #define __NR_vpixsys         178    SunOS Specific                              */
-/* #define __NR_aioread         179    SunOS Specific                              */
-/* #define __NR_aiowrite        180    SunOS Specific                              */
-/* #define __NR_aiowait         181    SunOS Specific                              */
-/* #define __NR_aiocancel       182    SunOS Specific                              */
+#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define __NR_listxattr          178 /* SunOS: vpixsys                              */
+#define __NR_llistxattr         179 /* SunOS: aioread                              */
+#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define __NR_removexattr        181 /* SunOS: aiowait                              */
+#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
+#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 /* #define __NR_fpathconf       187    SunOS Specific                              */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
diff -Nru a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
--- a/include/asm-sparc64/bitops.h	Tue Feb  5 19:17:21 2002
+++ b/include/asm-sparc64/bitops.h	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $
+/* $Id: bitops.h,v 1.39 2002/01/30 01:40:00 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -64,54 +64,38 @@
 #define smp_mb__before_clear_bit()	do { } while(0)
 #define smp_mb__after_clear_bit()	do { } while(0)
 
-extern __inline__ int test_bit(int nr, __const__ void *addr)
+static __inline__ int test_bit(int nr, __const__ void *addr)
 {
 	return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63))) != 0UL;
 }
 
 /* The easy/cheese version for now. */
-extern __inline__ unsigned long ffz(unsigned long word)
+static __inline__ unsigned long ffz(unsigned long word)
 {
 	unsigned long result;
 
-#ifdef ULTRA_HAS_POPULATION_COUNT	/* Thanks for nothing Sun... */
-	__asm__ __volatile__(
-"	brz,pn	%0, 1f\n"
-"	 neg	%0, %%g1\n"
-"	xnor	%0, %%g1, %%g2\n"
-"	popc	%%g2, %0\n"
-"1:	" : "=&r" (result)
-	  : "0" (word)
-	  : "g1", "g2");
-#else
-#if 1 /* def EASY_CHEESE_VERSION */
 	result = 0;
 	while(word & 1) {
 		result++;
 		word >>= 1;
 	}
-#else
-	unsigned long tmp;
+	return result;
+}
 
-	result = 0;	
-	tmp = ~word & -~word;
-	if (!(unsigned)tmp) {
-		tmp >>= 32;
-		result = 32;
-	}
-	if (!(unsigned short)tmp) {
-		tmp >>= 16;
-		result += 16;
-	}
-	if (!(unsigned char)tmp) {
-		tmp >>= 8;
-		result += 8;
-	}
-	if (tmp & 0xf0) result += 4;
-	if (tmp & 0xcc) result += 2;
-	if (tmp & 0xaa) result ++;
-#endif
-#endif
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+	unsigned long result = 0;
+
+	while (!(word & 1UL)) {
+		result++;
+		word >>= 1;
+	}
 	return result;
 }
 
@@ -122,8 +106,12 @@
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
-
-#define ffs(x) generic_ffs(x)
+static __inline__ int ffs(int x)
+{
+	if (!x)
+		return 0;
+	return __ffs((unsigned long)x);
+}
 
 /*
  * hweightN: returns the hamming weight (i.e. the number
@@ -132,7 +120,7 @@
 
 #ifdef ULTRA_HAS_POPULATION_COUNT
 
-extern __inline__ unsigned int hweight32(unsigned int w)
+static __inline__ unsigned int hweight32(unsigned int w)
 {
 	unsigned int res;
 
@@ -140,7 +128,7 @@
 	return res;
 }
 
-extern __inline__ unsigned int hweight16(unsigned int w)
+static __inline__ unsigned int hweight16(unsigned int w)
 {
 	unsigned int res;
 
@@ -148,7 +136,7 @@
 	return res;
 }
 
-extern __inline__ unsigned int hweight8(unsigned int w)
+static __inline__ unsigned int hweight8(unsigned int w)
 {
 	unsigned int res;
 
@@ -165,12 +153,67 @@
 #endif
 #endif /* __KERNEL__ */
 
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ unsigned long find_next_bit(void *addr, unsigned long size, unsigned long offset)
+{
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long result = offset & ~63UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 63UL;
+	if (offset) {
+		tmp = *(p++);
+		tmp &= (~0UL << offset);
+		if (size < 64)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= 64;
+		result += 64;
+	}
+	while (size & ~63UL) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += 64;
+		size -= 64;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp &= (~0UL >> (64 - size));
+	if (tmp == 0UL)        /* Are any bits set? */
+		return result + size; /* Nope. */
+found_middle:
+	return result + __ffs(tmp);
+}
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+#define find_first_bit(addr, size) \
+	find_next_bit((addr), (size), 0)
+
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
  */
 
-extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
 	unsigned long result = offset & ~63UL;
@@ -219,7 +262,7 @@
 #define set_le_bit(nr,addr)		((void)___test_and_set_le_bit(nr,addr))
 #define clear_le_bit(nr,addr)		((void)___test_and_clear_le_bit(nr,addr))
 
-extern __inline__ int test_le_bit(int nr, __const__ void * addr)
+static __inline__ int test_le_bit(int nr, __const__ void * addr)
 {
 	int			mask;
 	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
@@ -232,7 +275,7 @@
 #define find_first_zero_le_bit(addr, size) \
         find_next_zero_le_bit((addr), (size), 0)
 
-extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
 	unsigned long result = offset & ~63UL;
diff -Nru a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
--- a/include/asm-sparc64/mmu_context.h	Tue Feb  5 19:17:21 2002
+++ b/include/asm-sparc64/mmu_context.h	Tue Feb  5 19:17:21 2002
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.52 2002/01/11 08:45:38 davem Exp $ */
+/* $Id: mmu_context.h,v 1.53 2002/01/30 01:40:00 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -30,22 +30,20 @@
 /*
  * Every architecture must define this function. It's the fastest
  * way of searching a 168-bit bitmap where the first 128 bits are
- * unlikely to be clear. It's guaranteed that at least one of the 168
+ * unlikely to be set. It's guaranteed that at least one of the 168
  * bits is cleared.
  */
 #if MAX_RT_PRIO != 128 || MAX_PRIO != 168
 # error update this function.
 #endif
 
-static inline int sched_find_first_zero_bit(unsigned long *b)
+static inline int sched_find_first_bit(unsigned long *b)
 {
-	unsigned long rt;
-
-	rt = b[0] & b[1];
-	if (unlikely(rt != 0xffffffffffffffff))
-		return find_first_zero_bit(b, MAX_RT_PRIO);
-
-	return ffz(b[2]) + MAX_RT_PRIO;
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 64;
+	return __ffs(b[2]) + 128;
 }
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/device.h	Tue Feb  5 19:17:21 2002
@@ -66,10 +66,8 @@
 
 struct device {
 	struct list_head node;		/* node in sibling list */
-	struct iobus	*parent;	/* parent bus */
-
-	struct iobus	*subordinate;	/* only valid if this device is a
-					   bridge device */
+	struct list_head children;
+	struct device 	* parent;
 
 	char	name[DEVICE_NAME_SIZE];	/* descriptive ascii string */
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
@@ -113,36 +111,12 @@
 	int	(*add_device)	(struct iobus*, char*);
 };
 
-struct iobus {
-	spinlock_t	lock;		/* lock for bus */
-	atomic_t	refcount;
-
-	struct list_head node;		/* node in sibling list */
-	struct iobus *parent;		/* parent bus */
-	struct list_head children;	/* children buses */
-	struct list_head devices;	/* children devices */
-
-	struct device *self;		/* pointer to controlling device */
-	struct driver_dir_entry	dir;	/* driverfs directory */
-
-	char	name[DEVICE_NAME_SIZE];
-	char	bus_id[BUS_ID_SIZE];
-
-	struct	iobus_driver *driver;	/* bus operations */
-};
-
 static inline struct device *
 list_to_dev(struct list_head *node)
 {
 	return list_entry(node, struct device, node);
 }
 
-static inline struct iobus *
-list_to_iobus(const struct list_head *node)
-{
-	return list_entry(node, struct iobus, node);
-}
-
 /*
  * High level routines for use by the bus drivers
  */
@@ -163,9 +137,6 @@
 
 extern int (*platform_notify_remove)(struct device * dev);
 
-extern int device_driver_init(void);
-
-
 /* device and bus locking helpers.
  *
  * FIXME: Is there anything else we need to do?
@@ -191,23 +162,5 @@
 }
 
 extern void put_device(struct device * dev);
-
-static inline void lock_iobus(struct iobus * iobus)
-{
-	spin_lock(&iobus->lock);
-}
-
-static inline void unlock_iobus(struct iobus * iobus)
-{
-	spin_unlock(&iobus->lock);
-}
-
-static inline void get_iobus(struct iobus * iobus)
-{
-	BUG_ON(!atomic_read(&iobus->refcount));
-	atomic_inc(&iobus->refcount);
-}
-
-extern void put_iobus(struct iobus * iobus);
 
 #endif /* _DEVICE_H_ */
diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/gameport.h	Tue Feb  5 19:17:21 2002
@@ -70,7 +70,7 @@
 void gameport_close(struct gameport *gameport);
 void gameport_rescan(struct gameport *gameport);
 
-#if defined(CONFIG_INPUT_GAMEPORT) || defined(CONFIG_INPUT_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
 void gameport_register_port(struct gameport *gameport);
 void gameport_unregister_port(struct gameport *gameport);
 #else
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/nfs_fs.h	Tue Feb  5 19:17:21 2002
@@ -92,7 +92,6 @@
 	/*
 	 * The 64bit 'inode number'
 	 */
-	__u64 fsid;
 	__u64 fileid;
 
 	/*
@@ -130,6 +129,12 @@
 	unsigned long		attrtimeo_timestamp;
 
 	/*
+	 * Timestamp that dates the change made to read_cache_mtime.
+	 * This is of use for dentry revalidation
+	 */
+	unsigned long		cache_mtime_jiffies;
+
+	/*
 	 * This is the cookie verifier used for NFSv3 readdir
 	 * operations
 	 */
@@ -148,11 +153,6 @@
 				ncommit,
 				npages;
 
-	/* Flush daemon info */
-	struct inode		*hash_next,
-				*hash_prev;
-	unsigned long		nextscan;
-
 	/* Credentials for shared mmap */
 	struct rpc_cred		*mm_cred;
 
@@ -183,6 +183,7 @@
 #define NFS_CONGESTED(inode)		(RPC_CONGESTED(NFS_CLIENT(inode)))
 #define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
 #define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
+#define NFS_MTIME_UPDATE(inode)		(NFS_I(inode)->cache_mtime_jiffies)
 #define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
 #define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
 #define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
@@ -206,7 +207,6 @@
 #define NFS_NEW(inode)			(NFS_FLAGS(inode) & NFS_INO_NEW)
 
 #define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
-#define NFS_FSID(inode)			(NFS_I(inode)->fsid)
 
 /* Inode Flags */
 #define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
@@ -250,7 +250,9 @@
 static __inline__ struct rpc_cred *
 nfs_file_cred(struct file *file)
 {
-	struct rpc_cred *cred = (struct rpc_cred *)(file->private_data);
+	struct rpc_cred *cred = NULL;
+	if (file)
+		cred = (struct rpc_cred *)file->private_data;
 #ifdef RPC_DEBUG
 	if (cred && cred->cr_magic != RPCAUTH_CRED_MAGIC)
 		BUG();
diff -Nru a/include/linux/nfs_page.h b/include/linux/nfs_page.h
--- a/include/linux/nfs_page.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/nfs_page.h	Tue Feb  5 19:17:21 2002
@@ -41,9 +41,10 @@
 
 #define NFS_WBACK_BUSY(req)	(test_bit(PG_BUSY,&(req)->wb_flags))
 
-extern	struct nfs_page *nfs_create_request(struct file *, struct inode *,
+extern	struct nfs_page *nfs_create_request(struct rpc_cred *, struct inode *,
 					    struct page *,
 					    unsigned int, unsigned int);
+extern	void nfs_clear_request(struct nfs_page *req);
 extern	void nfs_release_request(struct nfs_page *req);
 
 
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/pci.h	Tue Feb  5 19:17:21 2002
@@ -432,8 +432,7 @@
 	unsigned char	productver;	/* product version */
 	unsigned char	checksum;	/* if zero - checksum passed */
 	unsigned char	pad1;
-
-	struct iobus	iobus;		/* Generic device interface */
+	struct	device	* dev;
 };
 
 #define pci_bus_b(n) list_entry(n, struct pci_bus, node)
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/reiserfs_fs.h	Tue Feb  5 19:17:21 2002
@@ -381,7 +381,7 @@
     offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
     tmp->linear = le64_to_cpu(tmp->linear);
     tmp->offset_v2.k_type = type;
-    tmp->linear = le64_to_cpu(tmp->linear);
+    tmp->linear = cpu_to_le64(tmp->linear);
 }
  
 static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 )
@@ -395,7 +395,7 @@
     offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
     tmp->linear = le64_to_cpu(tmp->linear);
     tmp->offset_v2.k_offset = offset;
-    tmp->linear = le64_to_cpu(tmp->linear);
+    tmp->linear = cpu_to_le64(tmp->linear);
 }
 #else
 # define offset_v2_k_type(v2)           ((v2)->k_type)
diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
--- a/include/linux/reiserfs_fs_sb.h	Tue Feb  5 19:17:21 2002
+++ b/include/linux/reiserfs_fs_sb.h	Tue Feb  5 19:17:21 2002
@@ -131,7 +131,7 @@
   struct buffer_head *bh ;		 /* real buffer head */
   struct super_block *sb ;		 /* dev of real buffer head */
   unsigned long blocknr ;		 /* block number of real buffer head, == 0 when buffer on disk */		 
-  int state ;
+  long state ;
   struct reiserfs_journal_list *jlist ;  /* journal list this cnode lives in */
   struct reiserfs_journal_cnode *next ;  /* next in transaction list */
   struct reiserfs_journal_cnode *prev ;  /* prev in transaction list */
@@ -199,7 +199,7 @@
   struct block_device *j_dev_bd;  
   int j_1st_reserved_block;     /* first block on s_dev of reserved area journal */        
 	
-  int j_state ;			
+  long j_state ;			
   unsigned long j_trans_id ;
   unsigned long j_mount_id ;
   unsigned long j_start ;             /* start of current waiting commit (index into j_ap_blocks) */
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Tue Feb  5 19:17:21 2002
+++ b/init/main.c	Tue Feb  5 19:17:21 2002
@@ -31,8 +31,6 @@
 #include <asm/io.h>
 #include <asm/bugs.h>
 
-#include <linux/device.h>
-
 #if defined(CONFIG_ARCH_S390)
 #include <asm/s390mach.h>
 #include <asm/ccwcache.h>
@@ -446,10 +444,6 @@
 #if defined(CONFIG_ARCH_S390)
 	s390_init_machine_check();
 #endif
-
-	/* bring up the device tree */
-	device_driver_init();
-
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
diff -Nru a/lib/crc32.c b/lib/crc32.c
--- a/lib/crc32.c	Tue Feb  5 19:17:21 2002
+++ b/lib/crc32.c	Tue Feb  5 19:17:21 2002
@@ -564,7 +564,7 @@
 	crc32cleanup_be();
 }
 
-module_init(init_crc32);
+fs_initcall(init_crc32);
 module_exit(cleanup_crc32);
 
 EXPORT_SYMBOL(crc32_le);
diff -Nru a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c
--- a/lib/zlib_inflate/inflate_syms.c	Tue Feb  5 19:17:21 2002
+++ b/lib/zlib_inflate/inflate_syms.c	Tue Feb  5 19:17:21 2002
@@ -18,4 +18,5 @@
 EXPORT_SYMBOL(zlib_inflateSync);
 EXPORT_SYMBOL(zlib_inflateReset);
 EXPORT_SYMBOL(zlib_inflateSyncPoint);
+EXPORT_SYMBOL(zlib_inflateIncomp); 
 MODULE_LICENSE("GPL");
diff -Nru a/scripts/header.tk b/scripts/header.tk
--- a/scripts/header.tk	Tue Feb  5 19:17:21 2002
+++ b/scripts/header.tk	Tue Feb  5 19:17:21 2002
@@ -449,29 +449,24 @@
 	catch {destroy $w}
 	toplevel $w -class Dialog
 
-	set filefound 0
 	set found 0
-	set lineno 0
 
-	if { [file readable Documentation/Configure.help] == 1} then {
-		set filefound 1
-		# First escape sed regexp special characters in var:
-		set var [exec echo "$var" | sed s/\[\]\[\/.^$*\]/\\\\&/g]
-		# Now pick out right help text:
-		set message [exec sed -n "
-			/^$var\[ 	\]*\$/,\${
-				/^$var\[ 	\]*\$/c\\
+	# First escape sed regexp special characters in var:
+	set var [exec echo "$var" | sed s/\[\]\[\/.^$*\]/\\\\&/g]
+	# Now pick out right help text:
+	set message [exec find . -name Config.help | xargs sed -n "
+		/^$var\[ 	\]*\$/,\${
+			/^$var\[ 	\]*\$/c\\
 ${var}:\\
 
-				/^#/b
-				/^\[^ 	\]/q
-				s/^  //
-				/<file:\\(\[^>\]*\\)>/s//\\1/g
-				p
-			}
-			" Documentation/Configure.help]
-		set found [expr [string length "$message"] > 0]
-	}
+			/^#/b
+			/^\[^ 	\]/q
+			s/^  //
+			/<file:\\(\[^>\]*\\)>/s//\\1/g
+			p
+		}
+		" /dev/null ]
+	set found [expr [string length "$message"] > 0]
 
 	frame $w.f1
 	pack $w.f1 -fill both -expand on
@@ -494,13 +489,8 @@
 	pack $w.f1.canvas -side right -fill y -expand on
 
 	if { $found == 0 } then {
-		if { $filefound == 0 } then {
-		message $w.f1.f.m -width 750 -aspect 300 -relief flat -text \
-			"No help available - unable to open file Documentation/Configure.help.  This file should have come with your kernel."
-		} else {
 		message $w.f1.f.m -width 400 -aspect 300 -relief flat -text \
 			"No help available for $var"
-		}
 		label $w.f1.bm -bitmap error
 		wm title $w "RTFM"
 	} else {
