# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	v2.5.3  ->        
#	arch/sparc64/kernel/entry.S	1.8     -> 1.9    
#	arch/alpha/kernel/entry.S	1.7     -> 1.8    
#	   fs/hfs/file_cap.c	1.6     -> 1.7    
#	       fs/nfs/read.c	1.9     -> 1.11   
#	drivers/isdn/isdn_audio.c	1.3     -> 1.4    
#	include/asm-arm/siginfo.h	1.2     -> 1.3    
#	include/asm-m68k/siginfo.h	1.1     -> 1.2    
#	arch/sparc64/kernel/smp.c	1.17    -> 1.18   
#	include/linux/proc_fs.h	1.7     -> 1.9    
#	arch/sparc64/kernel/signal32.c	1.5     -> 1.7    
#	arch/i386/kernel/cpuid.c	1.4     -> 1.5    
#	include/asm-ppc/siginfo.h	1.2     -> 1.3    
#	drivers/isdn/hisax/gazel.c	1.4     -> 1.5    
#	           fs/pipe.c	1.5     -> 1.7    
#	drivers/usb/usbnet.c	1.13    -> 1.14   
#	drivers/usb/mdc800.c	1.9     -> 1.10   
#	drivers/char/joystick/a3d.c	1.3     -> 1.4     drivers/input/joystick/a3d.c (moved)
#	drivers/char/joystick/stinger.c	1.2     -> 1.3     drivers/input/joystick/stinger.c (moved)
#	include/asm-parisc/unistd.h	1.1     -> 1.2    
#	drivers/sbus/char/flash.c	1.7     -> 1.8    
#	         lib/crc32.c	1.2     -> 1.3    
#	lib/zlib_inflate/inflate_syms.c	1.1     -> 1.2    
#	   fs/reiserfs/dir.c	1.10    -> 1.11   
#	drivers/media/video/cpia_usb.c	1.5     -> 1.6    
#	   drivers/char/lp.c	1.15    -> 1.16   
#	      kernel/ksyms.c	1.52    -> 1.54   
#	drivers/usb/serial/kl5kusb105.c	1.1     -> 1.2    
#	drivers/char/joystick/magellan.c	1.3     -> 1.4     drivers/input/joystick/magellan.c (moved)
#	include/asm-cris/siginfo.h	1.1     -> 1.2    
#	arch/m68k/kernel/entry.S	1.2     -> 1.3    
#	arch/sparc64/solaris/ioctl.c	1.1     -> 1.2    
#	arch/sparc64/kernel/signal.c	1.4     -> 1.6    
#	arch/arm/kernel/signal.c	1.5     -> 1.6    
#	drivers/usb/dabusb.c	1.9     -> 1.10   
#	arch/ia64/kernel/sys_ia64.c	1.6     -> 1.7    
#	include/asm-mips/unistd.h	1.2     -> 1.3    
#	 fs/reiserfs/namei.c	1.18    -> 1.19   
#	  drivers/pci/proc.c	1.6     -> 1.9    
#	arch/ia64/kernel/signal.c	1.4     -> 1.5    
#	drivers/usb/drivers.c	1.1     -> 1.2    
#	   drivers/usb/hcd.c	1.7     -> 1.8    
#	     fs/hpfs/super.c	1.8     -> 1.9    
#	drivers/usb/hid-core.c	1.9     -> 1.10   
#	drivers/char/joystick/serio.c	1.2     -> 1.3     drivers/input/serio/serio.c (moved)
#	drivers/usb/serial/belkin_sa.c	1.16    -> 1.17   
#	drivers/usb/CDCEther.c	1.6     -> 1.7    
#	drivers/char/joystick/emu10k1-gp.c	1.2     -> 1.3     drivers/input/gameport/emu10k1-gp.c (moved)
#	    net/ipv6/ndisc.c	1.9     -> 1.10   
#	            fs/bio.c	1.13    -> 1.14   
#	     fs/file_table.c	1.4     -> 1.5    
#	         MAINTAINERS	1.54    -> 1.55   
#	fs/reiserfs/journal.c	1.23    -> 1.24   
#	drivers/ide/ide-proc.c	1.5     -> 1.6    
#	drivers/char/joystick/cs461x.c	1.3     -> 1.4     drivers/input/gameport/cs461x.c (moved)
#	arch/cris/kernel/signal.c	1.5     -> 1.6    
#	drivers/char/joystick/spaceball.c	1.4     -> 1.5     drivers/input/joystick/spaceball.c (moved)
#	     fs/ncpfs/file.c	1.5     -> 1.7    
#	arch/mips/kernel/syscalls.h	1.2     -> 1.3    
#	 drivers/usb/wacom.c	1.7     -> 1.8    
#	arch/sparc64/kernel/sys_sunos32.c	1.11    -> 1.12   
#	arch/ia64/ia32/sys_ia32.c	1.8     -> 1.9    
#	arch/ppc/kernel/ppc_htab.c	1.6     -> 1.7    
#	 drivers/base/core.c	1.8     -> 1.11   
#	drivers/video/neofb.c	1.1     -> 1.2    
#	drivers/char/joystick/Config.help	1.1     -> 1.2     drivers/input/joystick/Config.help (moved)
#	drivers/net/Config.in	1.28    -> 1.29   
#	drivers/usb/serial/io_edgeport.c	1.20    -> 1.21   
#	      fs/proc/base.c	1.12    -> 1.13   
#	drivers/char/joystick/interact.c	1.3     -> 1.4     drivers/input/joystick/interact.c (moved)
#	arch/mips64/kernel/linux32.c	1.5     -> 1.6    
#	arch/s390x/kernel/signal.c	1.5     -> 1.6    
#	     fs/read_write.c	1.4     -> 1.5    
#	 drivers/usb/inode.c	1.9     -> 1.12   
#	drivers/isdn/hisax/st5481_usb.c	1.7     -> 1.8    
#	  net/unix/af_unix.c	1.16    -> 1.17   
#	arch/sparc64/kernel/sys_sparc32.c	1.13    -> 1.14   
#	include/asm-sparc/siginfo.h	1.1     -> 1.2    
#	   drivers/usb/acm.c	1.12    -> 1.13   
#	include/asm-sparc/unistd.h	1.3     -> 1.5    
#	drivers/zorro/proc.c	1.1     -> 1.3    
#	drivers/base/interface.c	1.2     -> 1.3    
#	drivers/usb/hcd/ohci-hcd.c	1.1     -> 1.2    
#	include/asm-i386/unistd.h	1.5     -> 1.6    
#	      fs/namespace.c	1.15    -> 1.16   
#	      fs/udf/super.c	1.11    -> 1.12   
#	include/linux/nfs_page.h	1.2     -> 1.3    
#	include/linux/sched.h	1.35    -> 1.36   
#	       kernel/fork.c	1.29    -> 1.30   
#	drivers/usb/hcd/ohci-mem.c	1.1     -> 1.2    
#	     fs/ext2/super.c	1.12    -> 1.13   
#	drivers/usb/serial/keyspan_pda.c	1.11    -> 1.12   
#	       fs/nfs/file.c	1.11    -> 1.12   
#	drivers/macintosh/nvram.c	1.3     -> 1.4    
#	drivers/char/joystick/amijoy.c	1.3     -> 1.4     drivers/input/joystick/amijoy.c (moved)
#	   fs/hfs/file_hdr.c	1.5     -> 1.6    
#	drivers/char/joystick/iforce.c	1.6     -> 1.8     drivers/input/joystick/iforce.c (moved)
#	     kernel/sysctl.c	1.15    -> 1.16   
#	    fs/autofs/init.c	1.2     -> 1.3    
#	arch/sparc64/solaris/socket.c	1.3     -> 1.4    
#	            Makefile	1.156   -> 1.159  
#	drivers/usb/serial/keyspan.c	1.18    -> 1.19   
#	drivers/net/wireless/airo.c	1.11    -> 1.12   
#	drivers/isdn/hisax/hisax.h	1.13    -> 1.14   
#	drivers/isdn/hisax/st5481.h	1.4     -> 1.5    
#	drivers/usb/serial/mct_u232.c	1.18    -> 1.19   
#	include/asm-ia64/unistd.h	1.3     -> 1.4    
#	drivers/sound/Config.in	1.12    -> 1.13   
#	arch/mips64/kernel/scall_64.S	1.4     -> 1.5    
#	net/packet/af_packet.c	1.8     -> 1.9    
#	 arch/i386/defconfig	1.59    -> 1.60   
#	 fs/driverfs/inode.c	1.6     -> 1.8    
#	drivers/usb/stv680.c	1.4     -> 1.6    
#	fs/autofs4/autofs_i.h	1.2     -> 1.3    
#	         fs/dcache.c	1.17    -> 1.18   
#	drivers/usb/hcd/ohci-hub.c	1.1     -> 1.2    
#	drivers/char/joystick/warrior.c	1.3     -> 1.4     drivers/input/joystick/warrior.c (moved)
#	drivers/mtd/mtdchar.c	1.6     -> 1.7    
#	net/wanrouter/wanmain.c	1.9     -> 1.10   
#	   fs/autofs4/init.c	1.2     -> 1.3    
#	drivers/char/joystick/gf2k.c	1.3     -> 1.4     drivers/input/joystick/gf2k.c (moved)
#	include/asm-s390x/unistd.h	1.4     -> 1.5    
#	drivers/isdn/hisax/elsa.c	1.5     -> 1.6    
#	 fs/reiserfs/stree.c	1.19    -> 1.22   
#	arch/sparc/kernel/signal.c	1.3     -> 1.4    
#	include/asm-sparc64/bitops.h	1.6     -> 1.7    
#	drivers/char/joystick/pcigame.c	1.3     -> 1.4     drivers/input/gameport/pcigame.c (moved)
#	 fs/fat/fatfs_syms.c	1.4     -> 1.6    
#	arch/m68k/kernel/signal.c	1.2     -> 1.3    
#	include/asm-sparc64/unistd.h	1.3     -> 1.4    
#	drivers/char/joystick/Makefile	1.3     -> 1.4     drivers/input/joystick/Makefile (moved)
#	     fs/devfs/base.c	1.24    -> 1.25   
#	         init/main.c	1.31    -> 1.32   
#	drivers/usb/kaweth.c	1.10    -> 1.12   
#	drivers/parport/ChangeLog	1.20    -> 1.23   
#	fs/autofs/autofs_i.h	1.4     -> 1.5    
#	arch/s390/kernel/entry.S	1.11    -> 1.12   
#	drivers/usb/printer.c	1.11    -> 1.13   
#	arch/s390x/kernel/linux32.c	1.8     -> 1.9    
#	           fs/stat.c	1.4     -> 1.5    
#	  include/net/sock.h	1.8     -> 1.9    
#	        fs/ntfs/fs.c	1.14    -> 1.15   
#	include/asm-ppc/unistd.h	1.4     -> 1.5    
#	    fs/hfs/catalog.c	1.3     -> 1.4    
#	  fs/autofs4/inode.c	1.4     -> 1.5    
#	include/asm-sparc64/siginfo.h	1.1     -> 1.2    
#	arch/mips64/kernel/scall_o32.S	1.4     -> 1.5    
#	      fs/nfs/write.c	1.16    -> 1.18   
#	drivers/sound/ite8172.c	1.4     -> 1.5    
#	   fs/autofs/inode.c	1.4     -> 1.5    
#	drivers/sound/nec_vrc5477.c	1.3     -> 1.4    
#	drivers/char/joystick/turbografx.c	1.2     -> 1.3     drivers/input/joystick/turbografx.c (moved)
#	drivers/usb/bluetooth.c	1.16    -> 1.17   
#	drivers/char/Config.in	1.16    -> 1.17   
#	drivers/isdn/hisax/hisax_fcpcipnp.c	1.2     -> 1.3    
#	arch/parisc/hpux/fs.c	1.2     -> 1.4    
#	   fs/devpts/inode.c	1.5     -> 1.6    
#	drivers/usb/usb-ohci.c	1.22    -> 1.23   
#	 drivers/block/nbd.c	1.20    -> 1.23   
#	      fs/proc/root.c	1.4     -> 1.6    
#	drivers/char/joystick/db9.c	1.2     -> 1.3     drivers/input/joystick/db9.c (moved)
#	include/asm-i386/siginfo.h	1.2     -> 1.3    
#	      fs/nfs/inode.c	1.18    -> 1.21   
#	           mm/slab.c	1.12    -> 1.13   
#	drivers/usb/serial/ftdi_sio.c	1.22    -> 1.23   
#	arch/s390/kernel/signal.c	1.6     -> 1.7    
#	arch/s390x/kernel/entry.S	1.10    -> 1.11   
#	  drivers/usb/uhci.c	1.21    -> 1.22   
#	drivers/isdn/avmb1/capifs.c	1.10    -> 1.11   
#	arch/sparc64/solaris/fs.c	1.6     -> 1.7    
#	arch/mips64/kernel/signal.c	1.3     -> 1.4    
#	arch/ia64/kernel/entry.S	1.6     -> 1.7    
#	  include/linux/fs.h	1.69    -> 1.77   
#	    drivers/Makefile	1.8     -> 1.9    
#	drivers/usb/storage/usb.c	1.10    -> 1.11   
#	arch/i386/kernel/entry.S	1.12    -> 1.13   
#	drivers/usb/ibmcam.c	1.7     -> 1.8    
#	drivers/usb/scanner.c	1.12    -> 1.13   
#	include/asm-mips64/unistd.h	1.1     -> 1.2    
#	       fs/ufs/file.c	1.3     -> 1.5    
#	drivers/usb/serial/ipaq.c	1.1     -> 1.2    
#	drivers/hotplug/pci_hotplug_core.c	1.2     -> 1.3    
#	   drivers/pci/pci.c	1.28    -> 1.29   
#	drivers/char/joystick/ns558.c	1.5     -> 1.6     drivers/input/gameport/ns558.c (moved)
#	include/linux/hpfs_fs_sb.h	1.1     -> 1.2    
#	fs/reiserfs/procfs.c	1.3     -> 1.4    
#	drivers/char/vc_screen.c	1.3     -> 1.4    
#	drivers/parport/daisy.c	1.1     -> 1.2    
#	  net/unix/garbage.c	1.4     -> 1.5    
#	drivers/usb/uhci-debug.h	1.4     -> 1.6    
#	      net/atm/proc.c	1.3     -> 1.4    
#	include/asm-mips64/siginfo.h	1.2     -> 1.3    
#	fs/reiserfs/fix_node.c	1.15    -> 1.16   
#	     net/ipv6/icmp.c	1.7     -> 1.8    
#	 drivers/usb/se401.c	1.7     -> 1.8    
#	        mm/bootmem.c	1.7     -> 1.8    
#	drivers/usb/serial/visor.c	1.21    -> 1.22   
#	drivers/usb/hcd/ohci-dbg.c	1.1     -> 1.2    
#	    net/ipv6/mcast.c	1.4     -> 1.5    
#	include/asm-sh/unistd.h	1.1     -> 1.2    
#	 drivers/usb/ov511.c	1.12    -> 1.14   
#	drivers/input/Config.help	1.1     -> 1.2    
#	arch/cris/drivers/usb-host.c	1.9     -> 1.10   
#	arch/sparc/kernel/rtrap.S	1.4     -> 1.5    
#	 fs/reiserfs/inode.c	1.30    -> 1.34   
#	drivers/usb/serial/omninet.c	1.14    -> 1.15   
#	Documentation/filesystems/Locking	1.3     -> 1.4    
#	net/8021q/vlanproc.c	1.4     -> 1.5    
#	include/asm-s390/siginfo.h	1.2     -> 1.3    
#	include/linux/reiserfs_fs.h	1.20    -> 1.21   
#	 drivers/usb/vicam.c	1.4     -> 1.6    
#	    fs/ramfs/inode.c	1.6     -> 1.7    
#	include/asm-sh/siginfo.h	1.1     -> 1.2    
#	arch/sparc64/solaris/socksys.c	1.5     -> 1.6    
#	drivers/usb/serial/whiteheat.c	1.13    -> 1.14   
#	drivers/char/joystick/serport.c	1.4     -> 1.5     drivers/input/serio/serport.c (moved)
#	     fs/proc/inode.c	1.5     -> 1.7    
#	include/linux/stat.h	1.1     -> 1.2    
#	drivers/isdn/isdn_common.c	1.18    -> 1.19   
#	drivers/char/joystick/adi.c	1.4     -> 1.5     drivers/input/joystick/adi.c (moved)
#	drivers/char/joystick/lightning.c	1.3     -> 1.4     drivers/input/gameport/lightning.c (moved)
#	include/asm-s390x/siginfo.h	1.1     -> 1.2    
#	include/linux/device.h	1.4     -> 1.6    
#	drivers/ieee1394/pcilynx.c	1.13    -> 1.14   
#	        net/socket.c	1.12    -> 1.15   
#	drivers/char/joystick/analog.c	1.6     -> 1.7     drivers/input/joystick/analog.c (moved)
#	drivers/char/joystick/grip.c	1.3     -> 1.4     drivers/input/joystick/grip.c (moved)
#	include/linux/nfs_fs.h	1.6     -> 1.9    
#	drivers/usb/serial/cyberjack.c	1.9     -> 1.10   
#	     fs/smbfs/sock.c	1.4     -> 1.5    
#	include/asm-cris/unistd.h	1.5     -> 1.6    
#	    fs/binfmt_misc.c	1.4     -> 1.5    
#	   fs/nfs/pagelist.c	1.2     -> 1.3    
#	arch/ppc/kernel/misc.S	1.9     -> 1.10   
#	include/asm-ia64/siginfo.h	1.2     -> 1.3    
#	arch/cris/drivers/eeprom.c	1.4     -> 1.5    
#	drivers/pnp/isapnp_proc.c	1.3     -> 1.5    
#	drivers/char/joystick/tmdc.c	1.4     -> 1.5     drivers/input/joystick/tmdc.c (moved)
#	  net/ax25/af_ax25.c	1.6     -> 1.7    
#	arch/mips/kernel/sysirix.c	1.5     -> 1.6    
#	     fs/ncpfs/sock.c	1.2     -> 1.3    
#	Documentation/Changes	1.14    -> 1.15   
#	arch/sh/kernel/entry.S	1.7     -> 1.8    
#	drivers/usb/storage/transport.c	1.10    -> 1.11   
#	drivers/usb/usbmouse.c	1.7     -> 1.8    
#	drivers/usb/hcd/ohci-q.c	1.1     -> 1.2    
#	net/netlink/netlink_dev.c	1.5     -> 1.6    
#	drivers/bluetooth/hci_usb.c	1.4     -> 1.5    
#	drivers/input/Makefile	1.1     -> 1.2    
#	drivers/char/nvram.c	1.7     -> 1.8    
#	     kernel/signal.c	1.8     -> 1.9    
#	arch/sparc64/solaris/timod.c	1.8     -> 1.9    
#	drivers/isdn/hisax/st5481_b.c	1.4     -> 1.5    
#	        fs/hfs/mdb.c	1.2     -> 1.4    
#	drivers/usb/auerswald.c	1.3     -> 1.5    
#	 include/linux/net.h	1.2     -> 1.3    
#	drivers/usb/Config.help	1.1     -> 1.2    
#	    net/x25/af_x25.c	1.6     -> 1.7    
#	drivers/char/Makefile	1.13    -> 1.14   
#	include/asm-alpha/siginfo.h	1.1     -> 1.2    
#	arch/sparc/kernel/sys_sunos.c	1.11    -> 1.12   
#	drivers/usb/serial/usbserial.c	1.22    -> 1.23   
#	include/linux/gameport.h	1.3     -> 1.4    
#	drivers/usb/usbkbd.c	1.9     -> 1.10   
#	arch/cris/kernel/entry.S	1.10    -> 1.11   
#	arch/arm/mach-clps711x/dma.c	1.1     -> 1.2    
#	include/asm-alpha/unistd.h	1.3     -> 1.4    
#	include/asm-i386/pci.h	1.10    -> 1.11   
#	          mm/shmem.c	1.30    -> 1.31   
#	arch/i386/kernel/msr.c	1.4     -> 1.5    
#	arch/sparc64/kernel/process.c	1.16    -> 1.17   
#	arch/sparc64/kernel/systbls.S	1.3     -> 1.5    
#	 include/linux/usb.h	1.17    -> 1.18   
#	drivers/parport/parport_pc.c	1.20    -> 1.21   
#	        fs/hfs/hfs.h	1.3     -> 1.5    
#	drivers/char/ppdev.c	1.9     -> 1.11   
#	drivers/usb/devices.c	1.5     -> 1.6    
#	drivers/char/joystick/spaceorb.c	1.3     -> 1.4     drivers/input/joystick/spaceorb.c (moved)
#	drivers/net/wan/comx.c	1.8     -> 1.9    
#	 drivers/usb/audio.c	1.11    -> 1.12   
#	          fs/super.c	1.41    -> 1.45   
#	   drivers/ide/ide.c	1.26    -> 1.27   
#	include/asm-sparc64/mmu_context.h	1.7     -> 1.8    
#	arch/sparc64/kernel/ptrace.c	1.8     -> 1.9    
#	arch/parisc/kernel/signal.c	1.1     -> 1.2    
#	 fs/reiserfs/super.c	1.20    -> 1.22   
#	drivers/usb/usb-uhci.c	1.23    -> 1.24   
#	    fs/hpfs/buffer.c	1.3     -> 1.4    
#	drivers/usb/serial/empeg.c	1.18    -> 1.19   
#	arch/ppc/kernel/signal.c	1.3     -> 1.4    
#	arch/i386/kernel/signal.c	1.8     -> 1.9    
#	  drivers/scsi/esp.c	1.6     -> 1.7    
#	drivers/usb/pegasus.c	1.13    -> 1.15   
#	arch/sparc64/kernel/traps.c	1.7     -> 1.8    
#	drivers/isdn/hisax/st5481_d.c	1.6     -> 1.7    
#	drivers/usb/serial/pl2303.c	1.9     -> 1.10   
#	drivers/sbus/char/jsflash.c	1.8     -> 1.9    
#	arch/s390x/kernel/signal32.c	1.4     -> 1.5    
#	drivers/usb/serial/ir-usb.c	1.8     -> 1.9    
#	fs/openpromfs/inode.c	1.5     -> 1.6    
#	drivers/usb/usb-skeleton.c	1.6     -> 1.7    
#	drivers/usb/serial/digi_acceleport.c	1.14    -> 1.15   
#	arch/sparc64/kernel/rtrap.S	1.6     -> 1.7    
#	  drivers/usb/catc.c	1.7     -> 1.8    
#	   drivers/usb/hub.c	1.13    -> 1.14   
#	drivers/input/Config.in	1.2     -> 1.3    
#	 include/linux/pci.h	1.23    -> 1.24   
#	      fs/ext2/ext2.h	1.4     -> 1.5    
#	net/wanrouter/wanproc.c	1.10    -> 1.11   
#	 drivers/scsi/osst.c	1.10    -> 1.11   
#	arch/alpha/kernel/signal.c	1.3     -> 1.4    
#	include/asm-m68k/unistd.h	1.2     -> 1.3    
#	   fs/proc/generic.c	1.8     -> 1.9    
#	arch/parisc/kernel/syscall.S	1.1     -> 1.2    
#	include/asm-parisc/siginfo.h	1.1     -> 1.2    
#	        fs/nfs/dir.c	1.9     -> 1.10   
#	drivers/isdn/isdn_net.c	1.11    -> 1.12   
#	   fs/nfs/nfs3proc.c	1.2     -> 1.3    
#	drivers/char/joystick/gamecon.c	1.3     -> 1.4     drivers/input/joystick/gamecon.c (moved)
#	drivers/usb/usbvideo.c	1.5     -> 1.6    
#	drivers/char/nwflash.c	1.4     -> 1.5    
#	 drivers/usb/devio.c	1.14    -> 1.16   
#	  net/rose/af_rose.c	1.6     -> 1.7    
#	drivers/usb/storage/scsiglue.c	1.12    -> 1.13   
#	net/netrom/af_netrom.c	1.6     -> 1.7    
#	   drivers/base/fs.c	1.1     -> 1.3    
#	drivers/usb/microtek.c	1.11    -> 1.12   
#	    fs/ncpfs/inode.c	1.8     -> 1.9    
#	arch/i386/boot/bootsect.S	1.5     -> 1.6    
#	arch/sparc/kernel/systbls.S	1.3     -> 1.5    
#	drivers/parport/share.c	1.7     -> 1.8    
#	drivers/char/joystick/cobra.c	1.4     -> 1.5     drivers/input/joystick/cobra.c (moved)
#	arch/arm/kernel/calls.S	1.2     -> 1.3    
#	      fs/block_dev.c	1.33    -> 1.35   
#	drivers/net/irda/irda-usb.c	1.11    -> 1.12   
#	include/asm-s390/unistd.h	1.3     -> 1.4    
#	drivers/char/joystick/gameport.c	1.4     -> 1.5     drivers/input/gameport/gameport.c (moved)
#	   drivers/usb/usb.c	1.26    -> 1.28   
#	fs/reiserfs/tail_conversion.c	1.12    -> 1.13   
#	  drivers/char/mem.c	1.17    -> 1.18   
#	 drivers/scsi/scsi.c	1.23    -> 1.24   
#	arch/mips64/kernel/signal32.c	1.3     -> 1.4    
#	     fs/hfs/extent.c	1.2     -> 1.3    
#	include/linux/reiserfs_fs_sb.h	1.8     -> 1.9    
#	arch/sh/kernel/signal.c	1.5     -> 1.6    
#	   scripts/header.tk	1.2     -> 1.3    
#	drivers/scsi/megaraid.h	1.7     -> 1.8    
#	include/asm-mips/siginfo.h	1.1     -> 1.2    
#	drivers/usb/pwc-if.c	1.11    -> 1.12   
#	arch/mips/kernel/signal.c	1.4     -> 1.5    
#	drivers/char/joystick/Config.in	1.3     -> 1.4     drivers/input/joystick/Config.in (moved)
#	drivers/char/joystick/sidewinder.c	1.4     -> 1.5     drivers/input/joystick/sidewinder.c (moved)
#	     fs/smbfs/file.c	1.9     -> 1.10   
#	drivers/bluetooth/hci_vhci.c	1.3     -> 1.4    
#	Documentation/usb/ibmcam.txt	1.1     -> 1.2    
#	drivers/usb/hpusbscsi.c	1.5     -> 1.6    
#	drivers/usb/hcd/ohci.h	1.1     -> 1.2    
#	               (new)	        -> 1.1     drivers/input/gameport/Config.in
#	               (new)	        -> 1.1     drivers/input/gameport/Makefile
#	               (new)	        -> 1.1     drivers/input/serio/Config.help
#	               (new)	        -> 1.1     drivers/input/serio/Makefile
#	               (new)	        -> 1.1     drivers/input/serio/Config.in
#	               (new)	        -> 1.1     drivers/input/gameport/Config.help
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/02/05	torvalds@athlon.transmeta.com	1.167
# v2.5.2.6 -> v2.5.3
# 
# - Doug Ledford: i810 audio driver update
# - Evgeniy Polyakov: update various SCSI drivers to new locking
# - David Howells: syscall latency improvement, try 2
# - Francois Romieu: dscc4 driver update
# - Patrick Mochel: driver model fixes
# - Andrew Morton: clean up a few details in ext3 inode initialization
# - Pete Wyckoff: make x86 machine check print out right address..
# - Hans Reiser: reiserfs update
# - Richard Gooch: devfs update
# - Greg KH: USB updates
# - Dave Jones: PNPBIOS
# - Nathan Scott: extended attributes
# - Corey Minyard: clean up zlib duplication (triplication..)
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.168
# [PATCH] Dup in drivers/net/Config.in
# 
# Don't offer SunLANCE twice.
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.169
# [PATCH] Fix ESP thinko in 2.5.3-final
# 
# I think I told you to revert this bit from 2.5.3, but here
# it is in patch form anyways.  Whoever made this change didn't
# read the driver, and well... didn't even build test it either :-)
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.170
# [PATCH] Fix IDE printf formatting
# 
# The usual "u64 is long long only on some platforms" problem.
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.171
# [PATCH] OSST kdev_t fixes
# 
# MINOR --> minor
# MKDEV --> mk_kdev
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.172
# [PATCH] Fix typo in i386 PCI header
# 
# I made a typo the other weeks while renaming the interfaces for you,
# oops.  Please apply, thanks.
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.173
# [PATCH] malloc.h references
# 
# linux/malloc.h --> linux/slab.h
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.174
# [PATCH] Fix UFS build
# 
# Missing smp_lock.h inclusion.
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.175
# [PATCH] Missing ZLIB export
# --------------------------------------------
# 02/02/05	davem@redhat.com	1.176
# [PATCH] Sparc updates
# 
# Gets sparc64 in sync with 2.5.3 final changes.
# --------------------------------------------
# 02/02/05	twaugh@redhat.com	1.177
# [PATCH] 2.5.3-pre6: ecr
# 
# This patch (from 2.4.x) cleans up the use of the ECR in parport_pc.
# 
# 	* drivers/parport/parport_pc.c: Integrate fixes and cleanups
# 	from Damian Gruszka (VScom).
# 	* drivers/parport/ChangeLog: Updated.
# --------------------------------------------
# 02/02/05	twaugh@redhat.com	1.178
# [PATCH] 2.5.3-pre6: getmodes
# 
# This patch prevents ppdev from oopsing when the PPGETMODES ioctl is
# used before a PPCLAIM.
# 
# 	* drivers/char/ppdev.c: Fix an oops in PPGETMODES handling.
# --------------------------------------------
# 02/02/05	twaugh@redhat.com	1.179
# [PATCH] 2.5.3-pre6: console
# 
# I finally found the reason that printer console sometimes acted up
# (duh):
# 
# 	* drivers/char/lp.c: Fix printer console.
# --------------------------------------------
# 02/02/05	twaugh@redhat.com	1.180
# [PATCH] 2.5.3-pre6: deadlock
# 
# This patch fixes a potential deadlock in ppdev.
# 
# 	* drivers/char/ppdev.c: Watch out for errors from
# 	parport_claim_or_block.
# 	* drivers/parport/share.c: Watch out for signals.
# 	* drivers/parport/ChangeLog: Updated.
# --------------------------------------------
# 02/02/05	twaugh@redhat.com	1.181
# [PATCH] 2.5.3-pre6: mode
# 
# This patch paves the way for a new driver which needs the
# functionality.  Now parport_daisy_select actually _uses_ its mode
# parameter.
# 
# 	* drivers/parport/daisy.c: Make parport_daisy_select aware of
# 	its 'mode' parameter.
# 	* drivers/parport/ChangeLog: Updated.
# --------------------------------------------
# 02/02/05	vandrove@vc.cvut.cz	1.182
# [PATCH] nbd in 2.5.3 does not work, and can cause severe damage when read-write
# 
# Hi Linus,
#     I've got strange idea and tried to build diskless machine around
# 2.5.3... Besides problem with segfaulting crc32 (it is initialized after
# net/ipv4/ipconfig.c due to lib/lib.a being a library... I had to hardcode
# lib/crc32.o before --start-group in main Makefile, but it is another
# story) there is bad problem with NBD caused by BIO changes:
# 
# (1) request flags were immediately put into on-wire request format.
#     In the past, we had 0=READ, !0=WRITE. Now only REQ_RW bit determines
#     direction. As nbd-server from nbd distribution package treats any
#     non-zero value as write, it performs writes instead of read. Fortunately
#     it will die due to other consistency checks on incoming request, but...
# 
# (2) nbd servers handle only up to 10240 byte requests. So setting max_sectors
#     to 20 is needed, as otherwise nbd server commits suicide. Maximum request size
#     should be handshaked during nbd initialization, but currently just use
#     hardwired 20 sectors, so it will behave like it did in the past.
# --------------------------------------------
# 02/02/05	knan@mo.himolde.no	1.183
# [PATCH] typo in drivers/scsi/megaraid.h
# 
# A trivial patch that fixes this irritation in my dmesg, 2.5.3:
# 
# megaraid: v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001
# )<5>megaraid: found 0x8086:0x1960:idx 0:bus 2:slot 5:func 1
# scsi0 : Found a MegaRAID controller at 0xe089c000, IRQ: 12
# 
# Please apply.
# --------------------------------------------
# 02/02/05	mec@shout.net	1.184
# [PATCH] fix xconfig for new help system
# 
# Here is a patch to enhance xconfig to read the new Config.help files.
# Olaf Dietsche wrote this, and Steven Cole passed it on to me.
# 
# Testing: Steven Cole tested it, and I tested it.
# --------------------------------------------
# 02/02/05	mochel@osdl.org	1.185
# [PATCH] driver model updates (1/5)
# 
# Patch 1: Make device_driver_init() an initcall.
# It declares it as subsys_initcall and removes the explicit call from
# init/main.c::do_basic_setup().
# --------------------------------------------
# 02/02/05	mochel@osdl.org	1.186
# [PATCH] driver model updates (3/5)
# 
# Patch 3: Make default callbacks simpler.
# 
# I want to move as much to a 1 file/1 value model as possible. I haven't
# come up with a clean way to enforce it except via social pressure.
# 
# This patch is a step in that direction. It:
# 
# - Reduces the output of 'power' to just the decimal state of the device
# - Adds a 'name' file which exports just the device name
# - Reduces the 'status' file to just export the bus ID. (This will change,
#   since the bus ID is obvious based on what directory you're in, but it's
#   another patch at another time)
# --------------------------------------------
# 02/02/05	mochel@osdl.org	1.187
# [PATCH] driver model updates (4/5)
# 
# Patch 4: Add some default files for PCI devices.
# 
# This adds two files for PCI devices: 'irq' and 'resources'. They display
# just those things and currently do nothing on write. These are the
# examples for other subsystems to use for creating files ('Hey, look how
# simple it is!')
# --------------------------------------------
# 02/02/05	mochel@osdl.org	1.188
# [PATCH] driver model updates (5/5)
# 
# Remove struct iobus.
# 
# There is a lot of duplication between struct device and struct iobus, both
# in their members and the code in their interfaces. Waxing struct iobus
# removes this duplication and makes things a bit simpler.
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.189
# [PATCH] reiserfs patchset, patch 1 of 9 01-pick_correct_key_version.diff
# 
# 01-pick_correct_key_version.diff
#     This is to fix certain cases where items may get its keys to be interpreted
#     wrong, or to be inserted into the tree in wrong order. This bug was only
#     observed live on 2.5.3, though it is present in 2.4, too.
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.190
# [PATCH] reiserfs patchset, patch 2 of 9 02-prealloc_list_init.diff
# 
# 02-prealloc_list_init.diff
#     prealloc list was forgotten to be initialised.
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.191
# [PATCH] reiserfs patchset, patch 3 of 9 03-key_output_fix.diff
# 
# 03-key_output_fix.diff
#     Fix all the places where cpu key is attempted to be printed as ondisk key
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.192
# [PATCH] reiserfs patchset, patch 4 of 9 04-nfs_stale_inode_access.diff
# 
# 04-nfs_stale_inode_access.diff
#     This is to fix a case where stale NFS handles are correctly detected as
#     stale, but inodes assotiated with them are still valid and present in cache,
#     hence there is no way to deal with files, these handles are attached to.
#     Bug was found and explained by
#     Anne Milicia <milicia@missioncriticallinux.com>
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.193
# [PATCH] reiserfs patchset, patch 5 of 9 05-kernel-reiserfs_fs_h-offset_v2.diff
# 
# 05-kernel-reiserfs_fs_h-offset_v2.diff
#     Convert erroneous le64_to_cpu to cpu_to_le64
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.194
# [PATCH] reiserfs patchset, patch 6 of 9 06-return_braindamage_removal.diff
# 
# 06-return_braindamage_removal.diff
#     Kill stupid code like 'goto label ; return 1;'
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.195
# [PATCH] reiserfs patchset, patch 7 of 9 07-remove_nospace_warnings.diff
# 
# 07-remove_nospace_warnings.diff
#     Do not print scary warnings in out of free space situations.
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.196
# [PATCH] reiserfs patchset, patch 8 of 9 08-unfinished_rebuildtree_message.diff
# 
# 
# 08-unfinished_rebuildtree_message.diff
#     Give a proper explanation if unfinished reiserfsck --rebuild-tree
#     run on a fs was detected.
# --------------------------------------------
# 02/02/05	reiser@namesys.com	1.197
# [PATCH] reiserfs patchset, patch 9 of 9 09-64bit_bitops_fix-1.diff
# 
# 09-64bit_bitops_fix-1.diff
#     Bitopts arguments must be long, not int.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.198
# [PATCH] USB Kawasaki driver maintainer change
# 
# Here's a patch against 2.5.3 that changes the maintainer of the USB
# Kawasaki driver to Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.199
# [PATCH] USB Config.help update
# 
# Here's a patch against 2.5.3 that updates the Config.help entries for
# the USB microtek and hpusbscsi drivers.
# This patch was done by Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.200
# [PATCH] USB Kaweth driver update
# 
# Here's a patch against 2.5.3 for the USB kaweth driver that does the
# following:
# 	- removes SMP deadlock
# 	- removes nfs deadlock
# 	- fixes a memory leak when the firmware is not loaded.
# 	- few other minor cleanups.
# This patch was done by Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.201
# [PATCH] USB pegasus driver update
# 
# Here's a patch against 2.5.3 for the USB pegasus driver that does the
# following:
# 	- fixes __FUNCTION__ warnings on gcc-3.0.3 and up
# 	- added 3 more devices
# 	- fixed memory leak
# This patch was done by Petko Manolov and Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.202
# [PATCH] USB printer driver update
# 
# Here's a patch against 2.5.3 for the USB printer driver that does the
# following:
# 	- removes the races inherent in sleep_on
# 	- uses 2.5 style of module usage counting
# 	- kills a lockup on failure of usb_submit_urb
# This patch was done by Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.203
# [PATCH] USB stv680 driver update
# 
# Here's a patch against 2.5.3 for the USB stv680 driver that fixes two
# bugs in the existing driver.  This patch was done by Kevin Sisson.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.204
# [PATCH] USB core update
# 
# Here's a patch against 2.5.3 for the USB core that fixes a possible
# initialization bug for some platforms when allocating a new usb, and
# changes the warning level on a message (it isn't an error.)  This patch
# was done by Oliver Neukum and David Brownell.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.205
# [PATCH] USB vicam driver update
# 
# Here's a patch against 2.5.3 for the USB vicam driver that removes the
# use of interruptible_sleep_on() in the driver.  This patch was done by
# Oliver Neukum.
# --------------------------------------------
# 02/02/05	greg@kroah.com	1.206
# [PATCH] USB ohci-hcd driver update
# 
# Here's a patch against 2.5.3 for the USB ohci-hcd driver that does the
# following:
# 	- doesn't assume CONFIG_DEBUG_SLAB
# 	- unlink from interrupt completions now work
# 	- doesn't force debugging on
# 	- updated copyright / license statements
# 	- slightly smaller object size
# 	- fewer inlined magic numbers
# 	- removes unused fields from data structures
# 	- header file reorg, doc fixup
# This patch was done by David Brownell.
# --------------------------------------------
# 02/02/05	trond.myklebust@fys.uio.no	1.207
# [PATCH] NFS lookup code rewrite w/o open(".") fix...
# 
#   This is a resend of the NFS lookup code rewrite, but with the open(".")
# VFS fix removed. (I'll resend the 'uses d_revalidate()' version
# separately after a suitable delay to allow for comments.)
# 
#   Issues fixed by this patch:
# 
#  - Use the directory mtime in order to give us a hint when we should
#    check for namespace changes.
# 
#  - Add support for the 'nocto' flag, in order to turn off the strict
#    attribute cache revalidation on file open().
# 
#  - Simplify inode lookup. Don't check the 'fsid' field (which appears
#    to be buggy in too many servers in order to be reliable). Instead
#    we only rely on the inode number (a.k.a. 'fileid') and the
#    (supposedly unique) filehandle.
# --------------------------------------------
# 02/02/05	trond.myklebust@fys.uio.no	1.208
# [PATCH] Fix spurious ETXTBSY errors due to late release of struct file
# 
#   The following patch should fix a problem of ETXTBSY sometimes
# occurring if one tries to run a file straight after compilation.
# 
# The problem is that both NFS read and write requests can currently
# hold a count on the struct file. This is done partly so as to be able
# to pass along the RPC credential (which is cached in the struct file),
# and partly so that asynchronous writes can report any errors via the
# file->f_error mechanism.
# 
# The problem is that both the read and write requests may persist even
# after file close() occurs. For O_RDONLY files, this is not a problem,
# but for O_WRONLY, and O_RDWR files, the fact that the struct file is
# not released until the last call to nfs_release_request() means that
# inode->i_writecount does not necessarily get cleared upon file
# close().
# 
# The following patch fixes both these issues.
# 
#   - NFS read requests no longer hold the struct file. They take a
#     count on the the RPC credential itself.
# 
#   - NFS write requests still hold the struct file, since they want to
#     report errors to sys_close() using the file->f_error mechanism.
#     However they are made to release the page, credential, and file
#     structures as soon as the write is completed instead of following
#     the current practice of waiting for the last nfs_page request
#     release.
# --------------------------------------------
# 02/02/05	trond.myklebust@fys.uio.no	1.209
# [PATCH] Drop reliance on file->f_dentry in NFS reads/writes
# 
# Following a request by David Chow on linux fsdevel, this patch causes
# NFS read and write requests to take the inode from page->mapping->host
# rather than relying on file->f_dentry->d_inode. Apparently this will
# simplify some work he is doing on another filesystem.
# 
# In any case, it cleans up the current mix of sometimes doing one
# thing, sometimes the other (historical cruft), and puts NFS client
# behaviour on par with what is done in other filesystems...
# --------------------------------------------
# 02/02/05	vandrove@vc.cvut.cz	1.210
# [PATCH] Re: [PATCH] nbd in 2.5.3 does not work, and can cause severe damage when read-write
# 
# Linus, this reverts limit for request size from 10KB to unlimited.
# Although no released nbd version supports it, it is certainly better to
# add support to servers than cripple clients if incompatibility does
# not matter.
# --------------------------------------------
# 02/02/05	vandrove@vc.cvut.cz	1.211
# [PATCH] crc32 and lib.a (was Re: [PATCH] nbd in 2.5.3 does
# 
#   I've found that multiple level initcalls went into kernel
# behind my back, so you can throw away my yesterday patch
# which converted lib.a => lib.o, and apply this one.
# 
# [Patch tested with both lib.a and lib.o - it boots correctly
# in both cases]
# --------------------------------------------
# 02/02/05	nkbj@image.dk	1.212
# [PATCH] Two fixes for linux-2.5.3.
# 
#  Correct typo in Documentation/Changes.
#  Remove duplicate code in arch/i386/boot/bootsect.S.
# --------------------------------------------
# 02/02/05	kai@tp1.ruhr-uni-bochum.de	1.213
# [PATCH] 2.5.3 ISDN devfs fix
# 
# the appended patch by Adrian Bunk removes yet another leftover from
# the /dev/isdnX devices (which causes an build error when
# CONFIG_DEVFS_FS=y).
# --------------------------------------------
# 02/02/05	kai@tp1.ruhr-uni-bochum.de	1.214
# [PATCH] 2.5.3 ISDN charge hup fix
# 
# the appended patch by Igmar Palsenberg fixes the CHARGE_HUP functionality
# (automatically hang up just before the next charging unit)
# --------------------------------------------
# 02/02/05	kai@tp1.ruhr-uni-bochum.de	1.215
# [PATCH] 2.5.3 ISDN undefined behavior fix
# 
# the appended patch fixes a case of undefined behavior, found by
# Urs Thuermann and "VDA".
# --------------------------------------------
# 02/02/05	kai@tp1.ruhr-uni-bochum.de	1.216
# [PATCH] 2.5.3 ISDN hisax_fcpcipnp driver fix
# 
# the appended patch fixes a problem where the ->rcvidx variable was not
# initialized properly.
# --------------------------------------------
# 02/02/05	kai@tp1.ruhr-uni-bochum.de	1.217
# [PATCH] 2.5.3 ISDN work around buggy hw
# 
# the appended patch works around a bug in the PLX9050 chip. This chip is
# used in various PCI ISDN adapters (it's an PCI interface chip) and has
# an erratum when the BAR 0/1 has bit 7 set (the size of the region is
# 0x80, so aligning it to 0x80 is legal and really happens for people).
# 
# This workaround has been tested by a user who hit this problem with a
# Gazel card. Basically the same fix has been done for Elsa cards, but it's
# untested.
# --------------------------------------------
# 02/02/05	vojtech@suse.cz	1.218
# 
# The patch moves:
# 
# 	* joystick drivers from drivers/char/joystick to drivers/input/joystick
# 	* gameport drivers from drivers/char/joystick to drivers/input/gameport
# 	* serio drivers from drivers/char/joystick to drivers/input/serio
# 
# I don't think the joystick drivers should stay in char, because they're
# NOT character device drivers (check for register_chrdev, none to be found).
# 
# It also fixes build problems with sound driver gameport support.
# --------------------------------------------
# 02/02/05	torvalds@penguin.transmeta.com	1.219
# Makefile:
#   Update version
# --------------------------------------------
# 02/02/05	torvalds@penguin.transmeta.com	1.220
# defconfig:
#   update
# --------------------------------------------
# 02/02/06	dmccr@us.ibm.com	1.221
# [PATCH] Third version of signal changes for thread groups
# 
# During the course of developing our pthread library (the NGPT pthread
# library) it became clear we needed some kernel support for handling
# signals.  This patch helps the library by redirecting all signals sent
# to tasks in a thread group to the thread group leader.  It also defines
# the tkill() system call so the library can signal a specific task if
# necessary. 
# 
# Given that as far as I know NGPT is the only user of thread groups, and
# that this change would benefit any other user of thread groups, I'm
# submitting this for inclusion in the 2.5 kernel.
# 
# Note that this patch also adds support for sys_gettid() for the
# architectures that don't have it.  While this could have been split into a
# spearate patch, it would create conflicts since this patch also adds
# sys_tkill(), so I felt it was cleaner to leave them together.
# 
# Dave McCracken
# 
# ======================================================================
# Dave McCracken          IBM Linux Base Kernel Team      1-512-838-3059
# dmccr@us.ibm.com                                        T/L   678-3059
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.222
# [PATCH] (1/2) inode trimming
# 
# 	more inode->u trimming - socket_i is killed.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.223
# [PATCH] (2/2) inode trimming
# 
# 	procfs switched to alloc_inode/destroy_inode.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.224
# [PATCH] (1/5) beginning of getattr series.
# 
# 	added new helpers - vfs_stat(), vfs_lstat() and vfs_fstat().
# 	fs/stat.c switched to use them.
# 
# Following patches will
# 
# 	stat(2) variants in arch/* that used to copy inode fields manually
# 	switched to vfs_*stat() and partially cleaned up
# 
# 	irix_...() switched from sys_new*stat() to vfs_*stat() and cleaned
# 	up.  Missing LFS check added.
# 
# 	similar for solaris ones
# 
# 	ditto for x86 compatibility ones on ia64.
# 
# We are almost ready to switch to ->getattr() - let filesystem decide what
# values should go into ->st_... (e.g. for CODA life would become much
# easier if it could just use ->i_size of caching file, for supermount
# we want ->i_ino inherited from underlying fs, etc.)
# 
# Another thing that needs to be done is fixing the rest of LFS/uid size
# fsckups in architecture-specific variants of stat() - I've fixed several,
# but quite a few are still there.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.225
# [PATCH] (2/5) beginning of getattr series.
# 
# stat(2) variants in arch/* that used to copy inode fields manually
# switched to vfs_*stat() and partially cleaned up
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.226
# [PATCH] (3/5) beginning of getattr series.
# 
# irix_...() switched from sys_new*stat() to vfs_*stat() and cleaned up. 
# Missing LFS check added
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.227
# [PATCH] (4/5) beginning of getattr series.
# 
# solaris: switched from sys_new*stat() to vfs_*stat() and cleaned up. 
# Missing LFS check added. 
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.228
# [PATCH] (5/5) beginning of getattr series.
# 
# ia64: switched from sys_new*stat() to vfs_*stat() and cleaned up. 
# --------------------------------------------
# 02/02/06	rml@tech9.net	1.229
# [PATCH] 2.5.4-pre1: further llseek cleanup (1/3)
# 
# This is the first of three patches implementing further llseek cleanup,
# against 2.5.4-pre1.
# 
# The 'push locking into llseek methods' patch was integrated into 2.5.3.
# The networking filesystems, however, do not protect i_size and can not
# rely on the inode semaphore used in generic_file_llseek.
# 
# This patch implements a remote_llseek method, which is basically the
# pre-2.5.3 version of generic_file_llseek.  Locking is done via the BKL.
# When we have a saner locking system in place, we can push it into this
# function in lieu.
# 
# Ncpfs, nfs, and smbfs have been converted to use this new llseek.
# 
# Note this is updated over the previous posted patch.
# 
# 	Robert Love
# --------------------------------------------
# 02/02/06	rml@tech9.net	1.230
# [PATCH] 2.5.4-pre1: further llseek cleanup (2/3)
# 
# This is the second patch of three implementing further llseek cleanups,
# against 2.5.4-pre1.  It does not depend on the other patches.
# 
# This patch cleans up various code and quite nicely removes much more
# code than it adds.  Specifically:
# 
# - remove static lseek method which merely reimplements
#   the standard no_llseek in the following seven files:
#   hci_vhci.c, ite8172.c, nec_vrc5477.c, auerswald.c,
#   pipe.c, netlink_dev.c, and socket.c
# 
# - remove fs/ufs/file.c::ufs_file_lseek -- Al says it is
#   reimplementing generic_file_llseek, so let's use that
#   instead (the comment about 32-bit sizes shouldn't be
#   an issue, the generic method checks size)
# 
# - include smp_lock.h in 3 files missed from previous
#   'remove bkl' patch
# 
# - Documentation/filesystem/Locking update
# 
# Please, apply.
# 
# 	Robert Love
# --------------------------------------------
# 02/02/06	rml@tech9.net	1.231
# [PATCH] 2.5.4-pre1: further llseek cleanup (3/3)
# 
# The previous patch did not provide protection for device lseek methods
# (drivers/* stuff).  This patch pushes the BKL into each of the remaining
# lseek methods -- without them we have a race.
# 
# I'd much prefer to have a a better lock to push down than the BKL, but
# that will have to wait.
# 
# Before you balk at the size, remember patch #2 in this series which
# removed much code ;-)
# 
# Thanks to Al for assistance, especially a listing of affected files.
# 
# 	Robert Love
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.232
# [PATCH] hpfs cleanup (switch from sleep_on() to semaphore)
# 
# 	Pair (flag, wait_queue) in hpfs replaced with semaphore.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.233
# [PATCH] death of hfs rename_lock
# 
# 	Useless (lock,waitqueue) pair killed - we have fs-wide
# exclusion between renames enforced by VFS, so hfs rename_{lock,wait}
# can be removed.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.234
# [PATCH] more sleep_on() removals
# 
# 	Yet another flag/wait_queue pair bites the dust - hfs bitmap_{lock,wait}
# was trying to implement a semaphore.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.235
# [PATCH] missing ->i_zombie in hpux_getdents()
# 
# 	hpux_getdents() contains a years-old copy of code from fs/readdir.c.
# Switched to use of vfs_readdir(), which does correct locking.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.236
# [PATCH] fix for exit_fat_fs()
# 
# 	Kudos to OGAWA Hirofumi for finding that one - gcc barfs on the
# current code, trying to define an alias to external symbol.
# --------------------------------------------
# 02/02/06	reiser@namesys.com	1.237
# [PATCH] reiserfs fix for inodes with wrong item versions (2.5)
# 
#    This is hopefully last bugfix for a bug introduced by struct inode splitting.
#    Because of setting i_flags to some value and then cleaning the i_flags
#    contents later, on-disk items received wrong item version ob v3.6 filesystems
# --------------------------------------------
# 02/02/06	torvalds@penguin.transmeta.com	1.238
# fatfs_syms.c:
#   Al Viro: fix a typo (destory->destroy)
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.1.1
# patch from Wolfgang Mües <wmues@nexgo.de> for the usb auerswald.c driver:
#   	- Code-Review from Oliver Neukum: remove SMP races.
#   	- Added some wake_up calls after auerbuf_releasebuf to wake up tasks waiting
#   	  for cp buffers.
#   	- Change the module count handling to automatic (owner: THIS_MODULE).
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.2.1
# patch from dimitry for the usb ibmcam driver that does:
#   	- Updates the documentation
#   	- Adds Veo Stingray support
#   	- Fixes hotplug table dependency upon now-defunct symbol
#   	- deletes drivers/usb/ibmcam.h
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.1
# usb core:
# 	- initial add of the "int mem_flags" call to the usb_submit_urb() call
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.2
# usb host controllers:
# 	- add mem_flags support
# 	- portions of this patch by Oliver Neukum and David Brownell.
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.3
# "mem_flags" support for the cris usb host controller.
# These changes have been approved by the CRIS maintainer.
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.4
# usb_submit_urb() changes for the drivers/usb/*.c drivers.
# Some driver changes were done by Oliver Neukum and David Brownell.
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.5
# usb_submit_urb() changes for all drivers/usb/serial/*.c drivers
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.6
# usb_submit_urb() changes.
# Patch done by Oliver Neukum.
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.3.7
# usb_submit_urb() changes for USB drivers that live outside of the drivers/usb subdirectory.
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.1.2
# Merge soap.kroah.net:/home/greg/linux/bk_main/gregkh-2.5
# into soap.kroah.net:/home/greg/linux/bk_main/usb-2
# --------------------------------------------
# 02/02/06	greg@soap.kroah.net	1.220.1.3
# Merge soap.kroah.net:/home/greg/linux/bk_main/gregkh-2.5
# into soap.kroah.net:/home/greg/linux/bk_main/usb-3
# --------------------------------------------
# 02/02/06	torvalds@athlon.transmeta.com	1.239
# Merge bk://linuxusb.bkbits.net/linus-2.5
# into athlon.transmeta.com:/home/torvalds/v2.5/linux
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.240
# [PATCH] (1/8) ->get_sb() switchover
# 
# 	OK, here comes the long-promised switchover to ->get_sb().
# 
# New method added - ->get_sb(type, flags, dev, data).  At this point we
# still keep ->read_super(), but it will go away in the end of series. 
# ->get_sb() is a generalization of get_sb_{bdev,nodev,single}() - as the
# matter of fact, these will become common helpers used by filesystems in
# their ->get_sb(). 
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.241
# [PATCH] (2/8) ->get_sb() switchover
# 
# get_sb_bdev() et.al. get a new argument (fill_super) and become
# exported.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.242
# [PATCH] (3/8) ->get_sb() switchover
# 
# ext2 switched to ->get_sb().  For that we had
#         a) turned ext2_read_super() into ext2_fill_super() (instead of
# "return NULL if failed and sb if succeeded" it's "return error value or
# 0").
#         b) added ext2_get_sb(type, flags, dev, data) - all it does is
# return get_sb_bdev(type, flags, dev, data, ext2_fill_super);
#         c) replaced DECLARE_...() with explicit initializer.
# That's it.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.243
# [PATCH] (4/8) ->get_sb() switchover
# 
# convert procfs to ->get_sb().  Similar to ext2, except that we use
# get_sb_single() instead of get_sb_bdev().  Notice the we _don't_ keep
# FS_SINGLE in flags - as the matter of fact, with ->get_sb() FS_SINGLE is
# useless. 
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.244
# [PATCH] (5/8) ->get_sb() switchover
# 
# converte binfmt_misc to ->get_sb()
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.245
# [PATCH] (6/8) ->get_sb() switchover
# 
# converte usb to ->get_sb()
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.246
# [PATCH] (7/8) ->get_sb() switchover
# 
# converted ramfs/rootfs to ->get_sb().  Use get_sb_nodev() as helper. 
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.247
# [PATCH] (8/8) ->get_sb() switchover
# 
# converted fs/block_dev.c ("bdev") to ->get_sb.  use get_sb_nodev() as
# helper. 
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.248
# [PATCH] (1/6) more ->get_sb() stuff
# 
# Fix for idiotic typo in __get_sb_single().
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.249
# [PATCH] (2/6) more ->get_sb() stuff
# 
# devpts converted.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.250
# [PATCH] (3/6) more ->get_sb() stuff
# 
# pcihpfs converted.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.251
# [PATCH] (4/6) more ->get_sb() stuff
# 
# driverfs converted.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.252
# [PATCH] (5/6) more ->get_sb() stuff
# 
# devfs converted.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.253
# [PATCH] (6/6) more ->get_sb() stuff
# 
# Now that all FS_SINGLE filesystems are using ->get_sb(), FS_SINGLE
# can die.
# --------------------------------------------
# 02/02/06	ak@muc.de	1.239.1.1
# [PATCH] Slab name cleanup - last try
# 
# Hallo Linus,
# 
# This is the slab name cleanup you originally requested when the reiserfs
# slab name too long boot bug was introduced. It replaces the static
# name limit for slab cache names with the requirement for the caller
# to supply a stable name. This version addresses all concerns that were given
# over earlier versions of the patch.
# 
# As I do not feel very strongly about the slab cache name limit and you
# also do not seem to be interested in it and the original bug of reiserfs
# not booting anymore has been long fixed in your tree with the patch
# you originally rejected from me I will not resend this patch after this
# try.
# 
# Patch against 2.5.4pre1.
# 
# -Andi
# --------------------------------------------
# 02/02/06	ak@muc.de	1.239.1.2
# [PATCH] Bootmem speedup
# 
# This patch speeds the bootmem freeing up a bit. Not particularly important,
# but helps on some slow simulators where the loop can chew up significant
# CPU time.
# --------------------------------------------
# 02/02/06	ak@muc.de	1.239.1.3
# [PATCH] Automatic file-max sizing
# 
# The default for NR_FILES of 8192 is far too low for many workloads. This
# patch does dynamic sizing for it instead. It assumes file+inode+dentry
# are roughly 1K and will use upto 10% of the memory for it.
# 
# Also removes two obsolete prototypes.
# --------------------------------------------
# 02/02/06	ak@muc.de	1.239.1.4
# [PATCH] Fix page cache limit wrapping in filesystems
# 
# Several file systems in tree that nominally support files >2GB set their
# s_maxbytes value to ~0ULL. This has the nasty side effect on 32bit machines
# that when a file write reaches the page cache limit (e.g. 2^43) it'll silently
# wrap and destroy data at the beginning of the file.
# 
# This patch changes the file systems in question to fill in a proper limit.
# 
# I also have an alternate patch that adds a check for this generically
# in super.c, but preliminary comments from Al suggested that he prefered
# to do it in the file systems, so it is done this way way.
# --------------------------------------------
# 02/02/06	ak@muc.de	1.239.1.5
# [PATCH] Fix mount hash table
# 
# On my 512MB machine with 6 mount points the mount hash table uses 64K.
# This patch brings it to a more reasonable size by limiting it to one
# page.
# --------------------------------------------
# 02/02/06	torvalds@athlon.transmeta.com	1.254
# Merge penguin:v2.5/linux
# into athlon.transmeta.com:/home/torvalds/v2.5/linux
# --------------------------------------------
# 02/02/06	torvalds@athlon.transmeta.com	1.255
# update version number
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.256
# [PATCH] (1/9) more ->get_sb() stuff
# 
# 	More ->get_sb() patches.
# 
# shmem/tmpfs switched
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.257
# [PATCH] (2/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: fix for usbdevfs - forgot to remove
# DECLARE_FSTYPE() after adding explicit initializer.
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.258
# [PATCH] (3/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: pipefs
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.259
# [PATCH] (4/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: sockfs
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.260
# [PATCH] (5/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: openpromfs
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.261
# [PATCH] (6/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: capifs
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.262
# [PATCH] (7/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: autofs
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.263
# [PATCH] (8/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: autofs4
# --------------------------------------------
# 02/02/06	viro@math.psu.edu	1.264
# [PATCH] (9/9) more ->get_sb() stuff
# 
# More ->get_sb() patches: nfs.  It still acts as nodev - what we want to
# (and can) do now is to give it enough smarts to recognize that same tree
# might be already mounted.
# 
# We are almost done with nodev filesystems by now.
# --------------------------------------------
#
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Wed Feb  6 22:48:39 2002
+++ b/Documentation/Changes	Wed Feb  6 22:48:39 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/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Wed Feb  6 22:48:39 2002
+++ b/Documentation/filesystems/Locking	Wed Feb  6 22:48:39 2002
@@ -237,7 +237,10 @@
 
 ->llseek() locking has moved from llseek to the individual llseek
 implementations.  If your fs is not using generic_file_llseek, you
-need to acquire and release the BKL in your ->llseek().
+need to acquire and release the appropriate locks in your ->llseek().
+For many filesystems, it is probably safe to acquire the inode
+semaphore.  Note some filesystems (i.e. remote ones) provide no
+protection for i_size so you will need to use the BKL.
 
 ->open() locking is in-transit: big lock partially moved into the methods.
 The only exception is ->open() in the instances of file_operations that never
diff -Nru a/Documentation/usb/ibmcam.txt b/Documentation/usb/ibmcam.txt
--- a/Documentation/usb/ibmcam.txt	Wed Feb  6 22:48:39 2002
+++ b/Documentation/usb/ibmcam.txt	Wed Feb  6 22:48:39 2002
@@ -25,12 +25,19 @@
 
 SUPPORTED CAMERAS:
 
-IBM "C-It" camera, also known as "Xirlink PC Camera"
+Xirlink "C-It" camera, also known as "IBM PC Camera".
 The device uses proprietary ASIC (and compression method);
 it is manufactured by Xirlink. See http://www.xirlink.com/
 http://www.ibmpccamera.com or http://www.c-itnow.com/ for
 details and pictures.
 
+This very chipset ("X Chip", as marked at the factory)
+is used in several other cameras, and they are supported
+as well:
+
+- IBM NetCamera
+- Veo Stingray
+
 The Linux driver was developed with camera with following
 model number (or FCC ID): KSX-XVP510. This camera has three
 interfaces, each with one endpoint (control, iso, iso). This
@@ -50,12 +57,30 @@
 Such type of cameras is referred to as "model 2". They are supported
 (with exception of 352x288 native mode).
 
+Some IBM NetCameras (Model 4) are made to generate only compressed
+video streams. This is great for performance, but unfortunately
+nobody knows how to decompress the stream :-( Therefore, these
+cameras are *unsupported* and if you try to use one of those, all
+you get is random colored horizontal streaks, not the image!
+If you have one of those cameras, you probably should return it
+to the store and get something that is supported.
+
+Tell me more about all that "model" business
+--------------------------------------------
+
+I just invented model numbers to uniquely identify flavors of the
+hardware/firmware that were sold. It was very confusing to use
+brand names or some other internal numbering schemes. So I found
+by experimentation that all Xirlink chipsets fall into four big
+classes, and I called them "models". Each model is programmed in
+its own way, and each model sends back the video in its own way.
+
 Quirks of Model 2 cameras:
 -------------------------
 
 Model 2 does not have hardware contrast control. Corresponding V4L
-control is not used at the moment. It may be possible to implement
-contrast control in software, at cost of extra processor cycles.
+control is implemented in software, which is not very nice to your
+CPU, but at least it works.
 
 This driver provides 352x288 mode by switching the camera into
 quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting
@@ -67,17 +92,24 @@
 the frame rate at slowest setting, but I had to move it pretty much down
 the scale (so that framerate option barely matters). I also noticed that
 camera after first powering up produces frames slightly faster than during
-consecutive uses. All this means that if you use videosize=2 (which is
+consecutive uses. All this means that if you use 352x288 (which is
 default), be warned - you may encounter broken picture on first connect;
 try to adjust brightness - brighter image is slower, so USB will be able
 to send all data. However if you regularly use Model 2 cameras you may
-prefer videosize=1 which makes perfectly good I420, with no scaling and
+prefer 176x144 which makes perfectly good I420, with no scaling and
 lesser demands on USB (300 Kbits per second, or 26 frames per second).
 
+Another strange effect of 352x288 mode is the fine vertical grid visible
+on some colored surfaces. I am sure it is caused by me not understanding
+what the camera is trying to say. Blame trade secrets for that.
+
 The camera that I had also has a hardware quirk: if disconnected,
 it needs few minutes to "relax" before it can be plugged in again
 (poorly designed USB processor reset circuit?)
 
+[Veo Stingray with Product ID 0x800C is also Model 2, but I haven't
+observed this particular flaw in it.]
+
 Model 2 camera can be programmed for very high sensitivity (even starlight
 may be enough), this makes it convenient for tinkering with. The driver
 code has enough comments to help a programmer to tweak the camera
@@ -98,12 +130,14 @@
 precompile all modules, so you can go directly to the next
 section "HOW TO USE THE DRIVER".
 
-The driver consists of two files in usb/ directory:
-ibmcam.c and ibmcam.h These files are included into the
-Linux kernel build process if you configure the kernel
-for CONFIG_USB_IBMCAM. Run "make xconfig" and in USB section
-you will find the IBM camera driver. Select it, save the
-configuration and recompile.
+The ibmcam driver uses usbvideo helper library (module),
+so if you are studying the ibmcam code you will be led there.
+
+The driver itself consists of only one file in usb/ directory:
+ibmcam.c. This file is included into the Linux kernel build
+process if you configure the kernel for CONFIG_USB_IBMCAM.
+Run "make xconfig" and in USB section you will find the IBM
+camera driver. Select it, save the configuration and recompile.
 
 HOW TO USE THE DRIVER:
 
@@ -112,6 +146,13 @@
 settings than V4L can operate, so some settings are done using
 module options.
 
+To begin with, on most modern Linux distributions the driver
+will be automatically loaded whenever you plug the supported
+camera in. Therefore, you don't need to do anything. However
+if you want to experiment with some module parameters then
+you can load and unload the driver manually, with camera
+plugged in or unplugged.
+
 Typically module is installed with command 'modprobe', like this:
 
 # modprobe ibmcam framerate=1
@@ -138,7 +179,7 @@
 init_hue        Integer         0-255 [128]     init_hue=115
 lighting        Integer         0-2* [1]        lighting=2
 sharpness       Integer         0-6* [4]        sharpness=3
-videosize       Integer         0-2* [2]        videosize=1
+size            Integer         0-2* [2]        size=1
 
 Options for Model 2 only:
 
@@ -181,6 +222,11 @@
                                            this is a little faster but may
                                            produce flicker if frame rate is
                                            too high and Isoc data gets lost.
+                FLAGS_NO_DECODING      128 This flag turns the video stream
+                                           decoder off, and dumps the raw
+                                           Isoc data from the camera into
+                                           the reading process. Useful to
+                                           developers, but not to users.
 
 framerate       This setting controls frame rate of the camera. This is
                 an approximate setting (in terms of "worst" ... "best")
@@ -227,35 +273,38 @@
                 be greeted with "snowy" image. Default is 4. Model 2
                 cameras do not support this feature.
 
-videosize       This setting chooses one if three image sizes that are
-                supported by this driver. Camera supports more, but
+size            This setting chooses one of several image sizes that are
+                supported by this driver. Cameras may support more, but
                 it's difficult to reverse-engineer all formats.
                 Following video sizes are supported:
 
-                videosize=0     128x96  (Model 1 only)
-                videosize=1     176x144
-                videosize=2     352x288
-                videosize=3     320x240 (Model 2 only)
-                videosize=4     352x240 (Model 2 only)
+                size=0     128x96  (Model 1 only)
+                size=1     160x120
+                size=2     176x144
+                size=3     320x240 (Model 2 only)
+                size=4     352x240 (Model 2 only)
+                size=5     352x288
+                size=6     640x480 (Model 3 only)
 
-                The last one (352x288) is the native size of the sensor
-                array, so it's the best resolution camera (Model 1) can
+                The 352x288 is the native size of the Model 1 sensor
+                array, so it's the best resolution the camera can
                 yield. The best resolution of Model 2 is 176x144, and
                 larger images are produced by stretching the bitmap.
+                Model 3 has sensor with 640x480 grid, and it works too,
+                but the frame rate will be exceptionally low (1-2 FPS);
+                it may be still OK for some applications, like security.
                 Choose the image size you need. The smaller image can
                 support faster frame rate. Default is 352x288.
 
+For more information and the Troubleshooting FAQ visit this URL:
+
+                http://www.linux-usb.org/ibmcam/
+
 WHAT NEEDS TO BE DONE:
 
-- The box freezes if camera is unplugged after being used (OHCI).
-  Workaround: remove usb-ohci module first.
-- On occasion camera (model 1) does not start properly (xawtv reports
-  errors), or camera produces negative image (funny colors.)
-  Workaround: reload the driver module. Reason: [1].
 - The button on the camera is not used. I don't know how to get to it.
   I know now how to read button on Model 2, but what to do with it?
 
-[1]
 - Camera reports its status back to the driver; however I don't know
   what returned data means. If camera fails at some initialization
   stage then something should be done, and I don't do that because
@@ -263,26 +312,13 @@
   concern because Model 2 uses different commands which do not return
   status (and seem to complete successfully every time).
 
-VIDEO SIZE AND IMAGE SIZE
-
-Camera produces picture X by Y pixels. This is camera-specific and can be
-altered by programming the camera accordingly. This image is placed onto
-larger (or equal) area W by H, this is V4L image. At this time the driver
-uses V4L image size (W by H) 352x288 pixels because many programs (such
-as xawtv) expect quite specific sizes and don't want to deal with arbitrary,
-camera-specific sizes. However this approach "hides" real image size, and
-application always sees the camera as producing only 352x288 image. It is
-possible to change the V4L image size to 128x96, and then if camera is
-switched to 128x96 mode then xawtv will correctly accept this image size. But
-many other popular sizes (such as 176x144) will not be welcomed. This is the
-reason why all camera images are at this time placed onto 352x288 "canvas",
-and size of that canvas (V4L) is reported to applications. It will be easy
-to add options to control the canvas size, but it will be application-
-specific because not all applications are ready to work with variety of
-camera-specific sizes.
+- Some flavors of Model 4 NetCameras produce only compressed video
+  streams, and I don't know how to decode them.
 
 CREDITS:
 
 The code is based in no small part on the CPiA driver by Johannes Erdfelt,
 Randy Dunlap, and others. Big thanks to them for their pioneering work on that
 and the USB stack.
+
+I also thank John Lightsey for his donation of the Veo Stingray camera.
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Wed Feb  6 22:48:38 2002
+++ b/MAINTAINERS	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 2002
+++ b/Makefile	Wed Feb  6 22:48:38 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 3
-EXTRAVERSION =
+SUBLEVEL = 4
+EXTRAVERSION =-pre2
 
 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/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S	Wed Feb  6 22:48:38 2002
+++ b/arch/alpha/kernel/entry.S	Wed Feb  6 22:48:38 2002
@@ -1148,3 +1148,4 @@
 	.quad sys_gettid
 	.quad sys_readahead
 	.quad sys_ni_syscall			/* 380, sys_security */
+	.quad sys_tkill
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/alpha/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -717,9 +717,7 @@
 
 			default:
 				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 			continue;
diff -Nru a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
--- a/arch/arm/kernel/calls.S	Wed Feb  6 22:48:39 2002
+++ b/arch/arm/kernel/calls.S	Wed Feb  6 22:48:39 2002
@@ -236,6 +236,8 @@
 		.long	SYMBOL_NAME(sys_mincore)
 /* 220 */	.long	SYMBOL_NAME(sys_madvise)
 		.long	SYMBOL_NAME(sys_fcntl64)
+		.long	SYMBOL_NAME(sys_gettid)
+		.long	SYMBOL_NAME(sys_tkill)
 __syscall_end:
 
 		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c	Wed Feb  6 22:48:38 2002
+++ b/arch/arm/kernel/signal.c	Wed Feb  6 22:48:38 2002
@@ -637,10 +637,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/arm/mach-clps711x/dma.c b/arch/arm/mach-clps711x/dma.c
--- a/arch/arm/mach-clps711x/dma.c	Wed Feb  6 22:48:39 2002
+++ b/arch/arm/mach-clps711x/dma.c	Wed Feb  6 22:48:39 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/cris/drivers/eeprom.c b/arch/cris/drivers/eeprom.c
--- a/arch/cris/drivers/eeprom.c	Wed Feb  6 22:48:39 2002
+++ b/arch/cris/drivers/eeprom.c	Wed Feb  6 22:48:39 2002
@@ -74,6 +74,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include "i2c.h"
 
@@ -448,36 +449,39 @@
  *  orig 1: relative from current position
  *  orig 2: position from last eeprom address
  */
-  
+  loff_t ret;
+
+  lock_kernel();
   switch (orig)
   {
    case 0:
-     file->f_pos = offset;
+     ret = file->f_pos = offset;
      break;
    case 1:
-     file->f_pos += offset;
+     ret = file->f_pos += offset;
      break;
    case 2:
-     file->f_pos = eeprom.size - offset;
+     ret = file->f_pos = eeprom.size - offset;
      break;
    default:
-     return -EINVAL;
+     ret = -EINVAL;
   }
 
   /* truncate position */
   if (file->f_pos < 0)
   {
     file->f_pos = 0;    
-    return(-EOVERFLOW);
+    unlock_kernel();
+    ret = -EOVERFLOW;
   }
   
   if (file->f_pos >= eeprom.size)
   {
     file->f_pos = eeprom.size - 1;
-    return(-EOVERFLOW);
+    ret = -EOVERFLOW;
   }
 
-  return ( file->f_pos );
+  return ( ret );
 }
 
 /* Reads data from eeprom. */
diff -Nru a/arch/cris/drivers/usb-host.c b/arch/cris/drivers/usb-host.c
--- a/arch/cris/drivers/usb-host.c	Wed Feb  6 22:48:39 2002
+++ b/arch/cris/drivers/usb-host.c	Wed Feb  6 22:48:39 2002
@@ -210,12 +210,12 @@
 static void etrax_usb_free_epid(char epid);
 static void cleanup_sb(USB_SB_Desc_t *sb);
 
-static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen);
-static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen);
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags);
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags);
 
-static int etrax_usb_submit_ctrl_urb(struct urb *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags);
 
-static int etrax_usb_submit_urb(struct urb *urb);
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
 static int etrax_usb_unlink_urb(struct urb *urb);
 static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
 static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
@@ -512,7 +512,7 @@
 	} while (tmp_ep != first_ep);
 }
 
-static int etrax_usb_submit_intr_urb(struct urb *urb)
+static int etrax_usb_submit_intr_urb(struct urb *urb, mem_flags)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -556,7 +556,7 @@
 	}
 	/* Ok, now we got valid endpoint, lets insert some traffic */
 
-	urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
+	urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), mem_flags);
 	urb_priv->first_sb = 0;
 	urb_priv->rx_offset = 0;
 	urb_priv->eot = 0;
@@ -591,9 +591,9 @@
 				USB_SB_Desc_t *traffic_sb;
 
 				traffic_ep = (USB_EP_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+					kmem_cache_alloc(usb_desc_cache, mem_flags);
 				traffic_sb = (USB_SB_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+					kmem_cache_alloc(usb_desc_cache, mem_flags);
 
 				traffic_ep->hw_len = 0;
 				traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) |
@@ -904,7 +904,7 @@
 	return -1;
 }
 
-static int etrax_usb_submit_bulk_urb(struct urb *urb)
+static int etrax_usb_submit_bulk_urb(struct urb *urb, int mem_flags)
 {
 	char epid;
 	char devnum;
@@ -954,7 +954,7 @@
 		/* If this is the first URB, add the URB and do HW add */
 		URB_List[epid] = urb;
 		restore_flags(flags);
-		etrax_usb_do_bulk_hw_add(urb, epid, maxlen);
+		etrax_usb_do_bulk_hw_add(urb, epid, maxlen, mem_flags);
 	}
 
 	DBFEXIT;
@@ -962,7 +962,7 @@
 	return 0;
 }
 
-static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen)
+static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags)
 {
 	USB_SB_Desc_t *sb_desc_1;
 
@@ -973,8 +973,8 @@
 
 	DBFENTER;
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
-	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags);
+	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags);
 
 	if (usb_pipeout(urb->pipe)) {
 
@@ -1135,7 +1135,8 @@
 	if (URB_List[epid]) {
 		etrax_usb_do_bulk_hw_add(URB_List[epid], epid,
 					 usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe,
-						       usb_pipeout(URB_List[epid]->pipe)));
+						       usb_pipeout(URB_List[epid]->pipe)),
+					 GFP_KERNEL);
 	}
 #if 1
 	else {
@@ -1159,7 +1160,7 @@
 
 /* ---------------------------------------------------------------------------- */
 
-static int etrax_usb_submit_ctrl_urb(struct urb *urb)
+static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags)
 {
 	char epid;
 	char devnum;
@@ -1209,7 +1210,7 @@
 		/* If this is the first URB, add the URB and do HW add */
 		URB_List[epid] = urb;
 		restore_flags(flags);
-		etrax_usb_do_ctrl_hw_add(urb, epid, maxlen);
+		etrax_usb_do_ctrl_hw_add(urb, epid, maxlen, mem_flags);
 	}
 
 	DBFEXIT;
@@ -1217,7 +1218,7 @@
 	return 0;
 }
 
-static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen)
+static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags)
 {
 	USB_SB_Desc_t *sb_desc_1;
 	USB_SB_Desc_t *sb_desc_2;
@@ -1231,9 +1232,9 @@
 
 	DBFENTER;
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL);
-	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
-	sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags);
+	sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags);
+	sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags);
 
 	if (!(sb_desc_1 && sb_desc_2)) {
 		panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n");
@@ -1257,7 +1258,7 @@
 		
 		if (urb->transfer_buffer) {
 			dbg_ctrl("This OUT transfer has an extra data stage");
-			sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+			sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags);
 
 			sb_desc_1->next = virt_to_phys(sb_desc_3);
 			
@@ -1285,7 +1286,7 @@
 		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
 		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
 
-		sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL);
+		sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags);
 		
 		sb_desc_2->sw_len = urb->transfer_buffer_length ?
 			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
@@ -1358,7 +1359,7 @@
 	DBFEXIT;
 }
 
-static int etrax_usb_submit_urb(struct urb *urb)
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
 {
 	etrax_hc_t *hc;
 	int rval = -EINVAL;
@@ -1375,10 +1376,10 @@
 		rval = etrax_rh_submit_urb(urb);
 		
 	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		rval = etrax_usb_submit_ctrl_urb(urb);
+		rval = etrax_usb_submit_ctrl_urb(urb, mem_flags);
 
 	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-		rval = etrax_usb_submit_bulk_urb(urb);
+		rval = etrax_usb_submit_bulk_urb(urb, mem_flags);
 
 	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
 		int bustime;
@@ -1389,7 +1390,7 @@
 				rval = bustime;
 			} else {
 				usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-				rval = etrax_usb_submit_intr_urb(urb);
+				rval = etrax_usb_submit_intr_urb(urb, mem_flags);
 			}
 			
 		}
@@ -1683,7 +1684,8 @@
 	if (URB_List[epid]) {
 		etrax_usb_do_ctrl_hw_add(URB_List[epid], epid,
 					 usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe,
-						       usb_pipeout(URB_List[epid]->pipe)));
+						       usb_pipeout(URB_List[epid]->pipe)),
+					 GFP_KERNEL);
 	}
 #if 1
 	else {
diff -Nru a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
--- a/arch/cris/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/cris/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -1015,6 +1015,7 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
+        .long SYMBOL_NAME(sys_tkill)
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -Nru a/arch/cris/kernel/signal.c b/arch/cris/kernel/signal.c
--- a/arch/cris/kernel/signal.c	Wed Feb  6 22:48:38 2002
+++ b/arch/cris/kernel/signal.c	Wed Feb  6 22:48:38 2002
@@ -679,10 +679,7 @@
 
 			default:
 				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
--- a/arch/i386/boot/bootsect.S	Wed Feb  6 22:48:39 2002
+++ b/arch/i386/boot/bootsect.S	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/arch/i386/defconfig	Wed Feb  6 22:48:38 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/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
--- a/arch/i386/kernel/cpuid.c	Wed Feb  6 22:48:38 2002
+++ b/arch/i386/kernel/cpuid.c	Wed Feb  6 22:48:38 2002
@@ -35,6 +35,7 @@
 #include <linux/poll.h>
 #include <linux/smp.h>
 #include <linux/major.h>
+#include <linux/smp_lock.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
@@ -82,16 +83,24 @@
 
 static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
 {
+  loff_t ret;
+
+  lock_kernel();
+
   switch (orig) {
   case 0:
     file->f_pos = offset;
-    return file->f_pos;
+    ret = file->f_pos;
+    break;
   case 1:
     file->f_pos += offset;
-    return file->f_pos;
+    ret = file->f_pos;
   default:
-    return -EINVAL;	/* SEEK_END not supported */
+    ret = -EINVAL;
   }
+
+  unlock_kernel();
+  return ret;
 }
 
 static ssize_t cpuid_read(struct file * file, char * buf,
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/i386/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -667,6 +667,7 @@
 	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
 	.long SYMBOL_NAME(sys_lremovexattr)
 	.long SYMBOL_NAME(sys_fremovexattr)
+ 	.long SYMBOL_NAME(sys_tkill)
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Nru a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c	Wed Feb  6 22:48:39 2002
+++ b/arch/i386/kernel/msr.c	Wed Feb  6 22:48:39 2002
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/major.h>
 
 #include <asm/processor.h>
@@ -162,16 +163,19 @@
 
 static loff_t msr_seek(struct file *file, loff_t offset, int orig)
 {
+  loff_t ret = -EINVAL;
+  lock_kernel();
   switch (orig) {
   case 0:
     file->f_pos = offset;
-    return file->f_pos;
+    ret = file->f_pos;
+    break;
   case 1:
     file->f_pos += offset;
-    return file->f_pos;
-  default:
-    return -EINVAL;	/* SEEK_END not supported */
+    ret = file->f_pos;
   }
+  unlock_kernel();
+  return ret;
 }
 
 static ssize_t msr_read(struct file * file, char * buf,
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/i386/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -683,10 +683,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Wed Feb  6 22:48:38 2002
+++ b/arch/ia64/ia32/sys_ia32.c	Wed Feb  6 22:48:38 2002
@@ -171,77 +171,65 @@
 }
 
 static inline int
-putstat (struct stat32 *ubuf, struct stat *kbuf)
+putstat (struct stat32 *ubuf, struct kstat *stat)
 {
 	int err;
 
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+
 	if (clear_user(ubuf, sizeof(*ubuf)))
-		return 1;
+		return -EFAULT;
 
-	err  = __put_user(kbuf->st_dev, &ubuf->st_dev);
-	err |= __put_user(kbuf->st_ino, &ubuf->st_ino);
-	err |= __put_user(kbuf->st_mode, &ubuf->st_mode);
-	err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink);
-	err |= __put_user(kbuf->st_uid, &ubuf->st_uid);
-	err |= __put_user(kbuf->st_gid, &ubuf->st_gid);
-	err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev);
-	err |= __put_user(kbuf->st_size, &ubuf->st_size);
-	err |= __put_user(kbuf->st_atime, &ubuf->st_atime);
-	err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime);
-	err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime);
-	err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize);
-	err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks);
+	err  = __put_user(stat->dev, &ubuf->st_dev);
+	err |= __put_user(stat->ino, &ubuf->st_ino);
+	err |= __put_user(stat->mode, &ubuf->st_mode);
+	err |= __put_user(stat->nlink, &ubuf->st_nlink);
+	err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
+	err |= __put_user(high2lowgid(stat->gid), &ubuf->st_gid);
+	err |= __put_user(stat->rdev, &ubuf->st_rdev);
+	err |= __put_user(stat->size, &ubuf->st_size);
+	err |= __put_user(stat->atime, &ubuf->st_atime);
+	err |= __put_user(stat->mtime, &ubuf->st_mtime);
+	err |= __put_user(stat->ctime, &ubuf->st_ctime);
+	err |= __put_user(stat->blksize, &ubuf->st_blksize);
+	err |= __put_user(stat->blocks, &ubuf->st_blocks);
 	return err;
 }
 
-extern asmlinkage long sys_newstat (char * filename, struct stat * statbuf);
-
 asmlinkage long
 sys32_newstat (char *filename, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
-	mm_segment_t old_fs = get_fs();
+	struct kstat stat;
+	int ret = vfs_stat(filename, &stat);
+
+	if (!ret)
+		ret = putstat(statbuf, &stat);
 
-	set_fs(KERNEL_DS);
-	ret = sys_newstat(filename, &s);
-	set_fs(old_fs);
-	if (putstat(statbuf, &s))
-		return -EFAULT;
 	return ret;
 }
 
-extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
-
 asmlinkage long
 sys32_newlstat (char *filename, struct stat32 *statbuf)
 {
-	mm_segment_t old_fs = get_fs();
-	struct stat s;
-	int ret;
+	struct kstat stat;
+	int ret = vfs_lstat(filename, &stat);
+
+	if (!ret)
+		ret = putstat(statbuf, &stat);
 
-	set_fs(KERNEL_DS);
-	ret = sys_newlstat(filename, &s);
-	set_fs(old_fs);
-	if (putstat(statbuf, &s))
-		return -EFAULT;
 	return ret;
 }
 
-extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
-
 asmlinkage long
 sys32_newfstat (unsigned int fd, struct stat32 *statbuf)
 {
-	mm_segment_t old_fs = get_fs();
-	struct stat s;
-	int ret;
+	struct kstat stat;
+	int ret = vfs_fstat(fd, &stat);
+
+	if (!ret)
+		ret = putstat(statbuf, &stat);
 
-	set_fs(KERNEL_DS);
-	ret = sys_newfstat(fd, &s);
-	set_fs(old_fs);
-	if (putstat(statbuf, &s))
-		return -EFAULT;
 	return ret;
 }
 
@@ -3529,74 +3517,59 @@
 }
 
 static int
-putstat64 (struct stat64 *ubuf, struct stat *kbuf)
+putstat64 (struct stat64 *ubuf, struct kstat *kbuf)
 {
 	int err;
 
 	if (clear_user(ubuf, sizeof(*ubuf)))
-		return 1;
+		return -EFAULT;
 
-	err  = __put_user(kbuf->st_dev, &ubuf->st_dev);
-	err |= __put_user(kbuf->st_ino, &ubuf->__st_ino);
-	err |= __put_user(kbuf->st_ino, &ubuf->st_ino_lo);
-	err |= __put_user(kbuf->st_ino >> 32, &ubuf->st_ino_hi);
-	err |= __put_user(kbuf->st_mode, &ubuf->st_mode);
-	err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink);
-	err |= __put_user(kbuf->st_uid, &ubuf->st_uid);
-	err |= __put_user(kbuf->st_gid, &ubuf->st_gid);
-	err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev);
-	err |= __put_user(kbuf->st_size, &ubuf->st_size_lo);
-	err |= __put_user((kbuf->st_size >> 32), &ubuf->st_size_hi);
-	err |= __put_user(kbuf->st_atime, &ubuf->st_atime);
-	err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime);
-	err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime);
-	err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize);
-	err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks);
+	err  = __put_user(kbuf->dev, &ubuf->st_dev);
+	err |= __put_user(kbuf->ino, &ubuf->__st_ino);
+	err |= __put_user(kbuf->ino, &ubuf->st_ino_lo);
+	err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi);
+	err |= __put_user(kbuf->mode, &ubuf->st_mode);
+	err |= __put_user(kbuf->nlink, &ubuf->st_nlink);
+	err |= __put_user(kbuf->uid, &ubuf->st_uid);
+	err |= __put_user(kbuf->gid, &ubuf->st_gid);
+	err |= __put_user(kbuf->rdev, &ubuf->st_rdev);
+	err |= __put_user(kbuf->size, &ubuf->st_size_lo);
+	err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi);
+	err |= __put_user(kbuf->atime, &ubuf->st_atime);
+	err |= __put_user(kbuf->mtime, &ubuf->st_mtime);
+	err |= __put_user(kbuf->ctime, &ubuf->st_ctime);
+	err |= __put_user(kbuf->blksize, &ubuf->st_blksize);
+	err |= __put_user(kbuf->blocks, &ubuf->st_blocks);
 	return err;
 }
 
 asmlinkage long
 sys32_stat64 (char *filename, struct stat64 *statbuf)
 {
-	mm_segment_t old_fs = get_fs();
-	struct stat s;
-	long ret;
-
-	set_fs(KERNEL_DS);
-	ret = sys_newstat(filename, &s);
-	set_fs(old_fs);
-	if (putstat64(statbuf, &s))
-		return -EFAULT;
+	struct kstat s;
+	long ret = vfs_stat(filename, &s);
+	if (!ret)
+		ret = putstat64(statbuf, &s);
 	return ret;
 }
 
 asmlinkage long
 sys32_lstat64 (char *filename, struct stat64 *statbuf)
 {
-	mm_segment_t old_fs = get_fs();
-	struct stat s;
-	long ret;
-
-	set_fs(KERNEL_DS);
-	ret = sys_newlstat(filename, &s);
-	set_fs(old_fs);
-	if (putstat64(statbuf, &s))
-		return -EFAULT;
+	struct kstat s;
+	long ret = vfs_lstat(filename, &s);
+	if (!ret)
+		ret = putstat64(statbuf, &s);
 	return ret;
 }
 
 asmlinkage long
 sys32_fstat64 (unsigned int fd, struct stat64 *statbuf)
 {
-	mm_segment_t old_fs = get_fs();
-	struct stat s;
-	long ret;
-
-	set_fs(KERNEL_DS);
-	ret = sys_newfstat(fd, &s);
-	set_fs(old_fs);
-	if (putstat64(statbuf, &s))
-		return -EFAULT;
+	struct kstat s;
+	long ret = vfs_fstat(fd, &s);
+	if (!ret)
+		ret = putstat64(statbuf, &s);
 	return ret;
 }
 
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/ia64/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -1130,6 +1130,7 @@
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
 	data8 sys_readahead
+	data8 sys_tkill
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c	Wed Feb  6 22:48:38 2002
+++ b/arch/ia64/kernel/signal.c	Wed Feb  6 22:48:38 2002
@@ -578,10 +578,7 @@
 				/* FALLTHRU */
 
 			      default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
--- a/arch/ia64/kernel/sys_ia64.c	Wed Feb  6 22:48:38 2002
+++ b/arch/ia64/kernel/sys_ia64.c	Wed Feb  6 22:48:38 2002
@@ -282,120 +282,64 @@
  * call - it will be removed later once everybody migrates to the new
  * kernel stat structure that matches the glibc one - Jes
  */
-static __inline__ int
-do_revalidate (struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-	return 0;
-}
 
 static int
-cp_ia64_old_stat (struct inode *inode, struct ia64_oldstat *statbuf)
+cp_ia64_old_stat (struct kstat *stat, struct ia64_oldstat *statbuf)
 {
 	struct ia64_oldstat tmp;
 	unsigned int blocks, indirect;
 
 	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	SET_STAT_UID(tmp, inode->i_uid);
-	SET_STAT_GID(tmp, inode->i_gid);
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-/*
- * st_blocks and st_blksize are approximated with a simple algorithm if
- * they aren't supported directly by the filesystem. The minix and msdos
- * filesystems don't keep track of blocks, so they would either have to
- * be counted explicitly (by delving into the file itself), or by using
- * this simple algorithm to get a reasonable (although not 100% accurate)
- * value.
- */
-
-/*
- * Use minix fs values for the number of direct and indirect blocks.  The
- * count is now exact for the minix fs except that it counts zero blocks.
- * Everything is in units of BLOCK_SIZE until the assignment to
- * tmp.st_blksize.
- */
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-
-	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (blocks > D_B) {
-			indirect = (blocks - D_B + I_B - 1) / I_B;
-			blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				blocks += indirect;
-				if (indirect > 1)
-					blocks++;
-			}
-		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
-	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
-	}
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_STAT_UID(tmp, stat->uid);
+	SET_STAT_GID(tmp, stat->gid);
+	tmp.st_rdev = stat->rdev;
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	tmp.st_blocks = stat->i_blocks;
+	tmp.st_blksize = stat->i_blksize;
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
 asmlinkage long
 ia64_oldstat (char *filename, struct ia64_oldstat *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_ia64_old_stat(&stat, statbuf);
 
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-		error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
 
-
 asmlinkage long
-ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf) {
-	struct nameidata nd;
-	int error;
-
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
+ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf)
+{
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+
+	if (!error)
+		error = cp_ia64_old_stat(&stat, statbuf);
+
 	return error;
 }
 
 asmlinkage long
 ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_ia64_old_stat(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	if (!error)
+		error = cp_ia64_old_stat(&stat, statbuf);
+
+	return error;
 }
 
 #endif
diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
--- a/arch/m68k/kernel/entry.S	Wed Feb  6 22:48:38 2002
+++ b/arch/m68k/kernel/entry.S	Wed Feb  6 22:48:38 2002
@@ -646,6 +646,8 @@
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
+	.long SYMBOL_NAME(sys_gettid)
+	.long SYMBOL_NAME(sys_tkill)
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Nru a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
--- a/arch/m68k/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/m68k/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -1135,10 +1135,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
--- a/arch/mips/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/mips/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -661,10 +661,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
--- a/arch/mips/kernel/syscalls.h	Wed Feb  6 22:48:38 2002
+++ b/arch/mips/kernel/syscalls.h	Wed Feb  6 22:48:38 2002
@@ -235,3 +235,5 @@
 SYS(sys_madvise, 3)
 SYS(sys_getdents64, 3)
 SYS(sys_fcntl64, 3)				/* 4220 */
+SYS(sys_gettid, 0)
+SYS(sys_tkill, 2)
diff -Nru a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
--- a/arch/mips/kernel/sysirix.c	Wed Feb  6 22:48:39 2002
+++ b/arch/mips/kernel/sysirix.c	Wed Feb  6 22:48:39 2002
@@ -1178,7 +1178,7 @@
 	return MAJOR (t) << 18 | MINOR (t);
 }
 
-static inline int irix_xstat32_xlate(struct stat *kb, void *ubuf)
+static inline int irix_xstat32_xlate(struct kstat *stat, void *ubuf)
 {
 	struct xstat32 {
 		u32 st_dev, st_pad1[3], st_ino, st_mode, st_nlink, st_uid, st_gid;
@@ -1191,28 +1191,32 @@
 		u32 st_pad4[8];
 	} ub;
 
-	ub.st_dev     = linux_to_irix_dev_t (kb->st_dev);
-	ub.st_ino     = kb->st_ino;
-	ub.st_mode    = kb->st_mode;
-	ub.st_nlink   = kb->st_nlink;
-	ub.st_uid     = kb->st_uid;
-	ub.st_gid     = kb->st_gid;
-	ub.st_rdev    = linux_to_irix_dev_t (kb->st_rdev);
-	ub.st_size    = kb->st_size;
-	ub.st_atime0  = kb->st_atime;
+	ub.st_dev     = linux_to_irix_dev_t(stat->dev);
+	ub.st_ino     = stat->ino;
+	ub.st_mode    = stat->mode;
+	ub.st_nlink   = stat->nlink;
+	SET_STAT_UID(ub, stat->uid);
+	SET_STAT_GID(ub, stat->gid);
+	ub.st_rdev    = linux_to_irix_dev_t(stat->rdev);
+#if BITS_PER_LONG == 32
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+#endif	
+	ub.st_size    = stat->size;
+	ub.st_atime0  = stat->atime;
 	ub.st_atime1  = 0;
-	ub.st_mtime0  = kb->st_mtime;
+	ub.st_mtime0  = stat->mtime;
 	ub.st_mtime1  = 0;
-	ub.st_ctime0  = kb->st_ctime;
+	ub.st_ctime0  = stat->ctime;
 	ub.st_ctime1  = 0;
-	ub.st_blksize = kb->st_blksize;
-	ub.st_blocks  = kb->st_blocks;
+	ub.st_blksize = stat->blksize;
+	ub.st_blocks  = stat->blocks;
 	strcpy (ub.st_fstype, "efs");
 
 	return copy_to_user(ubuf, &ub, sizeof(ub)) ? -EFAULT : 0;
 }
 
-static inline void irix_xstat64_xlate(struct stat *sb)
+static inline void irix_xstat64_xlate(struct kstat *stat, void *ubuf)
 {
 	struct xstat64 {
 		u32 st_dev; s32 st_pad1[3];
@@ -1229,177 +1233,112 @@
 		s32 st_pad4[8];
 	} ks;
 
-	ks.st_dev = linux_to_irix_dev_t (sb->st_dev);
+	ks.st_dev = linux_to_irix_dev_t(stat->dev);
 	ks.st_pad1[0] = ks.st_pad1[1] = ks.st_pad1[2] = 0;
-	ks.st_ino = (unsigned long long) sb->st_ino;
-	ks.st_mode = (u32) sb->st_mode;
-	ks.st_nlink = (u32) sb->st_nlink;
-	ks.st_uid = (s32) sb->st_uid;
-	ks.st_gid = (s32) sb->st_gid;
-	ks.st_rdev = linux_to_irix_dev_t (sb->st_rdev);
+	ks.st_ino = (unsigned long long) stat->ino;
+	ks.st_mode = (u32) stat->mode;
+	ks.st_nlink = (u32) stat->nlink;
+	ks.st_uid = (s32) stat->uid;
+	ks.st_gid = (s32) stat->gid;
+	ks.st_rdev = linux_to_irix_dev_t (stat->rdev);
 	ks.st_pad2[0] = ks.st_pad2[1] = 0;
-	ks.st_size = (long long) sb->st_size;
+	ks.st_size = (long long) stat->size;
 	ks.st_pad3 = 0;
 
 	/* XXX hackety hack... */
-	ks.st_atime.tv_sec = (s32) sb->st_atime; ks.st_atime.tv_nsec = 0;
-	ks.st_mtime.tv_sec = (s32) sb->st_atime; ks.st_mtime.tv_nsec = 0;
-	ks.st_ctime.tv_sec = (s32) sb->st_atime; ks.st_ctime.tv_nsec = 0;
+	ks.st_atime.tv_sec = (s32) stat->atime; ks.st_atime.tv_nsec = 0;
+	ks.st_mtime.tv_sec = (s32) stat->atime; ks.st_mtime.tv_nsec = 0;
+	ks.st_ctime.tv_sec = (s32) stat->atime; ks.st_ctime.tv_nsec = 0;
 
-	ks.st_blksize = (s32) sb->st_blksize;
-	ks.st_blocks = (long long) sb->st_blocks;
+	ks.st_blksize = (s32) stat->blksize;
+	ks.st_blocks = (long long) stat->blocks;
 	memset(ks.st_fstype, 0, 16);
 	ks.st_pad4[0] = ks.st_pad4[1] = ks.st_pad4[2] = ks.st_pad4[3] = 0;
 	ks.st_pad4[4] = ks.st_pad4[5] = ks.st_pad4[6] = ks.st_pad4[7] = 0;
 
 	/* Now write it all back. */
-	copy_to_user(sb, &ks, sizeof(struct xstat64));
+	copy_to_user(ubuf, &ks, sizeof(struct xstat64));
 }
 
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-
 asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf)
 {
 	int retval;
+	struct kstat stat;
 
 #ifdef DEBUG_XSTAT
 	printk("[%s:%d] Wheee.. irix_xstat(%d,%s,%p) ",
 	       current->comm, current->pid, version, filename, statbuf);
 #endif
-	switch(version) {
-	case 2: {
-		struct stat kb;
-		mm_segment_t old_fs;
-
-		old_fs = get_fs(); set_fs(get_ds());
-		retval = sys_newstat(filename, &kb);
-		set_fs(old_fs);
-#ifdef DEBUG_XSTAT
-		printk("retval[%d]\n", retval);
-#endif
-		if(retval)
-			goto out;
-		retval = irix_xstat32_xlate(&kb, statbuf);
-		goto out;
-	}
-
-	case 3: {
-		retval = sys_newstat(filename, statbuf);
-#ifdef DEBUG_XSTAT
-		printk("retval[%d]\n", retval);
-#endif
-		if(retval)
-			goto out;
 
-		irix_xstat64_xlate(statbuf);
-		retval = 0;
-		break;
+	retval = vfs_stat(filename, &stat);
+	if (!retval) {
+		switch(version) {
+			case 2:
+				retval = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				irix_xstat64_xlate(&stat, statbuf);
+				retval = 0; /* Really? */
+				break;
+			default:
+				retval = -EINVAL;
+		}
 	}
-
-	default:
-		retval = -EINVAL;
-		break;
-	}
-
-out:
 	return retval;
 }
 
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-
 asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf)
 {
 	int error;
+	struct kstat stat;
 
 #ifdef DEBUG_XSTAT
 	printk("[%s:%d] Wheee.. irix_lxstat(%d,%s,%p) ",
 	       current->comm, current->pid, version, filename, statbuf);
 #endif
-	switch(version) {
-	case 2: {
-		struct stat kb;
-		mm_segment_t old_fs;
-
-		old_fs = get_fs(); set_fs(get_ds());
-		error = sys_newlstat(filename, &kb);
-		set_fs(old_fs);
-#ifdef DEBUG_XSTAT
-		printk("error[%d]\n", error);
-#endif
-		if(error)
-			goto out;
-		error = irix_xstat32_xlate(&kb, statbuf);
-		goto out;
-	}
 
-	case 3: {
-		error = sys_newlstat(filename, statbuf);
-#ifdef DEBUG_XSTAT
-		printk("error[%d]\n", error);
-#endif
-		if(error)
-			goto out;
-
-		irix_xstat64_xlate(statbuf);
-		error = 0;
-		goto out;
-	}
+	error = vfs_lstat(filename, &stat);
 
-	default:
-		error = -EINVAL;
-		goto out;
+	if (!error) {
+		switch (version) {
+			case 2:
+				error = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				irix_xstat64_xlate(&stat, statbuf);
+				error = 0;
+				break;
+			default:
+				error = -EINVAL;
+		}
 	}
-
-out:
 	return error;
 }
 
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-
 asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf)
 {
 	int error;
+	struct kstat stat;
 
 #ifdef DEBUG_XSTAT
 	printk("[%s:%d] Wheee.. irix_fxstat(%d,%d,%p) ",
 	       current->comm, current->pid, version, fd, statbuf);
 #endif
-	switch(version) {
-	case 2: {
-		struct stat kb;
-		mm_segment_t old_fs;
-
-		old_fs = get_fs(); set_fs(get_ds());
-		error = sys_newfstat(fd, &kb);
-		set_fs(old_fs);
-#ifdef DEBUG_XSTAT
-		printk("error[%d]\n", error);
-#endif
-		if(error)
-			goto out;
-		error = irix_xstat32_xlate(&kb, statbuf);
-		goto out;
-	}
-
-	case 3: {
-		error = sys_newfstat(fd, statbuf);
-#ifdef DEBUG_XSTAT
-		printk("error[%d]\n", error);
-#endif
-		if(error)
-			goto out;
 
-		irix_xstat64_xlate(statbuf);
-		error = 0;
-		goto out;
+	error = vfs_fstat(fd, &stat);
+	if (!error) {
+		switch (version) {
+			case 2:
+				error = irix_xstat32_xlate(&stat, statbuf);
+				break;
+			case 3:
+				irix_xstat64_xlate(&stat, statbuf);
+				error = 0;
+				break;
+			default:
+				error = -EINVAL;
+		}
 	}
-
-	default:
-		error = -EINVAL;
-		goto out;
-	}
-
-out:
 	return error;
 }
 
diff -Nru a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c
--- a/arch/mips64/kernel/linux32.c	Wed Feb  6 22:48:38 2002
+++ b/arch/mips64/kernel/linux32.c	Wed Feb  6 22:48:38 2002
@@ -39,125 +39,59 @@
 /*
  * Revalidate the inode. This is required for proper NFS attribute caching.
  */
-static __inline__ int
-do_revalidate(struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-
-	return 0;
-}
 
-static int cp_new_stat32(struct inode * inode, struct stat32 * statbuf)
+static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
 {
 	struct stat32 tmp;
-	unsigned int blocks, indirect;
 
 	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	SET_STAT_UID(tmp, inode->i_uid);
-	SET_STAT_GID(tmp, inode->i_gid);
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-
-	/*
-	 * st_blocks and st_blksize are approximated with a simple algorithm if
-	 * they aren't supported directly by the filesystem. The minix and msdos
-	 * filesystems don't keep track of blocks, so they would either have to
-	 * be counted explicitly (by delving into the file itself), or by using
-	 * this simple algorithm to get a reasonable (although not 100%
-	 * accurate) value.
-	 */
-
-	/*
-	 * Use minix fs values for the number of direct and indirect blocks.
-	 * The count is now exact for the minix fs except that it counts zero
-	 * blocks.  Everything is in units of BLOCK_SIZE until the assignment
-	 * to tmp.st_blksize.
-	 */
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-
-	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (blocks > D_B) {
-			indirect = (blocks - D_B + I_B - 1) / I_B;
-			blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				blocks += indirect;
-				if (indirect > 1)
-					blocks++;
-			}
-		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
-	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
-	}
-
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_STAT_UID(tmp, stat->uid);
+	SET_STAT_GID(tmp, stat->gid);
+	tmp.st_rdev = stat->rdev;
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	tmp.st_blocks = stat->blocks;
+	tmp.st_blksize = stat->blksize;
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
-
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
 
-		path_release(&nd);
-	}
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
 	return error;
 }
 
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
-
-		path_release(&nd);
-	}
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
 	return error;
 }
 
 asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 * statbuf)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat32(dentry->d_inode, statbuf);
-		fput(f);
-	}
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	return err;
+	return error;
 }
 
 asmlinkage int sys_mmap2(void) {return 0;}
diff -Nru a/arch/mips64/kernel/scall_64.S b/arch/mips64/kernel/scall_64.S
--- a/arch/mips64/kernel/scall_64.S	Wed Feb  6 22:48:38 2002
+++ b/arch/mips64/kernel/scall_64.S	Wed Feb  6 22:48:38 2002
@@ -347,3 +347,5 @@
 	PTR	sys_mincore
 	PTR	sys_madvise
 	PTR	sys_getdents64
+	PTR	sys_gettid
+	PTR	sys_tkill
diff -Nru a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S
--- a/arch/mips64/kernel/scall_o32.S	Wed Feb  6 22:48:39 2002
+++ b/arch/mips64/kernel/scall_o32.S	Wed Feb  6 22:48:39 2002
@@ -454,6 +454,8 @@
 	sys	sys_madvise	3
 	sys	sys_getdents64	3
 	sys	sys32_fcntl64	3			/* 4220 */
+	sys	sys32_gettid	0
+	sys	sys32_tkill	2
 	.endm
 
 	.macro	sys function, nargs
diff -Nru a/arch/mips64/kernel/signal.c b/arch/mips64/kernel/signal.c
--- a/arch/mips64/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/mips64/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -685,10 +685,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c
--- a/arch/mips64/kernel/signal32.c	Wed Feb  6 22:48:39 2002
+++ b/arch/mips64/kernel/signal32.c	Wed Feb  6 22:48:39 2002
@@ -757,10 +757,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
--- a/arch/parisc/hpux/fs.c	Wed Feb  6 22:48:39 2002
+++ b/arch/parisc/hpux/fs.c	Wed Feb  6 22:48:39 2002
@@ -83,42 +83,20 @@
 int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
 {
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	struct hpux_dirent * lastdirent;
 	struct getdents_callback buf;
-	int error;
+	int error = -EBADF;
 
-	lock_kernel();
-	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out_putf;
-
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.current_dir = dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, filldir);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, &buf, filldir);
 	if (error < 0)
 		goto out_putf;
 	error = buf.error;
@@ -131,7 +109,6 @@
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -141,110 +118,56 @@
 	return -ENOSYS;
 }
 
-static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf)
+static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 *statbuf)
 {
 	struct hpux_stat64 tmp;
-	unsigned int blocks, indirect;
 
 	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	tmp.st_uid = inode->i_uid;
-	tmp.st_gid = inode->i_gid;
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-
-	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (blocks > D_B) {
-			indirect = (blocks - D_B + I_B - 1) / I_B;
-			blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				blocks += indirect;
-				if (indirect > 1)
-					blocks++;
-			}
-		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
-	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
-	}
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	tmp.st_uid = stat->uid;
+	tmp.st_gid = stat->gid;
+	tmp.st_rdev = stat->rdev;
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	tmp.st_blocks = stat->blocks;
+	tmp.st_blksize = stat->blksize;
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
-/*
- * Revalidate the inode. This is required for proper NFS attribute caching.
- * Blatently copied wholesale from fs/stat.c
- */
-static __inline__ int
-do_revalidate(struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-	return 0;
-}
-
 long hpux_stat64(const char *path, struct hpux_stat64 *buf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_hpux_stat(&stat, statbuf);
 
-	lock_kernel();
-	error = user_path_walk(path, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_hpux_stat(nd.dentry->d_inode, buf);
-		path_release(&nd);
-	}
-	unlock_kernel();
 	return error;
 }
 
 long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	lock_kernel();
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_hpux_stat(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	unlock_kernel();
-	return err;
+	if (!error)
+		error = cp_hpux_stat(&stat, statbuf);
+
+	return error;
 }
 
 long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+
+	if (!error)
+		error = cp_hpux_stat(&stat, statbuf);
 
-	lock_kernel();
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_hpux_stat(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
-	unlock_kernel();
 	return error;
 }
diff -Nru a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
--- a/arch/parisc/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/parisc/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -581,11 +581,7 @@
 				/* FALLTHRU */
 
 			default:
-				lock_kernel();
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
--- a/arch/parisc/kernel/syscall.S	Wed Feb  6 22:48:39 2002
+++ b/arch/parisc/kernel/syscall.S	Wed Feb  6 22:48:39 2002
@@ -552,6 +552,8 @@
 	ENTRY_UHOH(shmctl)		/* 195 */
 	ENTRY_SAME(ni_syscall)		/* streams1 */
 	ENTRY_SAME(ni_syscall)		/* streams2 */
+	ENTRY_SAME(gettid)
+	ENTRY_SAME(tkill)
 
 .end
 
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Wed Feb  6 22:48:39 2002
+++ b/arch/ppc/kernel/misc.S	Wed Feb  6 22:48:39 2002
@@ -1121,6 +1121,7 @@
 	.long sys_madvise	/* 205 */
 	.long sys_mincore
 	.long sys_gettid
+	.long sys_tkill
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
 	.endr
diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
--- a/arch/ppc/kernel/ppc_htab.c	Wed Feb  6 22:48:38 2002
+++ b/arch/ppc/kernel/ppc_htab.c	Wed Feb  6 22:48:38 2002
@@ -21,6 +21,7 @@
 #include <linux/sysctl.h>
 #include <linux/ctype.h>
 #include <linux/threads.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -430,18 +431,20 @@
 static long long
 ppc_htab_lseek(struct file * file, loff_t offset, int orig)
 {
+    long long ret = -EINVAL;
+
+    lock_kernel();
     switch (orig) {
     case 0:
 	file->f_pos = offset;
-	return(file->f_pos);
+	ret = file->f_pos;
+	break;
     case 1:
 	file->f_pos += offset;
-	return(file->f_pos);
-    case 2:
-	return(-EINVAL);
-    default:
-	return(-EINVAL);
+	ret = file->f_pos;
     }
+    unlock_kernel();
+    return ret;
 }
 
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/ppc/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -641,10 +641,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
--- a/arch/s390/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/s390/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -602,6 +602,8 @@
 	.long  sys_ni_syscall		 /* 224 - reserved for posix_acl */
 	.rept  255-224
 	.long  sys_ni_syscall
+	.long  sys_gettid		/* 226 */
+	.long  sys_tkill		/* 227 */
 	.endr
 
 /*
diff -Nru a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
--- a/arch/s390/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/s390/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -563,10 +563,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/s390x/kernel/entry.S b/arch/s390x/kernel/entry.S
--- a/arch/s390x/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/s390x/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -635,6 +635,8 @@
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */
         .rept  255-224
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+	.long  SYSCALL(sys_gettid,sys_gettid)
+	.long  SYSCALL(sys_tkill,sys_tkill)
 	.endr
 
 /*
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	Wed Feb  6 22:48:39 2002
+++ b/arch/s390x/kernel/linux32.c	Wed Feb  6 22:48:39 2002
@@ -1471,140 +1471,62 @@
 	return ret;
 }
 
-static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
 {
-	unsigned long ino, blksize, blocks;
-	kdev_t dev, rdev;
-	umode_t mode;
-	nlink_t nlink;
-	uid_t uid;
-	gid_t gid;
-	off_t size;
-	time_t atime, mtime, ctime;
-	int err;
-
-	/* Stream the loads of inode data into the load buffer,
-	 * then we push it all into the store buffer below.  This
-	 * should give optimal cache performance.
-	 */
-	ino = inode->i_ino;
-	dev = inode->i_dev;
-	mode = inode->i_mode;
-	nlink = inode->i_nlink;
-	uid = inode->i_uid;
-	gid = inode->i_gid;
-	rdev = inode->i_rdev;
-	size = inode->i_size;
-	atime = inode->i_atime;
-	mtime = inode->i_mtime;
-	ctime = inode->i_ctime;
-	blksize = inode->i_blksize;
-	blocks = inode->i_blocks;
-
-	err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
-	err |= put_user(ino, &statbuf->st_ino);
-	err |= put_user(mode, &statbuf->st_mode);
-	err |= put_user(nlink, &statbuf->st_nlink);
-	err |= put_user(high2lowuid(uid), &statbuf->st_uid);
-	err |= put_user(high2lowgid(gid), &statbuf->st_gid);
-	err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
-	err |= put_user(size, &statbuf->st_size);
-	err |= put_user(atime, &statbuf->st_atime);
+	err  = put_user(stat->dev, &statbuf->st_dev);
+	err |= put_user(stat->ino, &statbuf->st_ino);
+	err |= put_user(stat->mode, &statbuf->st_mode);
+	err |= put_user(stat->nlink, &statbuf->st_nlink);
+	err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
+	err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
+	err |= put_user(stat->rdev, &statbuf->st_rdev);
+	err |= put_user(stat->size, &statbuf->st_size);
+	err |= put_user(stat->atime, &statbuf->st_atime);
 	err |= put_user(0, &statbuf->__unused1);
-	err |= put_user(mtime, &statbuf->st_mtime);
+	err |= put_user(stat->mtime, &statbuf->st_mtime);
 	err |= put_user(0, &statbuf->__unused2);
-	err |= put_user(ctime, &statbuf->st_ctime);
+	err |= put_user(stat->ctime, &statbuf->st_ctime);
 	err |= put_user(0, &statbuf->__unused3);
-	if (blksize) {
-		err |= put_user(blksize, &statbuf->st_blksize);
-		err |= put_user(blocks, &statbuf->st_blocks);
-	} else {
-		unsigned int tmp_blocks;
-
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-		tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (tmp_blocks > D_B) {
-			unsigned int indirect;
-
-			indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
-			tmp_blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				tmp_blocks += indirect;
-				if (indirect > 1)
-					tmp_blocks++;
-			}
-		}
-		err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
-		err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
-#undef D_B
-#undef I_B
-	}
+	err |= put_user(stat->blksize, &statbuf->st_blksize);
+	err |= put_user(stat->blocks, &statbuf->st_blocks);
 /* fixme
 	err |= put_user(0, &statbuf->__unused4[0]);
 	err |= put_user(0, &statbuf->__unused4[1]);
 */
-
 	return err;
 }
 
-/* Perhaps this belongs in fs.h or similar. -DaveM */
-static __inline__ int
-do_revalidate(struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-	return 0;
-}
-
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
-	struct file *f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat32(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
+
+	return error;
 }
 
 extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
diff -Nru a/arch/s390x/kernel/signal.c b/arch/s390x/kernel/signal.c
--- a/arch/s390x/kernel/signal.c	Wed Feb  6 22:48:38 2002
+++ b/arch/s390x/kernel/signal.c	Wed Feb  6 22:48:38 2002
@@ -569,10 +569,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/s390x/kernel/signal32.c b/arch/s390x/kernel/signal32.c
--- a/arch/s390x/kernel/signal32.c	Wed Feb  6 22:48:39 2002
+++ b/arch/s390x/kernel/signal32.c	Wed Feb  6 22:48:39 2002
@@ -699,10 +699,7 @@
                                 /* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
--- a/arch/sh/kernel/entry.S	Wed Feb  6 22:48:39 2002
+++ b/arch/sh/kernel/entry.S	Wed Feb  6 22:48:39 2002
@@ -1195,6 +1195,8 @@
 	.long SYMBOL_NAME(sys_madvise)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
+	.long SYMBOL_NAME(sys_gettid)
+	.long SYMBOL_NAME(sys_tkill)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
diff -Nru a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
--- a/arch/sh/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sh/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -673,10 +673,7 @@
 				/* FALLTHRU */
 
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOTREACHED */
 			}
 		}
diff -Nru a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
--- a/arch/sparc/kernel/rtrap.S	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc/kernel/rtrap.S	Wed Feb  6 22:48:39 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/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -1280,10 +1280,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc/kernel/sys_sunos.c	Wed Feb  6 22:48:39 2002
@@ -646,7 +646,7 @@
 
 	inode = file->f_dentry->d_inode;
 
-	socket = &inode->u.socket_i;
+	socket = SOCKET_I(inode);
 	local.sin_family = AF_INET;
 	local.sin_addr.s_addr = INADDR_ANY;
 
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc/kernel/systbls.S	Wed Feb  6 22:48:39 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
@@ -70,7 +70,7 @@
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_nis_syscall, sys_nis_syscall
+/*255*/	.long sys_nis_syscall, sys_nis_syscall, sys_tkill
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/entry.S	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/kernel/process.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/kernel/ptrace.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/kernel/rtrap.S	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/signal.c	Wed Feb  6 22:48:38 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	
@@ -807,10 +807,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
@@ -829,4 +826,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	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/signal32.c	Wed Feb  6 22:48:38 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;
@@ -1479,10 +1479,7 @@
 #endif
 				/* fall through */
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending(current);
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/smp.c	Wed Feb  6 22:48:38 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/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Wed Feb  6 22:48:38 2002
@@ -1459,138 +1459,60 @@
 	return ret;
 }
 
-static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
 {
-	unsigned long ino, blksize, blocks;
-	kdev_t dev, rdev;
-	umode_t mode;
-	nlink_t nlink;
-	uid_t uid;
-	gid_t gid;
-	off_t size;
-	time_t atime, mtime, ctime;
-	int err;
-
-	/* Stream the loads of inode data into the load buffer,
-	 * then we push it all into the store buffer below.  This
-	 * should give optimal cache performance.
-	 */
-	ino = inode->i_ino;
-	dev = inode->i_dev;
-	mode = inode->i_mode;
-	nlink = inode->i_nlink;
-	uid = inode->i_uid;
-	gid = inode->i_gid;
-	rdev = inode->i_rdev;
-	size = inode->i_size;
-	atime = inode->i_atime;
-	mtime = inode->i_mtime;
-	ctime = inode->i_ctime;
-	blksize = inode->i_blksize;
-	blocks = inode->i_blocks;
-
-	err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
-	err |= put_user(ino, &statbuf->st_ino);
-	err |= put_user(mode, &statbuf->st_mode);
-	err |= put_user(nlink, &statbuf->st_nlink);
-	err |= put_user(high2lowuid(uid), &statbuf->st_uid);
-	err |= put_user(high2lowgid(gid), &statbuf->st_gid);
-	err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
-	err |= put_user(size, &statbuf->st_size);
-	err |= put_user(atime, &statbuf->st_atime);
+	err  = put_user(stat->dev, &statbuf->st_dev);
+	err |= put_user(stat->ino, &statbuf->st_ino);
+	err |= put_user(stat->mode, &statbuf->st_mode);
+	err |= put_user(stat->nlink, &statbuf->st_nlink);
+	err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
+	err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
+	err |= put_user(stat->rdev, &statbuf->st_rdev);
+	err |= put_user(stat->size, &statbuf->st_size);
+	err |= put_user(stat->atime, &statbuf->st_atime);
 	err |= put_user(0, &statbuf->__unused1);
-	err |= put_user(mtime, &statbuf->st_mtime);
+	err |= put_user(stat->mtime, &statbuf->st_mtime);
 	err |= put_user(0, &statbuf->__unused2);
-	err |= put_user(ctime, &statbuf->st_ctime);
+	err |= put_user(stat->ctime, &statbuf->st_ctime);
 	err |= put_user(0, &statbuf->__unused3);
-	if (blksize) {
-		err |= put_user(blksize, &statbuf->st_blksize);
-		err |= put_user(blocks, &statbuf->st_blocks);
-	} else {
-		unsigned int tmp_blocks;
-
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-		tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (tmp_blocks > D_B) {
-			unsigned int indirect;
-
-			indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
-			tmp_blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				tmp_blocks += indirect;
-				if (indirect > 1)
-					tmp_blocks++;
-			}
-		}
-		err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
-		err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
-#undef D_B
-#undef I_B
-	}
+	err |= put_user(stat->blksize, &statbuf->st_blksize);
+	err |= put_user(stat->blocks, &statbuf->st_blocks);
 	err |= put_user(0, &statbuf->__unused4[0]);
 	err |= put_user(0, &statbuf->__unused4[1]);
-
 	return err;
 }
 
-/* Perhaps this belongs in fs.h or similar. -DaveM */
-static __inline__ int
-do_revalidate(struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-	return 0;
-}
-
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
-	struct file *f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat32(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
+
+	return error;
 }
 
 extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/kernel/sys_sunos32.c	Wed Feb  6 22:48:38 2002
@@ -612,7 +612,7 @@
 
 	inode = file->f_dentry->d_inode;
 
-	socket = &inode->u.socket_i;
+	socket = SOCKET_I(inode);
 	local.sin_family = AF_INET;
 	local.sin_addr.s_addr = INADDR_ANY;
 
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/kernel/systbls.S	Wed Feb  6 22:48:39 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
@@ -70,7 +70,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_tkill
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -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
@@ -129,7 +129,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_tkill
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/kernel/traps.c	Wed Feb  6 22:48:39 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/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
--- a/arch/sparc64/solaris/fs.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/solaris/fs.c	Wed Feb  6 22:48:39 2002
@@ -79,47 +79,49 @@
 
 #define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
 
-static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf)
+static inline int putstat(struct sol_stat *ubuf, struct kstat *kbuf)
 {
-	if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev)	||
-	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
-	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
-	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
-	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
-	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
-	    __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev)	||
-	    __put_user (kbuf->st_size, &ubuf->st_size)		||
-	    __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec)	||
+	if (kbuf->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+	if (put_user (R4_DEV(kbuf->dev), &ubuf->st_dev)	||
+	    __put_user (kbuf->ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->gid, &ubuf->st_gid)		||
+	    __put_user (R4_DEV(kbuf->rdev), &ubuf->st_rdev)	||
+	    __put_user (kbuf->size, &ubuf->st_size)		||
+	    __put_user (kbuf->atime, &ubuf->st_atime.tv_sec)	||
 	    __put_user (0, &ubuf->st_atime.tv_nsec)		||
-	    __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec)	||
+	    __put_user (kbuf->mtime, &ubuf->st_mtime.tv_sec)	||
 	    __put_user (0, &ubuf->st_mtime.tv_nsec)		||
-	    __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec)	||
+	    __put_user (kbuf->ctime, &ubuf->st_ctime.tv_sec)	||
 	    __put_user (0, &ubuf->st_ctime.tv_nsec)		||
-	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
-	    __put_user (kbuf->st_blocks, &ubuf->st_blocks)	||
+	    __put_user (kbuf->blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->blocks, &ubuf->st_blocks)	||
 	    __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int putstat64(struct sol_stat64 *ubuf, struct stat *kbuf)
+static inline int putstat64(struct sol_stat64 *ubuf, struct kstat *kbuf)
 {
-	if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev)	||
-	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
-	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
-	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
-	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
-	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
-	    __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev)	||
-	    __put_user (kbuf->st_size, &ubuf->st_size)		||
-	    __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec)	||
+	if (put_user (R4_DEV(kbuf->dev), &ubuf->st_dev)	||
+	    __put_user (kbuf->ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->gid, &ubuf->st_gid)		||
+	    __put_user (R4_DEV(kbuf->rdev), &ubuf->st_rdev)	||
+	    __put_user (kbuf->size, &ubuf->st_size)		||
+	    __put_user (kbuf->atime, &ubuf->st_atime.tv_sec)	||
 	    __put_user (0, &ubuf->st_atime.tv_nsec)		||
-	    __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec)	||
+	    __put_user (kbuf->mtime, &ubuf->st_mtime.tv_sec)	||
 	    __put_user (0, &ubuf->st_mtime.tv_nsec)		||
-	    __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec)	||
+	    __put_user (kbuf->ctime, &ubuf->st_ctime.tv_sec)	||
 	    __put_user (0, &ubuf->st_ctime.tv_nsec)		||
-	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
-	    __put_user (kbuf->st_blocks, &ubuf->st_blocks)	||
+	    __put_user (kbuf->blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->blocks, &ubuf->st_blocks)	||
 	    __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
 		return -EFAULT;
 	return 0;
@@ -128,21 +130,18 @@
 asmlinkage int solaris_stat(u32 filename, u32 statbuf)
 {
 	int ret;
-	struct stat s;
+	struct kstat s;
 	char *filenam;
 	mm_segment_t old_fs = get_fs();
-	int (*sys_newstat)(char *,struct stat *) = 
-		(int (*)(char *,struct stat *))SYS(stat);
 	
 	filenam = getname ((char *)A(filename));
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		set_fs (KERNEL_DS);
-		ret = sys_newstat(filenam, &s);
+		ret = vfs_stat(filenam, &s);
 		set_fs (old_fs);
 		putname (filenam);
-		if (putstat ((struct sol_stat *)A(statbuf), &s))
-			return -EFAULT;
+		return putstat((struct sol_stat *)A(statbuf), &s);
 	}
 	return ret;
 }
@@ -156,21 +155,18 @@
 asmlinkage int solaris_stat64(u32 filename, u32 statbuf)
 {
 	int ret;
-	struct stat s;
+	struct kstat s;
 	char *filenam;
 	mm_segment_t old_fs = get_fs();
-	int (*sys_newstat)(char *,struct stat *) = 
-		(int (*)(char *,struct stat *))SYS(stat);
 	
 	filenam = getname ((char *)A(filename));
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		set_fs (KERNEL_DS);
-		ret = sys_newstat(filenam, &s);
+		ret = vfs_stat(filenam, &s);
 		set_fs (old_fs);
 		putname (filenam);
-		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
-			return -EFAULT;
+		return putstat64((struct sol_stat64 *)A(statbuf), &s);
 	}
 	return ret;
 }
@@ -178,21 +174,18 @@
 asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
 {
 	int ret;
-	struct stat s;
+	struct kstat s;
 	char *filenam;
 	mm_segment_t old_fs = get_fs();
-	int (*sys_newlstat)(char *,struct stat *) = 
-		(int (*)(char *,struct stat *))SYS(lstat);
 	
 	filenam = getname ((char *)A(filename));
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		set_fs (KERNEL_DS);
-		ret = sys_newlstat(filenam, &s);
+		ret = vfs_lstat(filenam, &s);
 		set_fs (old_fs);
 		putname (filenam);
-		if (putstat ((struct sol_stat *)A(statbuf), &s))
-			return -EFAULT;
+		return putstat((struct sol_stat *)A(statbuf), &s);
 	}
 	return ret;
 }
@@ -205,21 +198,18 @@
 asmlinkage int solaris_lstat64(u32 filename, u32 statbuf)
 {
 	int ret;
-	struct stat s;
+	struct kstat s;
 	char *filenam;
 	mm_segment_t old_fs = get_fs();
-	int (*sys_newlstat)(char *,struct stat *) = 
-		(int (*)(char *,struct stat *))SYS(lstat);
 	
 	filenam = getname ((char *)A(filename));
 	ret = PTR_ERR(filenam);
 	if (!IS_ERR(filenam)) {
 		set_fs (KERNEL_DS);
-		ret = sys_newlstat(filenam, &s);
+		ret = vfs_lstat(filenam, &s);
 		set_fs (old_fs);
 		putname (filenam);
-		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
-			return -EFAULT;
+		return putstat64((struct sol_stat64 *)A(statbuf), &s);
 	}
 	return ret;
 }
@@ -227,16 +217,10 @@
 asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
 {
 	int ret;
-	struct stat s;
-	mm_segment_t old_fs = get_fs();
-	int (*sys_newfstat)(unsigned,struct stat *) = 
-		(int (*)(unsigned,struct stat *))SYS(fstat);
-	
-	set_fs (KERNEL_DS);
-	ret = sys_newfstat(fd, &s);
-	set_fs (old_fs);
-	if (putstat ((struct sol_stat *)A(statbuf), &s))
-		return -EFAULT;
+	struct kstat s;
+	ret = vfs_fstat(fd, &s);
+	if (!ret)
+		return putstat((struct sol_stat *)A(statbuf), &s);
 	return ret;
 }
 
@@ -248,16 +232,11 @@
 asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf)
 {
 	int ret;
-	struct stat s;
-	mm_segment_t old_fs = get_fs();
-	int (*sys_newfstat)(unsigned,struct stat *) = 
-		(int (*)(unsigned,struct stat *))SYS(fstat);
+	struct kstat s;
 	
-	set_fs (KERNEL_DS);
-	ret = sys_newfstat(fd, &s);
-	set_fs (old_fs);
-	if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
-		return -EFAULT;
+	ret = vfs_fstat(fd, &s);
+	if (!ret)
+		return putstat64((struct sol_stat64 *)A(statbuf), &s);
 	return ret;
 }
 
diff -Nru a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
--- a/arch/sparc64/solaris/ioctl.c	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/solaris/ioctl.c	Wed Feb  6 22:48:38 2002
@@ -308,7 +308,7 @@
 	case 110: /* SI_GETUDATA */
 	{
 		int etsdusize, servtype;
-		switch (ino->u.socket_i.type) {
+		switch (SOCKET_I(ino)->type) {
 		case SOCK_STREAM:
 			etsdusize = 1;
 			servtype = 2;
@@ -326,16 +326,16 @@
 		    __put_user(0, &((struct solaris_si_udata *)A(arg))->so_state) ||
 		    __put_user(0, &((struct solaris_si_udata *)A(arg))->so_options) ||
 		    __put_user(16384, &((struct solaris_si_udata *)A(arg))->tsdusize) ||
-		    __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_family) ||
-		    __put_user(ino->u.socket_i.type, &((struct solaris_si_udata *)A(arg))->sockparams.sp_type) ||
-		    __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_protocol))
+		    __put_user(SOCKET_I(ino)->ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_family) ||
+		    __put_user(SOCKET_I(ino)->type, &((struct solaris_si_udata *)A(arg))->sockparams.sp_type) ||
+		    __put_user(SOCKET_I(ino)->ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_protocol))
 			return (EFAULT << 8) | TSYSERR;
 		return 0;
 	}
 	case 101: /* O_SI_GETUDATA */
 	{
 		int etsdusize, servtype;
-		switch (ino->u.socket_i.type) {
+		switch (SOCKET_I(ino)->type) {
 		case SOCK_STREAM:
 			etsdusize = 1;
 			servtype = 2;
diff -Nru a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
--- a/arch/sparc64/solaris/socket.c	Wed Feb  6 22:48:38 2002
+++ b/arch/sparc64/solaris/socket.c	Wed Feb  6 22:48:38 2002
@@ -248,12 +248,6 @@
 					   24 for IPv6,
 					   about 80 for AX.25 */
 
-/* XXX These as well... */
-extern __inline__ struct socket *socki_lookup(struct inode *inode)
-{
-	return &inode->u.socket_i;
-}
-
 extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
 {
 	struct file *file;
@@ -265,13 +259,13 @@
 	}
 
 	inode = file->f_dentry->d_inode;
-	if (!inode->i_sock || !socki_lookup(inode)) {
+	if (!inode->i_sock) {
 		*err = -ENOTSOCK;
 		fput(file);
 		return NULL;
 	}
 
-	return socki_lookup(inode);
+	return SOCKET_I(inode);
 }
 
 extern __inline__ void sockfd_put(struct socket *sock)
diff -Nru a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
--- a/arch/sparc64/solaris/socksys.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/solaris/socksys.c	Wed Feb  6 22:48:39 2002
@@ -6,6 +6,13 @@
  * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
  */
 
+/*
+ *  Dave, _please_ give me specifications on this fscking mess so that I
+ * could at least get it into the state when it wouldn't screw the rest of
+ * the kernel over.  socksys.c and timod.c _stink_ and we are not talking
+ * H2S here, it's isopropilmercaptan in concentrations way over LD50. -- AV
+ */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -86,6 +93,9 @@
 		return fd;
 	/*
 	 * N.B. The following operations are not legal!
+	 *
+	 * No shit.  WTF is it supposed to do, anyway?
+	 *
 	 * Try instead:
 	 * d_delete(filp->f_dentry), then d_instantiate with sock inode
 	 */
@@ -93,7 +103,7 @@
 	filp->f_dentry = dget(fcheck(fd)->f_dentry);
 	filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
 	filp->f_dentry->d_inode->i_flock = inode->i_flock;
-	filp->f_dentry->d_inode->u.socket_i.file = filp;
+	SOCKET_I(filp->f_dentry->d_inode)->file = filp;
 	filp->f_op = &socksys_file_ops;
         sock = (struct sol_socket_struct*) 
         	mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
--- a/arch/sparc64/solaris/timod.c	Wed Feb  6 22:48:39 2002
+++ b/arch/sparc64/solaris/timod.c	Wed Feb  6 22:48:39 2002
@@ -149,7 +149,7 @@
 	struct socket *sock;
 
 	SOLD("wakeing socket");
-	sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
+	sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode);
 	wake_up_interruptible(&sock->wait);
 	read_lock(&sock->sk->callback_lock);
 	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -640,7 +640,7 @@
 	ino = filp->f_dentry->d_inode;
 	sock = (struct sol_socket_struct *)filp->private_data;
 	SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
-	if ( ctl_maxlen > 0 && !sock->pfirst && ino->u.socket_i.type == SOCK_STREAM
+	if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
 		&& sock->state == TS_IDLE) {
 		SOLD("calling LISTEN");
 		args[0] = fd;
@@ -730,7 +730,7 @@
 	*flags_p = 0;
 	if (ctl_maxlen >= 0) {
 		SOLD("ACCEPT perhaps?");
-		if (ino->u.socket_i.type == SOCK_STREAM && sock->state == TS_IDLE) {
+		if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) {
 			struct T_conn_ind ind;
 			char *buf = getpage();
 			int len = BUF_SIZE;
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Wed Feb  6 22:48:39 2002
+++ b/drivers/Makefile	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/base/core.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/base/fs.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/base/interface.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/block/nbd.c	Wed Feb  6 22:48:39 2002
@@ -155,14 +155,15 @@
 	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)
 		FAIL("Sendmsg failed for control.");
@@ -417,10 +418,13 @@
 		file = fget(arg);
 		if (file) {
 			inode = file->f_dentry->d_inode;
-			/* N.B. Should verify that it's a socket */
-			lo->file = file;
-			lo->sock = &inode->u.socket_i;
-			error = 0;
+			if (inode->i_sock) {
+				lo->file = file;
+				lo->sock = SOCKET_I(inode);
+				error = 0;
+			} else {
+				fput(file);
+			}
 		}
 		return error;
 	case NBD_SET_BLKSIZE:
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/bluetooth/hci_usb.c	Wed Feb  6 22:48:39 2002
@@ -120,11 +120,11 @@
 	DBG("%s", hdev->name);
 
 	husb->read_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->read_urb)))
+	if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL)))
 		DBG("read submit failed. %d", status);
 
 	husb->intr_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->intr_urb)))
+	if ((status = usb_submit_urb(husb->intr_urb, GFP_KERNEL)))
 		DBG("interrupt submit failed. %d", status);
 
 	hdev->flags |= HCI_RUNNING;
@@ -428,7 +428,7 @@
 
 resubmit:
 	husb->read_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->read_urb)))
+	if ((status = usb_submit_urb(husb->read_urb, GFP_KERNEL)))
 		DBG("%s read URB submit failed %d", husb->hdev.name, status);
 
 	DBG("%s read URB re-submited", husb->hdev.name);
@@ -453,7 +453,7 @@
 	FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
 	                 hci_usb_ctrl, skb);
 
-	if ((status = usb_submit_urb(urb))) {
+	if ((status = usb_submit_urb(urb, GFP_KERNEL))) {
 		DBG("%s control URB submit failed %d", husb->hdev.name, status);
 		return status;
 	}
@@ -474,7 +474,7 @@
 	              hci_usb_bulk_write, skb);
 	urb->transfer_flags |= USB_QUEUE_BULK;
 
-	if ((status = usb_submit_urb(urb))) {
+	if ((status = usb_submit_urb(urb, GFP_KERNEL))) {
 		DBG("%s write URB submit failed %d", husb->hdev.name, status);
 		return status;
 	}
diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
--- a/drivers/bluetooth/hci_vhci.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/bluetooth/hci_vhci.c	Wed Feb  6 22:48:39 2002
@@ -221,11 +221,6 @@
 	return ret;
 }
 
-static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
 static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	return -EINVAL;
@@ -296,7 +291,7 @@
 
 static struct file_operations hci_vhci_fops = {
 	owner:	THIS_MODULE,	
-	llseek:	hci_vhci_chr_lseek,
+	llseek:	no_lseek,
 	read:	hci_vhci_chr_read,
 	write:	hci_vhci_chr_write,
 	poll:	hci_vhci_chr_poll,
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/Config.in	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/Makefile	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/char/lp.c	Wed Feb  6 22:48:38 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/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/mem.c	Wed Feb  6 22:48:39 2002
@@ -21,6 +21,7 @@
 #include <linux/raw.h>
 #include <linux/tty.h>
 #include <linux/capability.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -466,16 +467,23 @@
  */
 static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
 {
+	int ret;
+
+	lock_kernel();
 	switch (orig) {
 		case 0:
 			file->f_pos = offset;
-			return file->f_pos;
+			ret = file->f_pos;
+			break;
 		case 1:
 			file->f_pos += offset;
-			return file->f_pos;
+			ret = file->f_pos;
+			break;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
 	}
+	unlock_kernel();
+	return ret;
 }
 
 static int open_port(struct inode * inode, struct file * filp)
diff -Nru a/drivers/char/nvram.c b/drivers/char/nvram.c
--- a/drivers/char/nvram.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/nvram.c	Wed Feb  6 22:48:39 2002
@@ -216,6 +216,7 @@
 
 static long long nvram_llseek(struct file *file,loff_t offset, int origin )
 {
+	lock_kernel();
 	switch( origin ) {
 	  case 0:
 		/* nothing to do */
@@ -227,6 +228,7 @@
 		offset += NVRAM_BYTES;
 		break;
 	}
+	unlock_kernel();
 	return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
 }
 
diff -Nru a/drivers/char/nwflash.c b/drivers/char/nwflash.c
--- a/drivers/char/nwflash.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/nwflash.c	Wed Feb  6 22:48:39 2002
@@ -26,6 +26,7 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
@@ -301,30 +302,45 @@
  */
 static long long flash_llseek(struct file *file, long long offset, int orig)
 {
+	long long ret;
+
+	lock_kernel();
 	if (flashdebug)
 		printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
 		       (unsigned int) offset, orig);
 
 	switch (orig) {
 	case 0:
-		if (offset < 0)
-			return -EINVAL;
+		if (offset < 0) {
+			ret = -EINVAL;
+			break;
+		}
 
-		if ((unsigned int) offset > gbFlashSize)
-			return -EINVAL;
+		if ((unsigned int) offset > gbFlashSize) {
+			ret = -EINVAL;
+			break;
+		}
 
 		file->f_pos = (unsigned int) offset;
-		return file->f_pos;
+		ret = file->f_pos;
+		break;
 	case 1:
-		if ((file->f_pos + offset) > gbFlashSize)
-			return -EINVAL;
-		if ((file->f_pos + offset) < 0)
-			return -EINVAL;
+		if ((file->f_pos + offset) > gbFlashSize) {
+			ret = -EINVAL;
+			break;
+		}
+		if ((file->f_pos + offset) < 0) {
+			ret = -EINVAL;
+			break;
+		}
 		file->f_pos += offset;
-		return file->f_pos;
+		ret = file->f_pos;
+		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+	unlock_kernel();
+	return ret;
 }
 
 
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/ppdev.c	Wed Feb  6 22:48:39 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/char/vc_screen.c b/drivers/char/vc_screen.c
--- a/drivers/char/vc_screen.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/char/vc_screen.c	Wed Feb  6 22:48:39 2002
@@ -36,6 +36,7 @@
 #include <linux/selection.h>
 #include <linux/kbd_kern.h>
 #include <linux/console.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -67,10 +68,13 @@
 
 static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
 {
-	int size = vcs_size(file->f_dentry->d_inode);
+	int size;
 
+	lock_kernel();
+	size = vcs_size(file->f_dentry->d_inode);
 	switch (orig) {
 		default:
+			unlock_kernel();
 			return -EINVAL;
 		case 2:
 			offset += size;
@@ -80,9 +84,12 @@
 		case 0:
 			break;
 	}
-	if (offset < 0 || offset > size)
+	if (offset < 0 || offset > size) {
+		unlock_kernel();
 		return -EINVAL;
+	}
 	file->f_pos = offset;
+	unlock_kernel();
 	return file->f_pos;
 }
 
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Wed Feb  6 22:48:39 2002
@@ -362,7 +362,7 @@
 	put_inode:	force_delete,
 };
 
-static struct super_block *pcihpfs_read_super (struct super_block *sb, void *data, int silent)
+static int pcihpfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
 	struct dentry *root;
@@ -375,20 +375,31 @@
 
 	if (!inode) {
 		dbg("%s: could not get inode!\n",__FUNCTION__);
-		return NULL;
+		return -ENOMEM;
 	}
 
 	root = d_alloc_root(inode);
 	if (!root) {
 		dbg("%s: could not get root dentry!\n",__FUNCTION__);
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root = root;
-	return sb;
+	return 0;
 }
 
-static DECLARE_FSTYPE(pcihpfs_fs_type, "pcihpfs", pcihpfs_read_super, FS_SINGLE | FS_LITTER);
+static struct super_block *pcihpfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, pcihpfs_fill_super);
+}
+
+static struct file_system_type pcihpfs_type = {
+	owner:		THIS_MODULE,
+	name:		"pchihpfs",
+	get_sb:		pcihpfs_get_sb,
+	fs_flags:	FS_LITTER,
+};
 
 static int get_mount (void)
 {
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/ide/ide-proc.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/ide/ide.c	Wed Feb  6 22:48:39 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/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
--- a/drivers/ieee1394/pcilynx.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/ieee1394/pcilynx.c	Wed Feb  6 22:48:39 2002
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
+#include <linux/smp_lock.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -732,8 +733,9 @@
 
 loff_t mem_llseek(struct file *file, loff_t offs, int orig)
 {
-        loff_t newoffs;
+        loff_t newoffs = -1;
 
+        lock_kernel();
         switch (orig) {
         case 0:
                 newoffs = offs;
@@ -743,12 +745,12 @@
                 break;
         case 2:
                 newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
-                break;
-        default:
-                return -EINVAL;
         }
 
-        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
+        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) {
+                lock_kernel();
+                return -EINVAL;
+        }
 
         file->f_pos = newoffs;
         return newoffs;
diff -Nru a/drivers/input/Config.help b/drivers/input/Config.help
--- a/drivers/input/Config.help	Wed Feb  6 22:48:39 2002
+++ b/drivers/input/Config.help	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/input/Config.in	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/input/Makefile	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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, GFP_ATOMIC)) {
+				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, GFP_ATOMIC)) {
+				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, GFP_KERNEL))
+					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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 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/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
--- a/drivers/isdn/avmb1/capifs.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/avmb1/capifs.c	Wed Feb  6 22:48:39 2002
@@ -281,17 +281,12 @@
 	return 0;
 }
 
-struct super_block *capifs_read_super(struct super_block *s, void *data,
-				      int silent)
+static int capifs_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
 	struct dentry * root;
 	struct capifs_sb_info *sbi;
 
-	/* Super block already completed? */
-	if (s->s_root)
-		goto out;
-
 	sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
 	if ( !sbi )
 		goto fail;
@@ -317,7 +312,6 @@
 	s->s_blocksize_bits = 10;
 	s->s_magic = CAPIFS_SUPER_MAGIC;
 	s->s_op = &capifs_sops;
-	s->s_root = NULL;
 
 	/*
 	 * Get the root inode and dentry, but defer checking for errors.
@@ -332,15 +326,6 @@
 	} 
 	root = d_alloc_root(root_inode);
 
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root) {
-		if (root) dput(root);
-		else iput(root_inode);
-		goto out;
-	}
-
 	if (!root) {
 		printk("capifs: get root dentry failed\n");
 		/*
@@ -352,15 +337,6 @@
 		goto fail;
 	}
 
-	/*
-	 * Check whether somebody else completed the super block.
-	 */
-	if (s->s_root)
-		goto out;
-	
-	/*
-	 * Success! Install the root dentry now to indicate completion.
-	 */
 	s->s_root = root;
 
 	sbi->next = mounts;
@@ -368,11 +344,9 @@
 		SBI(sbi->next)->back = &(sbi->next);
 	sbi->back = &mounts;
 	mounts = s;
-
-out:	/* Success ... somebody else completed the super block for us. */ 
-	return s;
+	return 0;
 fail:
-	return NULL;
+	return -EINVAL;
 }
 
 static int capifs_statfs(struct super_block *sb, struct statfs *buf)
@@ -400,7 +374,17 @@
 	return inode;
 }
 
-static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0);
+static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, capifs_fill_super);
+}
+
+static struct file_system_type capifs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"capifs",
+	get_sb:		capifs_get_sb,
+};
 
 void capifs_new_ncci(char type, unsigned int num, kdev_t device)
 {
diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
--- a/drivers/isdn/hisax/elsa.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/hisax/elsa.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/isdn/hisax/gazel.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/isdn/hisax/hisax.h	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c	Wed Feb  6 22:48:39 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/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
--- a/drivers/isdn/hisax/st5481.h	Wed Feb  6 22:48:38 2002
+++ b/drivers/isdn/hisax/st5481.h	Wed Feb  6 22:48:38 2002
@@ -409,10 +409,10 @@
  * Submit an URB with error reporting. This is a macro so
  * the __FUNCTION__ returns the caller function name.
  */
-#define SUBMIT_URB(urb) \
+#define SUBMIT_URB(urb, mem_flags) \
 ({ \
 	int status; \
-	if ((status = usb_submit_urb(urb)) < 0) { \
+	if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \
 		WARN("usb_submit_urb failed,status=%d", status); \
 	} \
         status; \
diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
--- a/drivers/isdn/hisax/st5481_b.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/hisax/st5481_b.c	Wed Feb  6 22:48:39 2002
@@ -115,7 +115,7 @@
 
 	DBG_ISO_PACKET(0x200,urb);
 
-	SUBMIT_URB(urb);
+	SUBMIT_URB(urb, GFP_KERNEL);
 }
 
 /*
diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
--- a/drivers/isdn/hisax/st5481_d.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/hisax/st5481_d.c	Wed Feb  6 22:48:39 2002
@@ -356,10 +356,10 @@
 
 	DBG_ISO_PACKET(0x20,urb);
 
-	if (usb_submit_urb(urb) < 0) {
+	if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
 		// There is another URB queued up
 		urb->transfer_flags = USB_ISO_ASAP;
-		SUBMIT_URB(urb);
+		SUBMIT_URB(urb, GFP_KERNEL);
 	}	
 }
 
@@ -450,7 +450,7 @@
 	urb->transfer_flags = USB_ISO_ASAP;
 
 	DBG_ISO_PACKET(0x20,urb);
-	SUBMIT_URB(urb);
+	SUBMIT_URB(urb, GFP_KERNEL);
 }
 
 static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg)
diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
--- a/drivers/isdn/hisax/st5481_usb.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/isdn/hisax/st5481_usb.c	Wed Feb  6 22:48:38 2002
@@ -48,7 +48,7 @@
 	// Prepare the URB
 	urb->dev = adapter->usb_dev;
 
-	SUBMIT_URB(urb);
+	SUBMIT_URB(urb, GFP_KERNEL);
 }
 
 /*
@@ -357,7 +357,7 @@
 	adapter->leds = RED_LED; 
 
 	// Start receiving on the interrupt endpoint
-	SUBMIT_URB(intr->urb); 
+	SUBMIT_URB(intr->urb, GFP_KERNEL); 
 
 	while ((request = init_cmd_table[i++])) {
 		value = init_cmd_table[i++];
@@ -517,7 +517,7 @@
 	urb->dev = in->adapter->usb_dev;
 	urb->actual_length = 0;
 
-	SUBMIT_URB(urb);
+	SUBMIT_URB(urb, GFP_KERNEL);
 }
 
 int __devinit st5481_setup_in(struct st5481_in *in)
@@ -603,10 +603,10 @@
 	DBG(4,"");
 
 	in->urb[0]->dev = adapter->usb_dev;
-	SUBMIT_URB(in->urb[0]);
+	SUBMIT_URB(in->urb[0], GFP_KERNEL);
 
 	in->urb[1]->dev = adapter->usb_dev;
-	SUBMIT_URB(in->urb[1]);
+	SUBMIT_URB(in->urb[1], GFP_KERNEL);
 }
 
 void st5481_in_mode(struct st5481_in *in, int mode)
diff -Nru a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
--- a/drivers/isdn/isdn_audio.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/isdn/isdn_audio.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/isdn_common.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/isdn/isdn_net.c	Wed Feb  6 22:48:39 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/macintosh/nvram.c b/drivers/macintosh/nvram.c
--- a/drivers/macintosh/nvram.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/macintosh/nvram.c	Wed Feb  6 22:48:38 2002
@@ -13,6 +13,7 @@
 #include <linux/fcntl.h>
 #include <linux/nvram.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/nvram.h>
 
@@ -20,6 +21,7 @@
 
 static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
 {
+	lock_kernel();
 	switch (origin) {
 	case 1:
 		offset += file->f_pos;
@@ -28,9 +30,12 @@
 		offset += NVRAM_SIZE;
 		break;
 	}
-	if (offset < 0)
+	if (offset < 0) {
+		unlock_kernel();
 		return -EINVAL;
+	}
 	file->f_pos = offset;
+	unlock_kernel();
 	return file->f_pos;
 }
 
diff -Nru a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
--- a/drivers/media/video/cpia_usb.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/media/video/cpia_usb.c	Wed Feb  6 22:48:38 2002
@@ -246,13 +246,13 @@
 	ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb;
 	ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb;
 	
-	err = usb_submit_urb(ucpia->sbuf[0].urb);
+	err = usb_submit_urb(ucpia->sbuf[0].urb, GFP_KERNEL);
 	if (err) {
 		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
 			err);
 		goto error_urb1;
 	}
-	err = usb_submit_urb(ucpia->sbuf[1].urb);
+	err = usb_submit_urb(ucpia->sbuf[1].urb, GFP_KERNEL);
 	if (err) {
 		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
 			err);
diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
--- a/drivers/mtd/mtdchar.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/mtd/mtdchar.c	Wed Feb  6 22:48:39 2002
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
+#include <linux/smp_lock.h>
 #include <linux/slab.h>
 
 #ifdef CONFIG_DEVFS_FS
@@ -31,6 +32,7 @@
 {
 	struct mtd_info *mtd=(struct mtd_info *)file->private_data;
 
+	lock_kernel();
 	switch (orig) {
 	case 0:
 		/* SEEK_SET */
@@ -45,6 +47,7 @@
 		file->f_pos =mtd->size + offset;
 		break;
 	default:
+		unlock_kernel();
 		return -EINVAL;
 	}
 
@@ -53,6 +56,7 @@
 	else if (file->f_pos >= mtd->size)
 		file->f_pos = mtd->size - 1;
 
+	unlock_kernel();
 	return file->f_pos;
 }
 
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Wed Feb  6 22:48:38 2002
+++ b/drivers/net/Config.in	Wed Feb  6 22:48:38 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/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/net/irda/irda-usb.c	Wed Feb  6 22:48:39 2002
@@ -278,7 +278,7 @@
 	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
 	urb->timeout = MSECS_TO_JIFFIES(100);
 
-	if ((ret = usb_submit_urb(urb))) {
+	if ((ret = usb_submit_urb(urb, GFP_KERNEL))) {
 		WARNING(__FUNCTION__ "(), failed Speed URB\n");
 	}
 	spin_unlock_irqrestore(&self->lock, flags);
@@ -451,7 +451,7 @@
 	}
 	
 	/* Ask USB to send the packet */
-	if ((res = usb_submit_urb(urb))) {
+	if ((res = usb_submit_urb(urb, GFP_KERNEL))) {
 		WARNING(__FUNCTION__ "(), failed Tx URB\n");
 		self->stats.tx_errors++;
 		/* Let USB recover : We will catch that in the watchdog */
@@ -730,7 +730,7 @@
 	urb->status = 0;
 	urb->next = NULL;	/* Don't auto resubmit URBs */
 	
-	ret = usb_submit_urb(urb);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
diff -Nru a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c
--- a/drivers/net/wan/comx.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/net/wan/comx.c	Wed Feb  6 22:48:39 2002
@@ -876,7 +876,7 @@
 
 static int comx_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	struct proc_dir_entry *entry = dentry->d_inode->u.generic_ip;
+	struct proc_dir_entry *entry = PDE(dentry->d_inode);
 	struct net_device *dev = entry->data;
 	struct comx_channel *ch = dev->priv;
 	int ret;
@@ -928,7 +928,7 @@
 	struct proc_dir_entry *de;
 	struct inode *inode = NULL;
 
-	if ((de = (struct proc_dir_entry *) dir->u.generic_ip) != NULL) {
+	if ((de = PDE(dir)) != NULL) {
 		for (de = de->subdir ; de ; de = de->next) {
 			if ((de && de->low_ino) && 
 			    (de->namelen == dentry->d_name.len) &&
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/net/wireless/airo.c	Wed Feb  6 22:48:38 2002
@@ -2280,7 +2280,7 @@
 
 static int proc_status_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
 	CapabilityRid cap_rid;
@@ -2289,8 +2289,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2364,7 +2362,7 @@
 				struct file *file,
 				u16 rid ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
 	StatsRid stats;
@@ -2372,9 +2370,6 @@
 	int *vals = stats.vals;
 	MOD_INC_USE_COUNT;
 
-
-	dp = inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2433,7 +2428,7 @@
 
 static void proc_config_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	ConfigRid config;
@@ -2442,7 +2437,6 @@
 	int need_reset = 0;
 
 	if ( !data->writelen ) return;
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 
 	disable_MAC(ai);
 	readConfigRid(ai, &config);
@@ -2629,7 +2623,7 @@
 
 static int proc_config_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	ConfigRid config;
@@ -2637,8 +2631,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2723,7 +2715,7 @@
 
 static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = (struct proc_data *)file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	SsidRid SSID_rid;
@@ -2759,7 +2751,7 @@
 
 static void proc_APList_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = (struct proc_data *)file->private_data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	APListRid APList_rid;
@@ -2852,7 +2844,7 @@
 
 static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	int i;
@@ -2862,7 +2854,6 @@
 
 	memset(key, 0, sizeof(key));
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 	data = (struct proc_data *)file->private_data;
 	if ( !data->writelen ) return;
 
@@ -2894,7 +2885,7 @@
 
 static int proc_wepkey_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	char *ptr;
@@ -2905,8 +2896,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2948,7 +2937,7 @@
 
 static int proc_SSID_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	int i;
@@ -2957,8 +2946,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2996,7 +2983,7 @@
 
 static int proc_APList_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	int i;
@@ -3005,8 +2992,6 @@
 
 	MOD_INC_USE_COUNT;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 	memset(file->private_data, 0, sizeof(struct proc_data));
@@ -3048,7 +3033,7 @@
 
 static int proc_BSSList_open( struct inode *inode, struct file *file ) {
 	struct proc_data *data;
-	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	char *ptr;
@@ -3058,8 +3043,6 @@
 	int doLoseSync = -1;
 
 	MOD_INC_USE_COUNT;
-
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 
 	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
diff -Nru a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
--- a/drivers/parport/ChangeLog	Wed Feb  6 22:48:39 2002
+++ b/drivers/parport/ChangeLog	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/parport/daisy.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/parport/parport_pc.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/parport/share.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/pci/pci.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/pci/proc.c	Wed Feb  6 22:48:38 2002
@@ -12,6 +12,7 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -21,8 +22,9 @@
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
-	loff_t new;
+	loff_t new = -1;
 
+	lock_kernel();
 	switch (whence) {
 	case 0:
 		new = off;
@@ -33,9 +35,8 @@
 	case 2:
 		new = PCI_CFG_SPACE_SIZE + off;
 		break;
-	default:
-		return -EINVAL;
 	}
+	unlock_kernel();
 	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
 		return -EINVAL;
 	return (file->f_pos = new);
@@ -45,7 +46,7 @@
 proc_bus_pci_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
 	const struct inode *ino = file->f_dentry->d_inode;
-	const struct proc_dir_entry *dp = ino->u.generic_ip;
+	const struct proc_dir_entry *dp = PDE(ino);
 	struct pci_dev *dev = dp->data;
 	unsigned int pos = *ppos;
 	unsigned int cnt, size;
@@ -127,7 +128,7 @@
 proc_bus_pci_write(struct file *file, const char *buf, size_t nbytes, loff_t *ppos)
 {
 	const struct inode *ino = file->f_dentry->d_inode;
-	const struct proc_dir_entry *dp = ino->u.generic_ip;
+	const struct proc_dir_entry *dp = PDE(ino);
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
 	int cnt;
@@ -199,7 +200,7 @@
 
 static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	const struct proc_dir_entry *dp = PDE(inode);
 	struct pci_dev *dev = dp->data;
 #ifdef HAVE_PCI_MMAP
 	struct pci_filp_private *fpriv = file->private_data;
@@ -241,7 +242,7 @@
 static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	const struct proc_dir_entry *dp = PDE(inode);
 	struct pci_dev *dev = dp->data;
 	struct pci_filp_private *fpriv = file->private_data;
 	int ret;
@@ -371,6 +372,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 +432,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/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c
--- a/drivers/pnp/isapnp_proc.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/pnp/isapnp_proc.c	Wed Feb  6 22:48:39 2002
@@ -84,18 +84,26 @@
 
 static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
 {
+	loff_t ret;
+
+	lock_kernel();
+
 	switch (orig) {
 	case 0:	/* SEEK_SET */
 		file->f_pos = offset;
-		return file->f_pos;
+		ret = file->f_pos;
+		break;
 	case 1:	/* SEEK_CUR */
 		file->f_pos += offset;
-		return file->f_pos;
+		ret = file->f_pos;
+		break;
 	case 2:	/* SEEK_END */
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-	return -ENXIO;
+
+	unlock_kernel();
+	return ret;
 }
 
 static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
@@ -211,8 +219,9 @@
 
 static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
 {
-	loff_t new;
-	
+	loff_t new = -1;
+
+	lock_kernel();
 	switch (whence) {
 	case 0:
 		new = off;
@@ -223,18 +232,19 @@
 	case 2:
 		new = 256 + off;
 		break;
-	default:
-		return -EINVAL;
 	}
-	if (new < 0 || new > 256)
+	if (new < 0 || new > 256) {
+		unlock_kernel();
 		return -EINVAL;
+	}
+	unlock_kernel();
 	return (file->f_pos = new);
 }
 
 static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
 	struct inode *ino = file->f_dentry->d_inode;
-	struct proc_dir_entry *dp = ino->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(ino);
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
 	int cnt, size = 256;
diff -Nru a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
--- a/drivers/sbus/char/flash.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/sbus/char/flash.c	Wed Feb  6 22:48:38 2002
@@ -83,6 +83,7 @@
 static long long
 flash_llseek(struct file *file, long long offset, int origin)
 {
+	lock_kernel();
 	switch (origin) {
 		case 0:
 			file->f_pos = offset;
@@ -96,8 +97,10 @@
 			file->f_pos = flash.read_size;
 			break;
 		default:
+			unlock_kernel();
 			return -EINVAL;
 	}
+	unlock_kernel();
 	return file->f_pos;
 }
 
diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
--- a/drivers/sbus/char/jsflash.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/sbus/char/jsflash.c	Wed Feb  6 22:48:39 2002
@@ -259,16 +259,23 @@
  */
 static loff_t jsf_lseek(struct file * file, loff_t offset, int orig)
 {
+	loff_t ret;
+
+	lock_kernel();
 	switch (orig) {
 		case 0:
 			file->f_pos = offset;
-			return file->f_pos;
+			ret = file->f_pos;
+			break;
 		case 1:
 			file->f_pos += offset;
-			return file->f_pos;
+			ret = file->f_pos;
+			break;
 		default:
-			return -EINVAL;
+			ret = -EINVAL;
 	}
+	unlock_kernel();
+	return ret;
 }
 
 /*
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/scsi/esp.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/scsi/megaraid.h	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/scsi/osst.c	Wed Feb  6 22:48:39 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/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/scsi/scsi.c	Wed Feb  6 22:48:39 2002
@@ -87,13 +87,16 @@
 
 struct scsi_host_sg_pool {
 	int size;
+	char *name; 
 	kmem_cache_t *slab;
 	mempool_t *pool;
 };
 
-static const int scsi_host_sg_pool_sizes[SG_MEMPOOL_NR] = { 8, 16, 32, 64, MAX_PHYS_SEGMENTS };
-struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR];
-
+#define SP(x) { x, "sgpool-" #x } 
+struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = { 
+	SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS)
+}; 	
+#undef SP 	
 /*
    static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
  */
@@ -2489,7 +2492,6 @@
 static int __init init_scsi(void)
 {
 	struct proc_dir_entry *generic;
-	char name[16];
 	int i;
 
 	printk(KERN_INFO "SCSI subsystem driver " REVISION "\n");
@@ -2499,18 +2501,15 @@
 	 */
 	for (i = 0; i < SG_MEMPOOL_NR; i++) {
 		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
-		int size = scsi_host_sg_pool_sizes[i] * sizeof(struct scatterlist);
+		int size = sgp->size * sizeof(struct scatterlist);
 
-		snprintf(name, sizeof(name) - 1, "sgpool-%d", scsi_host_sg_pool_sizes[i]);
-		sgp->slab = kmem_cache_create(name, size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+		sgp->slab = kmem_cache_create(sgp->name, size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
 		if (!sgp->slab)
 			panic("SCSI: can't init sg slab\n");
 
 		sgp->pool = mempool_create(SG_MEMPOOL_SIZE, scsi_pool_alloc, scsi_pool_free, sgp->slab);
 		if (!sgp->pool)
 			panic("SCSI: can't init sg mempool\n");
-
-		sgp->size = size;
 	}
 
 	/*
diff -Nru a/drivers/sound/Config.in b/drivers/sound/Config.in
--- a/drivers/sound/Config.in	Wed Feb  6 22:48:38 2002
+++ b/drivers/sound/Config.in	Wed Feb  6 22:48:38 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/sound/ite8172.c b/drivers/sound/ite8172.c
--- a/drivers/sound/ite8172.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/sound/ite8172.c	Wed Feb  6 22:48:39 2002
@@ -824,12 +824,6 @@
 
 /* --------------------------------------------------------------------- */
 
-static loff_t it8172_llseek(struct file *file, loff_t offset, int origin)
-{
-    return -ESPIPE;
-}
-
-
 static int it8172_open_mixdev(struct inode *inode, struct file *file)
 {
     int minor = MINOR(inode->i_rdev);
@@ -870,7 +864,7 @@
 
 static /*const*/ struct file_operations it8172_mixer_fops = {
     owner:	THIS_MODULE,
-    llseek:	it8172_llseek,
+    llseek:	no_llseek,
     ioctl:	it8172_ioctl_mixdev,
     open:	it8172_open_mixdev,
     release:	it8172_release_mixdev,
@@ -1633,7 +1627,7 @@
 
 static /*const*/ struct file_operations it8172_audio_fops = {
     owner:	THIS_MODULE,
-    llseek:	it8172_llseek,
+    llseek:	no_llseek,
     read:	it8172_read,
     write:	it8172_write,
     poll:	it8172_poll,
diff -Nru a/drivers/sound/nec_vrc5477.c b/drivers/sound/nec_vrc5477.c
--- a/drivers/sound/nec_vrc5477.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/sound/nec_vrc5477.c	Wed Feb  6 22:48:39 2002
@@ -805,12 +805,6 @@
 
 /* --------------------------------------------------------------------- */
 
-static loff_t vrc5477_ac97_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-
 static int vrc5477_ac97_open_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
@@ -852,7 +846,7 @@
 
 static /*const*/ struct file_operations vrc5477_ac97_mixer_fops = {
 	owner:		THIS_MODULE,
-	llseek:		vrc5477_ac97_llseek,
+	llseek:		no_llseek,
 	ioctl:		vrc5477_ac97_ioctl_mixdev,
 	open:		vrc5477_ac97_open_mixdev,
 	release:	vrc5477_ac97_release_mixdev,
@@ -1618,7 +1612,7 @@
 
 static /*const*/ struct file_operations vrc5477_ac97_audio_fops = {
 	owner:	THIS_MODULE,
-	llseek:		vrc5477_ac97_llseek,
+	llseek:		no_llseek,
 	read:		vrc5477_ac97_read,
 	write:		vrc5477_ac97_write,
 	poll:		vrc5477_ac97_poll,
diff -Nru a/drivers/usb/CDCEther.c b/drivers/usb/CDCEther.c
--- a/drivers/usb/CDCEther.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/CDCEther.c	Wed Feb  6 22:48:38 2002
@@ -132,7 +132,7 @@
 			
 	// Give this to the USB subsystem so it can tell us 
 	// when more data arrives.
-	if ( (res = usb_submit_urb(ether_dev->rx_urb)) ) {
+	if ( (res = usb_submit_urb(ether_dev->rx_urb, GFP_KERNEL)) ) {
 		warn( __FUNCTION__ " failed submint rx_urb %d", res);
 	}
 	
@@ -302,7 +302,7 @@
 	ether_dev->tx_urb->transfer_buffer_length = count;
 	
 	// Send the URB on its merry way.
-	if ((res = usb_submit_urb(ether_dev->tx_urb)))  {
+	if ((res = usb_submit_urb(ether_dev->tx_urb, GFP_KERNEL)))  {
 		// Hmm...  It didn't go. Tell someone...
 		warn("failed tx_urb %d", res);
 		// update some stats...
@@ -350,7 +350,7 @@
 			read_bulk_callback, ether_dev );
 
 	// Put it out there so the device can send us stuff
-	if ( (res = usb_submit_urb(ether_dev->rx_urb)) )
+	if ( (res = usb_submit_urb(ether_dev->rx_urb, GFP_KERNEL)) )
 	{
 		// Hmm...  Okay...
 		warn( __FUNCTION__ " failed rx_urb %d", res );
diff -Nru a/drivers/usb/Config.help b/drivers/usb/Config.help
--- a/drivers/usb/Config.help	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/Config.help	Wed Feb  6 22:48:39 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/acm.c b/drivers/usb/acm.c
--- a/drivers/usb/acm.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/acm.c	Wed Feb  6 22:48:38 2002
@@ -261,7 +261,7 @@
 	urb->actual_length = 0;
 	urb->dev = acm->dev;
 
-	if (usb_submit_urb(urb))
+	if (usb_submit_urb(urb, GFP_KERNEL))
 		dbg("failed resubmitting read urb");
 }
 
@@ -316,11 +316,11 @@
         unlock_kernel();
 
 	acm->ctrlurb.dev = acm->dev;
-	if (usb_submit_urb(&acm->ctrlurb))
+	if (usb_submit_urb(&acm->ctrlurb, GFP_KERNEL))
 		dbg("usb_submit_urb(ctrl irq) failed");
 
 	acm->readurb.dev = acm->dev;
-	if (usb_submit_urb(&acm->readurb))
+	if (usb_submit_urb(&acm->readurb, GFP_KERNEL))
 		dbg("usb_submit_urb(read bulk) failed");
 
 	acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
@@ -371,7 +371,7 @@
 	acm->writeurb.transfer_buffer_length = count;
 	acm->writeurb.dev = acm->dev;
 
-	if (usb_submit_urb(&acm->writeurb))
+	if (usb_submit_urb(&acm->writeurb, GFP_KERNEL))
 		dbg("usb_submit_urb(write bulk) failed");
 
 	return count;
diff -Nru a/drivers/usb/audio.c b/drivers/usb/audio.c
--- a/drivers/usb/audio.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/audio.c	Wed Feb  6 22:48:39 2002
@@ -917,7 +917,7 @@
 	if (!usbin_retire_desc(u, urb) &&
 	    u->flags & FLG_RUNNING &&
 	    !usbin_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb)) == 0) {
+	    (suret = usb_submit_urb(urb, GFP_KERNEL)) == 0) {
 		u->flags |= mask;
 	} else {
 		u->flags &= ~(mask | FLG_RUNNING);
@@ -982,7 +982,7 @@
 	if (!usbin_sync_retire_desc(u, urb) &&
 	    u->flags & FLG_RUNNING &&
 	    !usbin_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb)) == 0) {
+	    (suret = usb_submit_urb(urb, GFP_KERNEL)) == 0) {
 		u->flags |= mask;
 	} else {
 		u->flags &= ~(mask | FLG_RUNNING);
@@ -1055,7 +1055,7 @@
 		urb->number_of_packets = DESCFRAMES;
 		urb->context = as;
 		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb))
+		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 			u->flags |= FLG_URB0RUNNING;
 		else
 			u->flags &= ~FLG_RUNNING;
@@ -1068,7 +1068,7 @@
 		urb->number_of_packets = DESCFRAMES;
 		urb->context = as;
 		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb))
+		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 			u->flags |= FLG_URB1RUNNING;
 		else
 			u->flags &= ~FLG_RUNNING;
@@ -1083,7 +1083,7 @@
 			urb->context = as;
 			urb->complete = usbin_sync_completed;
 			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 				u->flags |= FLG_SYNC0RUNNING;
 			else
 				u->flags &= ~FLG_RUNNING;
@@ -1097,7 +1097,7 @@
 			urb->context = as;
 			urb->complete = usbin_sync_completed;
 			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 				u->flags |= FLG_SYNC1RUNNING;
 			else
 				u->flags &= ~FLG_RUNNING;
@@ -1275,7 +1275,7 @@
 	if (!usbout_retire_desc(u, urb) &&
 	    u->flags & FLG_RUNNING &&
 	    !usbout_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb)) == 0) {
+	    (suret = usb_submit_urb(urb, GFP_KERNEL)) == 0) {
 		u->flags |= mask;
 	} else {
 		u->flags &= ~(mask | FLG_RUNNING);
@@ -1347,7 +1347,7 @@
 	if (!usbout_sync_retire_desc(u, urb) &&
 	    u->flags & FLG_RUNNING &&
 	    !usbout_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb)) == 0) {
+	    (suret = usb_submit_urb(urb, GFP_KERNEL)) == 0) {
 		u->flags |= mask;
 	} else {
 		u->flags &= ~(mask | FLG_RUNNING);
@@ -1420,7 +1420,7 @@
 		urb->number_of_packets = DESCFRAMES;
 		urb->context = as;
 		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb))
+		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 			u->flags |= FLG_URB0RUNNING;
 		else
 			u->flags &= ~FLG_RUNNING;
@@ -1433,7 +1433,7 @@
 		urb->number_of_packets = DESCFRAMES;
 		urb->context = as;
 		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb))
+		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 			u->flags |= FLG_URB1RUNNING;
 		else
 			u->flags &= ~FLG_RUNNING;
@@ -1448,7 +1448,7 @@
 			urb->context = as;
 			urb->complete = usbout_sync_completed;
 			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 				u->flags |= FLG_SYNC0RUNNING;
 			else
 				u->flags &= ~FLG_RUNNING;
@@ -1462,7 +1462,7 @@
 			urb->context = as;
 			urb->complete = usbout_sync_completed;
 			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
 				u->flags |= FLG_SYNC1RUNNING;
 			else
 				u->flags &= ~FLG_RUNNING;
diff -Nru a/drivers/usb/auerswald.c b/drivers/usb/auerswald.c
--- a/drivers/usb/auerswald.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/auerswald.c	Wed Feb  6 22:48:39 2002
@@ -49,7 +49,7 @@
 
 /*-------------------------------------------------------------------*/
 /* Version Information */
-#define DRIVER_VERSION "0.9.9"
+#define DRIVER_VERSION "0.9.11"
 #define DRIVER_AUTHOR  "Wolfgang Mües <wmues@nexgo.de>"
 #define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
 
@@ -191,6 +191,13 @@
         struct list_head free_list;     /* list of available elements */
 } auerchain_t,*pauerchain_t;
 
+/* urb blocking completion helper struct */
+typedef struct
+{
+	wait_queue_head_t wqh;    	/* wait for completion */
+	unsigned int done;		/* completion flag */
+} auerchain_chs_t,*pauerchain_chs_t;
+
 /* ...................................................................*/
 /* buffer element */
 struct  auerbufctl;                     /* forward */
@@ -330,7 +337,7 @@
                 urb    = acep->urbp;
                 dbg ("auerchain_complete: submitting next urb from chain");
 		urb->status = 0;	/* needed! */
-		result = usb_submit_urb( urb);
+		result = usb_submit_urb(urb, GFP_KERNEL);
 
                 /* check for submit errors */
                 if (result) {
@@ -408,7 +415,7 @@
         if (acep) {
                 dbg("submitting urb immediate");
 		urb->status = 0;	/* needed! */
-                result = usb_submit_urb( urb);
+                result = usb_submit_urb(urb, GFP_KERNEL);
                 /* check for submit errors */
                 if (result) {
                         urb->status = result;
@@ -600,8 +607,10 @@
 /* completion handler for synchronous chained URBs */
 static void auerchain_blocking_completion (struct urb *urb)
 {
-	wait_queue_head_t *wakeup = (wait_queue_head_t *)urb->context;
-	wake_up (wakeup);
+	pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
+	pchs->done = 1;
+	wmb();
+	wake_up (&pchs->wqh);
 }
 
 
@@ -609,36 +618,43 @@
 static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
 {
 	DECLARE_WAITQUEUE (wait, current);
-	DECLARE_WAIT_QUEUE_HEAD (wqh);
+	auerchain_chs_t chs;
 	int status;
 
 	dbg ("auerchain_start_wait_urb called");
-	init_waitqueue_head (&wqh);
-	current->state = TASK_INTERRUPTIBLE;
-	add_wait_queue (&wqh, &wait);
-	urb->context = &wqh;
-	status = auerchain_submit_urb ( acp, urb);
+	init_waitqueue_head (&chs.wqh);
+	chs.done = 0;
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	add_wait_queue (&chs.wqh, &wait);
+	urb->context = &chs;
+	status = auerchain_submit_urb (acp, urb);
 	if (status) {
 		/* something went wrong */
-		current->state = TASK_RUNNING;
-		remove_wait_queue (&wqh, &wait);
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&chs.wqh, &wait);
 		return status;
 	}
 
-	if (urb->status == -EINPROGRESS) {
-		while (timeout && urb->status == -EINPROGRESS)
-			status = timeout = schedule_timeout (timeout);
-	} else
-		status = 1;
-
-	current->state = TASK_RUNNING;
-	remove_wait_queue (&wqh, &wait);
+	while (timeout && !chs.done)
+	{
+		timeout = schedule_timeout (timeout);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		rmb();
+	}
 
-	if (!status) {
-		/* timeout */
-		dbg ("auerchain_start_wait_urb: timeout");
-		auerchain_unlink_urb (acp, urb);  /* remove urb safely */
-		status = -ETIMEDOUT;
+	set_current_state (TASK_RUNNING);
+	remove_wait_queue (&chs.wqh, &wait);
+
+	if (!timeout && !chs.done) {
+		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
+			dbg ("auerchain_start_wait_urb: raced timeout");
+			status = urb->status;
+		} else {
+			dbg ("auerchain_start_wait_urb: timeout");
+			auerchain_unlink_urb (acp, urb);  /* remove urb safely */
+			status = -ETIMEDOUT;
+		}
 	} else
 		status = urb->status;
 
@@ -932,6 +948,8 @@
 			/* reuse the buffer */
 			err ("control read: transmission error %d, can not retry", urb->status);
 			auerbuf_releasebuf (bp);
+			/* Wake up all processes waiting for a buffer */
+			wake_up (&cp->bufferwait);
 			return;
 		}
 		bp->retries++;
@@ -1128,7 +1146,7 @@
         FILL_INT_URB (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->bInterval);
         /* start the urb */
 	cp->inturbp->status = 0;	/* needed! */
-	ret = usb_submit_urb (cp->inturbp);
+	ret = usb_submit_urb (cp->inturbp, GFP_KERNEL);
 
 intoend:
         if (ret < 0) {
@@ -1376,9 +1394,6 @@
 	}
 	up (&dev_table_mutex);
 
-	/* prevent module unloading */
-	MOD_INC_USE_COUNT;
-
 	/* we have access to the device. Now lets allocate memory */
 	ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
 	if (ccp == NULL) {
@@ -1415,7 +1430,6 @@
 	/* Error exit */
 ofail:	up (&cp->mutex);
 	auerchar_delete (ccp);
-  	MOD_DEC_USE_COUNT;
 	return ret;
 }
 
@@ -1553,21 +1567,14 @@
 	return ret;
 }
 
-
-/* Seek is not supported */
-static loff_t auerchar_llseek (struct file *file, loff_t offset, int origin)
-{
-        dbg ("auerchar_seek");
-        return -ESPIPE;
-}
-
-
 /* Read data from the device */
 static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos)
 {
         unsigned long flags;
 	pauerchar_t ccp = (pauerchar_t) file->private_data;
         pauerbuf_t   bp = NULL;
+	wait_queue_t wait;
+
         dbg ("auerchar_read");
 
 	/* Error checking */
@@ -1630,6 +1637,11 @@
 
 	/* a read buffer is not available. Try to get the next data block. */
 doreadlist:
+	/* Preparing for sleep */
+	init_waitqueue_entry (&wait, current);
+	set_current_state (TASK_INTERRUPTIBLE);
+	add_wait_queue (&ccp->readwait, &wait);
+
 	bp = NULL;
 	spin_lock_irqsave (&ccp->bufctl.lock, flags);
         if (!list_empty (&ccp->bufctl.rec_buff_list)) {
@@ -1644,20 +1656,25 @@
 	if (bp) {
 		ccp->readbuf = bp;
 		ccp->readoffset = AUH_SIZE; /* for headerbyte */
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&ccp->readwait, &wait);
 		goto doreadbuf;		  /* now we can read! */
 	}
 
 	/* no data available. Should we wait? */
 	if (file->f_flags & O_NONBLOCK) {
                 dbg ("No read buffer available, returning -EAGAIN");
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&ccp->readwait, &wait);
 		up (&ccp->readmutex);
 		up (&ccp->mutex);
-                return -EAGAIN;  /* nonblocking, no data available */
+		return -EAGAIN;  /* nonblocking, no data available */
         }
 
 	/* yes, we should wait! */
 	up (&ccp->mutex); /* allow other operations while we wait */
-	interruptible_sleep_on (&ccp->readwait);
+	schedule();
+	remove_wait_queue (&ccp->readwait, &wait);
 	if (signal_pending (current)) {
 		/* waked up by a signal */
 		up (&ccp->readmutex);
@@ -1688,6 +1705,7 @@
         pauerbuf_t bp;
         unsigned long flags;
 	int ret;
+	wait_queue_t wait;
 
         dbg ("auerchar_write %d bytes", len);
 
@@ -1724,6 +1742,11 @@
 		up (&ccp->mutex);
 		return -EIO;
 	}
+	/* Prepare for sleep */
+	init_waitqueue_entry (&wait, current);
+	set_current_state (TASK_INTERRUPTIBLE);
+	add_wait_queue (&cp->bufferwait, &wait);
+
 	/* Try to get a buffer from the device pool.
 	   We can't use a buffer from ccp->bufctl because the write
 	   command will last beond a release() */
@@ -1744,16 +1767,22 @@
 
 		/* NONBLOCK: don't wait */
 		if (file->f_flags & O_NONBLOCK) {
+			set_current_state (TASK_RUNNING);
+			remove_wait_queue (&cp->bufferwait, &wait);
 			return -EAGAIN;
 		}
 
 		/* BLOCKING: wait */
-		interruptible_sleep_on (&cp->bufferwait);
+		schedule();
+		remove_wait_queue (&cp->bufferwait, &wait);
 		if (signal_pending (current)) {
 			/* waked up by a signal */
 			return -ERESTARTSYS;
 		}
 		goto write_again;
+	} else {
+		set_current_state (TASK_RUNNING);
+		remove_wait_queue (&cp->bufferwait, &wait);
 	}
 
 	/* protect against too big write requests */
@@ -1763,6 +1792,8 @@
 	if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) {
 		dbg ("copy_from_user failed");
 		auerbuf_releasebuf (bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up (&cp->bufferwait);
 		up (&cp->mutex);
 		up (&ccp->mutex);
 		return -EIO;
@@ -1787,6 +1818,8 @@
 	if (ret) {
 		dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
 		auerbuf_releasebuf (bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up (&cp->bufferwait);
 		up (&ccp->mutex);
 		return -EIO;
 	}
@@ -1831,9 +1864,6 @@
 	up (&ccp->mutex);
 	auerchar_delete (ccp);
 
-	/* release the module */
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1843,7 +1873,7 @@
 static struct file_operations auerswald_fops =
 {
 	owner:		THIS_MODULE,
-	llseek:		auerchar_llseek,
+	llseek:		no_llseek,
 	read:		auerchar_read,
 	write:          auerchar_write,
 	ioctl:		auerchar_ioctl,
@@ -2154,3 +2184,4 @@
 module_exit (auerswald_cleanup);
 
 /* --------------------------------------------------------------------- */
+
diff -Nru a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
--- a/drivers/usb/bluetooth.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/bluetooth.c	Wed Feb  6 22:48:39 2002
@@ -335,7 +335,7 @@
 			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
 
 	/* send it down the pipe */
-	status = usb_submit_urb(urb);
+	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status)
 		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
 	
@@ -390,7 +390,7 @@
 			       bluetooth->bulk_in_buffer,
 			       bluetooth->bulk_in_buffer_size,
 			       bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
 		if (result)
 			dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
 #endif
@@ -400,7 +400,7 @@
 			      bluetooth->interrupt_in_buffer_size,
 			      bluetooth_int_callback, bluetooth,
 			      bluetooth->interrupt_in_interval);
-		result = usb_submit_urb(bluetooth->interrupt_in_urb);
+		result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL);
 		if (result)
 			dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
 	}
@@ -540,7 +540,7 @@
 				urb->transfer_flags |= USB_QUEUE_BULK;
 
 				/* send it down the pipe */
-				retval = usb_submit_urb(urb);
+				retval = usb_submit_urb(urb, GFP_KERNEL);
 				if (retval) {
 					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval);
 					goto exit;
@@ -730,7 +730,7 @@
 			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
 			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
 			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
 		if (result)
 			err (__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
@@ -921,7 +921,7 @@
 			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
 			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
 			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
 		if (result)
 			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
@@ -982,7 +982,7 @@
 		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
 		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
 		      bluetooth_read_bulk_callback, bluetooth);
-	result = usb_submit_urb(bluetooth->read_urb);
+	result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
 	if (result)
 		err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
diff -Nru a/drivers/usb/catc.c b/drivers/usb/catc.c
--- a/drivers/usb/catc.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/catc.c	Wed Feb  6 22:48:39 2002
@@ -257,7 +257,7 @@
 
 	if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
 		catc->rx_urb->dev = catc->usbdev;
-		if ((status = usb_submit_urb(catc->rx_urb)) < 0) {
+		if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) {
 			err("submit(rx_urb) status %d", status);
 			return;
 		} 
@@ -286,7 +286,7 @@
 	catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
 	catc->tx_urb->dev = catc->usbdev;
 
-	if ((status = usb_submit_urb(catc->tx_urb)) < 0)
+	if ((status = usb_submit_urb(catc->tx_urb, GFP_KERNEL)) < 0)
 		err("submit(tx_urb), status %d", status);
 
 	catc->tx_idx = !catc->tx_idx;
@@ -402,7 +402,7 @@
 	if (!q->dir && q->buf && q->len)
 		memcpy(catc->ctrl_buf, q->buf, q->len);
 
-	if ((status = usb_submit_urb(catc->ctrl_urb)))
+	if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL)))
 		err("submit(ctrl_urb) status %d", status);
 }
 
@@ -625,7 +625,7 @@
 	int status;
 
 	catc->irq_urb->dev = catc->usbdev;
-	if ((status = usb_submit_urb(catc->irq_urb)) < 0) {
+	if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
 		err("submit(irq_urb) status %d", status);
 		return -1;
 	}
diff -Nru a/drivers/usb/dabusb.c b/drivers/usb/dabusb.c
--- a/drivers/usb/dabusb.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/dabusb.c	Wed Feb  6 22:48:38 2002
@@ -458,7 +458,7 @@
 
 			end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
 
-			ret = usb_submit_urb (end->purb);
+			ret = usb_submit_urb (end->purb, GFP_KERNEL);
 			if (ret) {
 				err("usb_submit_urb returned:%d", ret);
 				if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
diff -Nru a/drivers/usb/devices.c b/drivers/usb/devices.c
--- a/drivers/usb/devices.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/devices.c	Wed Feb  6 22:48:39 2002
@@ -554,21 +554,26 @@
 
 static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
 {
+	loff_t ret;
+
+	lock_kernel();
+
 	switch (orig) {
 	case 0:
 		file->f_pos = offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 1:
 		file->f_pos += offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 2:
-		return -EINVAL;
-
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+
+	unlock_kernel();
+	return ret;
 }
 
 struct file_operations usbdevfs_devices_fops = {
diff -Nru a/drivers/usb/devio.c b/drivers/usb/devio.c
--- a/drivers/usb/devio.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/devio.c	Wed Feb  6 22:48:39 2002
@@ -58,21 +58,26 @@
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
+	loff_t ret;
+
+	lock_kernel();
+
 	switch (orig) {
 	case 0:
 		file->f_pos = offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 1:
 		file->f_pos += offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 2:
-		return -EINVAL;
-
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+
+	unlock_kernel();
+	return ret;
 }
 
 static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos)
@@ -364,7 +369,7 @@
 	if (test_bit(intf, &ps->ifclaimed))
 		return 0;
 	/* if not yet claimed, claim it for the driver */
-	printk(KERN_WARNING "usbdevfs: process %d (%s) did not claim interface %u before use\n",
+	printk(KERN_WARNING "usbfs: process %d (%s) did not claim interface %u before use\n",
 	       current->pid, current->comm, intf);
 	return claimintf(ps, intf);
 }
@@ -563,7 +568,7 @@
 	}
 	free_page((unsigned long)tbuf);
 	if (i<0) {
-		printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", 
+		printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", 
 		       dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
 	}
 	return i;
@@ -619,7 +624,7 @@
 	}
 	free_page((unsigned long)tbuf);
 	if (i < 0) {
-		printk(KERN_WARNING "usbdevfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
+		printk(KERN_WARNING "usbfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
 		       dev->devnum, bulk.ep, bulk.len, i);
 		return i;
 	}
@@ -906,8 +911,8 @@
 		}
 	}
         async_newpending(as);
-        if ((ret = usb_submit_urb(as->urb))) {
-		printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
+        if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
+		printk(KERN_DEBUG "usbfs: usb_submit_urb returned %d\n", ret);
                 async_removepending(as);
                 free_async(as);
                 return ret;
diff -Nru a/drivers/usb/drivers.c b/drivers/usb/drivers.c
--- a/drivers/usb/drivers.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/drivers.c	Wed Feb  6 22:48:38 2002
@@ -38,6 +38,7 @@
 #include <linux/mm.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 /*****************************************************************/
@@ -96,21 +97,24 @@
 
 static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig)
 {
+	loff_t ret;
+
+	lock_kernel();
 	switch (orig) {
 	case 0:
 		file->f_pos = offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 1:
 		file->f_pos += offset;
-		return file->f_pos;
-
+		ret = file->f_pos;
+		break;
 	case 2:
-		return -EINVAL;
-
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+	unlock_kernel();
+	return ret;
 }
 
 struct file_operations usbdevfs_drivers_fops = {
diff -Nru a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
--- a/drivers/usb/hcd/ohci-dbg.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hcd/ohci-dbg.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/hcd/ohci-hcd.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hcd/ohci-hub.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/hcd/ohci-mem.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hcd/ohci-q.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hcd/ohci.h	Wed Feb  6 22:48:39 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/hcd.c b/drivers/usb/hcd.c
--- a/drivers/usb/hcd.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/hcd.c	Wed Feb  6 22:48:38 2002
@@ -916,14 +916,13 @@
 /* may be called in any context with a valid urb->dev usecount */
 /* caller surrenders "ownership" of urb (and chain at urb->next).  */
 
-static int hcd_submit_urb (struct urb *urb)
+static int hcd_submit_urb (struct urb *urb, int mem_flags)
 {
 	int			status;
 	struct usb_hcd		*hcd;
 	struct hcd_dev		*dev;
 	unsigned long		flags;
 	int			pipe;
-	int			mem_flags;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
@@ -947,11 +946,6 @@
 			usb_pipeout (pipe)))
 		return -EPIPE;
 
-	// FIXME paging/swapping requests over USB should not use GFP_KERNEL
-	// and might even need to use GFP_NOIO ... that flag actually needs
-	// to be passed from the higher level.
-	mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
-
 #ifdef DEBUG
 	{
 	unsigned int	orig_flags = urb->transfer_flags;
@@ -1316,7 +1310,7 @@
 	else if (urb->next) {
 		int 	status;
 
-		status = usb_submit_urb (urb->next);
+		status = usb_submit_urb (urb->next, GFP_ATOMIC);
 		if (status) {
 			dbg ("urb %p chain fail, %d", urb->next, status);
 			urb->next->status = -ENOTCONN;
diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c
--- a/drivers/usb/hid-core.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/hid-core.c	Wed Feb  6 22:48:38 2002
@@ -992,7 +992,7 @@
 	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
 	hid->urbout.dev = hid->dev;
 
-	if (usb_submit_urb(&hid->urbout)) {
+	if (usb_submit_urb(&hid->urbout, GFP_KERNEL)) {
 		err("usb_submit_urb(out) failed");
 		return -1;
 	}
@@ -1036,7 +1036,7 @@
 
 	hid->urb.dev = hid->dev;
 
-	if (usb_submit_urb(&hid->urb))
+	if (usb_submit_urb(&hid->urb, GFP_KERNEL))
 		return -EIO;
 
 	return 0;
diff -Nru a/drivers/usb/hpusbscsi.c b/drivers/usb/hpusbscsi.c
--- a/drivers/usb/hpusbscsi.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hpusbscsi.c	Wed Feb  6 22:48:39 2002
@@ -245,7 +245,7 @@
 			desc->interrupt_interval
 	);
 
-	if ( 0  >  usb_submit_urb(desc->controlurb)) {
+	if ( 0  >  usb_submit_urb(desc->controlurb, GFP_KERNEL)) {
 		kfree(sht->proc_name);
 		return 0;
 	}
@@ -321,7 +321,7 @@
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
 
-	res = usb_submit_urb(hpusbscsi->dataurb);
+	res = usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC);
 	if (unlikely(res)) {
 		hpusbscsi->state = HP_STATE_FREE;
 		TRACE_STATE;
@@ -460,7 +460,7 @@
                 hpusbscsi
         );
 
-        res = usb_submit_urb(u);
+        res = usb_submit_urb(u, GFP_ATOMIC);
         if (unlikely(res))
                 hpusbscsi->state = HP_STATE_ERROR;
 	TRACE_STATE;
@@ -509,7 +509,7 @@
 		hpusbscsi
 	);
 
-	res = usb_submit_urb(u);
+	res = usb_submit_urb(u, GFP_ATOMIC);
 	if (unlikely(res)) {
                 handle_usb_error(hpusbscsi);
 		return;
diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c
--- a/drivers/usb/hub.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/hub.c	Wed Feb  6 22:48:39 2002
@@ -312,7 +312,7 @@
 
 	FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
 		hub, endpoint->bInterval);
-	ret = usb_submit_urb(hub->urb);
+	ret = usb_submit_urb(hub->urb, GFP_KERNEL);
 	if (ret) {
 		err("usb_submit_urb failed (%d)", ret);
 		kfree(hub->descriptor);
@@ -498,7 +498,7 @@
 		return -1;
 
 	hub->urb->dev = dev;                                                    
-	if (usb_submit_urb(hub->urb))
+	if (usb_submit_urb(hub->urb, GFP_KERNEL))
 		return -1;
 
 	usb_hub_power_on(hub);
diff -Nru a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
--- a/drivers/usb/ibmcam.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/ibmcam.c	Wed Feb  6 22:48:39 2002
@@ -1,7 +1,8 @@
 /*
  * USB IBM C-It Video Camera driver
  *
- * Supports IBM C-It Video Camera.
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
  *
  * This driver is based on earlier work of:
  *
@@ -33,9 +34,11 @@
 
 #include "usbvideo.h"
 
-#define	IBMCAM_VENDOR_ID	0x0545
-#define	IBMCAM_PRODUCT_ID	0x8080
+#define IBMCAM_VENDOR_ID	0x0545
+#define IBMCAM_PRODUCT_ID	0x8080
 #define NETCAM_PRODUCT_ID	0x8002	/* IBM NetCamera, close to model 2 */
+#define VEO_800C_PRODUCT_ID	0x800C	/* Veo Stingray, repackaged Model 2 */
+#define VEO_800D_PRODUCT_ID	0x800D	/* Veo Stingray, repackaged Model 4 */
 
 #define MAX_IBMCAM		4	/* How many devices we allow to connect */
 #define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
@@ -3671,6 +3674,8 @@
 	if (dev->descriptor.idVendor != IBMCAM_VENDOR_ID)
 		return NULL;
 	if ((dev->descriptor.idProduct != IBMCAM_PRODUCT_ID) &&
+	    (dev->descriptor.idProduct != VEO_800C_PRODUCT_ID) &&
+	    (dev->descriptor.idProduct != VEO_800D_PRODUCT_ID) &&
 	    (dev->descriptor.idProduct != NETCAM_PRODUCT_ID))
 		return NULL;
 
@@ -3684,7 +3689,8 @@
 	case 0x030A:
 		if (ifnum != 0)
 			return NULL;
-		if (dev->descriptor.idProduct == NETCAM_PRODUCT_ID)
+		if ((dev->descriptor.idProduct == NETCAM_PRODUCT_ID) ||
+		    (dev->descriptor.idProduct == VEO_800D_PRODUCT_ID))
 			model = IBMCAM_MODEL_4;
 		else
 			model = IBMCAM_MODEL_2;
@@ -3699,8 +3705,28 @@
 			dev->descriptor.bcdDevice);
 		return NULL;
 	}
-	info("IBM USB camera found (model %d, rev. 0x%04x)",
-		model, dev->descriptor.bcdDevice);
+
+	/* Print detailed info on what we found so far */
+	do {
+		char *brand = NULL;
+		switch (dev->descriptor.idProduct) {
+		case NETCAM_PRODUCT_ID:
+			brand = "IBM NetCamera";
+			break;
+		case VEO_800C_PRODUCT_ID:
+			brand = "Veo Stingray [800C]";
+			break;
+		case VEO_800D_PRODUCT_ID:
+			brand = "Veo Stingray [800D]";
+			break;
+		case IBMCAM_PRODUCT_ID:
+		default:
+			brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
+			break;
+		}
+		info("%s USB camera found (model %d, rev. 0x%04x)",
+		     brand, model, dev->descriptor.bcdDevice);
+	} while (0);
 
 	/* Validate found interface: must have one ISO endpoint */
 	nas = dev->actconfig->interface[ifnum].num_altsetting;
@@ -3908,18 +3934,16 @@
 	usbvideo_Deregister(&cams);
 }
 
-#if defined(usb_device_id_ver)
-
 static __devinitdata struct usb_device_id id_table[] = {
 	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },	/* Model 1 */
 	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
 	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },	/* Model 3 */
 	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
 	{ }  /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
-
-#endif /* defined(usb_device_id_ver) */
 
 module_init(ibmcam_init);
 module_exit(ibmcam_cleanup);
diff -Nru a/drivers/usb/inode.c b/drivers/usb/inode.c
--- a/drivers/usb/inode.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/inode.c	Wed Feb  6 22:48:38 2002
@@ -36,7 +36,7 @@
 #include <linux/proc_fs.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
-
+#include <linux/smp_lock.h>
 
 static struct super_operations usbfs_ops;
 static struct address_space_operations usbfs_aops;
@@ -295,6 +295,7 @@
 {
 	loff_t retval = -EINVAL;
 
+	lock_kernel();
 	switch(orig) {
 	case 0:
 		if (offset > 0) {
@@ -311,6 +312,7 @@
 	default:
 		break;
 	}
+	unlock_kernel();
 	return retval;
 }
 
@@ -362,15 +364,14 @@
 	put_inode:	force_delete,
 };
 
-static struct super_block *usbfs_read_super (struct super_block *sb, void *data, 
-					     int silent)
+static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
 	struct dentry *root;
 
 	if (parse_options(sb, data)) {
 		warn("usbfs: mount parameter error:");
-		return NULL;
+		return -EINVAL;
 	}
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -381,17 +382,17 @@
 
 	if (!inode) {
 		dbg("%s: could not get inode!\n",__FUNCTION__);
-		return NULL;
+		return -ENOMEM;
 	}
 
 	root = d_alloc_root(inode);
 	if (!root) {
 		dbg("%s: could not get root dentry!\n",__FUNCTION__);
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root = root;
-	return sb;
+	return 0;
 }
 
 /**
@@ -520,8 +521,24 @@
  * It will be removed when the 2.7.x development cycle is started.
  * You have been warned :)
  */
-static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE);
-static DECLARE_FSTYPE(usb_fs_type,       "usbfs",    usbfs_read_super, FS_SINGLE);
+
+static struct super_block *usb_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, usb_fill_super);
+}
+
+static struct file_system_type usbdevice_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"usbdevfs",
+	get_sb:		usb_get_sb,
+};
+
+static struct file_system_type usb_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"usbfs",
+	get_sb:		usb_get_sb,
+};
 
 /* --------------------------------------------------------------------- */
 static int get_mount (void)
diff -Nru a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
--- a/drivers/usb/kaweth.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/kaweth.c	Wed Feb  6 22:48:39 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");
@@ -447,7 +447,8 @@
 /****************************************************************
  *     kaweth_resubmit_rx_urb
  ****************************************************************/
-static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
+static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
+						int mem_flags)
 {
 	int result;
 
@@ -461,7 +462,7 @@
 		      kaweth_usb_receive,
 		      kaweth);
 
-	if((result = usb_submit_urb(kaweth->rx_urb))) {
+	if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) {
 		kaweth_err("resubmitting rx_urb %d failed", result);
 	}
 }
@@ -493,7 +494,7 @@
 			   urb->status,
 			   count, 
 			   (int)pkt_len);
-		kaweth_resubmit_rx_urb(kaweth);
+		kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                 return;
 	}
 
@@ -502,12 +503,12 @@
 			kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
 			kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
 			kaweth_err("Count 2: %x", count2);
-		        kaweth_resubmit_rx_urb(kaweth);
+		        kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                         return;
                 }
 		
 		if(!(skb = dev_alloc_skb(pkt_len+2))) {
-		        kaweth_resubmit_rx_urb(kaweth);
+		        kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                         return;
 		}
 
@@ -525,7 +526,7 @@
 		kaweth->stats.rx_bytes += pkt_len;
 	}
 
-	kaweth_resubmit_rx_urb(kaweth);
+	kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
 }
 
 /****************************************************************
@@ -539,11 +540,11 @@
 
 	kaweth_dbg("Opening network device.");
 
-	kaweth_resubmit_rx_urb(kaweth);
+	MOD_INC_USE_COUNT;
 
-	netif_start_queue(net);
+	kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
 
-	MOD_INC_USE_COUNT;
+	netif_start_queue(net);
 
 	kaweth_async_set_rx_mode(kaweth);
 	return 0;
@@ -586,14 +587,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);
 }
 
 /****************************************************************
@@ -625,7 +622,7 @@
 		      kaweth_usb_transmit_complete,
 		      kaweth);
 
-	if((res = usb_submit_urb(kaweth->tx_urb)))
+	if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
 	{
 		kaweth_warn("kaweth failed tx_urb %d", res);
 		kaweth->stats.tx_errors++;
@@ -757,9 +754,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 +819,7 @@
 
 		/* Device will now disappear for a moment...  */
 		kaweth_info("Firmware loaded.  I'll be back...");
+		kfree(kaweth);
 		return NULL;
 	}
 
@@ -925,6 +921,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) {
@@ -978,7 +976,7 @@
         set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&awd.wqh, &wait);
         urb->context = &awd;
-        status = usb_submit_urb(urb);
+        status = usb_submit_urb(urb, GFP_KERNEL);
         if (status) {
                 // something went wrong
                 usb_free_urb(urb);
diff -Nru a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
--- a/drivers/usb/mdc800.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/mdc800.c	Wed Feb  6 22:48:38 2002
@@ -605,7 +605,7 @@
 
 	retval=0;
 	mdc800->irq_urb->dev = mdc800->dev;
-	if (usb_submit_urb (mdc800->irq_urb))
+	if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
 	{
 		err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
 		errn = -EIO;
@@ -694,7 +694,7 @@
 
 				/* Download -> Request new bytes */
 				mdc800->download_urb->dev = mdc800->dev;
-				if (usb_submit_urb (mdc800->download_urb))
+				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
 				{
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
 					up (&mdc800->io_lock);
@@ -808,7 +808,7 @@
 			mdc800->state=WORKING;
 			memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
 			mdc800->write_urb->dev = mdc800->dev;
-			if (usb_submit_urb (mdc800->write_urb))
+			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
 			{
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
 				up (&mdc800->io_lock);
diff -Nru a/drivers/usb/microtek.c b/drivers/usb/microtek.c
--- a/drivers/usb/microtek.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/microtek.c	Wed Feb  6 22:48:39 2002
@@ -499,7 +499,7 @@
 
 	transfer->status = 0;
 
-	res = usb_submit_urb( transfer );
+	res = usb_submit_urb( transfer, GFP_ATOMIC );
 	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
 		context->srb->result = DID_ERROR << 16;
@@ -719,7 +719,8 @@
 	mts_build_transfer_context( srb, desc );
 	desc->context.final_callback = callback;
 	
-	res=usb_submit_urb(desc->urb);
+	/* here we need ATOMIC as we are called with the iolock */
+	res=usb_submit_urb(desc->urb, GFP_ATOMIC);
 
 	if(unlikely(res)){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
diff -Nru a/drivers/usb/ov511.c b/drivers/usb/ov511.c
--- a/drivers/usb/ov511.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/ov511.c	Wed Feb  6 22:48:39 2002
@@ -4457,7 +4457,7 @@
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		ov511->sbuf[n].urb->dev = ov511->dev;
-		err = usb_submit_urb(ov511->sbuf[n].urb);
+		err = usb_submit_urb(ov511->sbuf[n].urb, GFP_KERNEL);
 		if (err)
 			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
 	}
@@ -5618,7 +5618,7 @@
 	void *arg = (void *) ularg;
 	int rc;
 
-	pde = (struct proc_dir_entry *) inode->u.generic_ip;
+	pde = PDE(inode);
 	if (!pde)
 		return -ENOENT;
 
diff -Nru a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
--- a/drivers/usb/pegasus.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/pegasus.c	Wed Feb  6 22:48:39 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 );
@@ -157,8 +157,9 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRLs %d", ret);
+	/* using ATOMIC, we'd never wake up if we slept */
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
+		err("%s: BAD CTRLs %d", __FUNCTION__, ret);
 		goto out;
 	}
 
@@ -207,8 +208,8 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRL %d", ret);
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
+		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 	
@@ -257,8 +258,8 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
-		err( __FUNCTION__ " BAD CTRL %d", ret);
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
+		err("%s: BAD CTRL %d", __FUNCTION__, ret);
 		goto out;
 	}
 
@@ -287,8 +288,8 @@
 			  (char *)&pegasus->dr,
 			  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 );
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) )
+		err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
 
 	return	ret;
 }
@@ -313,7 +314,7 @@
 		*regd = le16_to_cpu(regdi);
 		return	0;
 	}
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 	
 	return 1;
 }
@@ -335,7 +336,7 @@
 	}
 	if ( i < REG_TIMEOUT )
 		return	0;
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 
 	return 1;
 }
@@ -361,7 +362,7 @@
 		*retdata = le16_to_cpu (retdatai);
 		return	0;
 	}
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 
 	return -1;
 }
@@ -405,7 +406,7 @@
 	disable_eprom_write( pegasus );
 	if ( i < REG_TIMEOUT )
 		return	0;
-	warn( __FUNCTION__ " failed" );
+	warn("%s: failed", __FUNCTION__);
 	return	-1;
 }
 #endif	/* PEGASUS_WRITE_EEPROM */
@@ -573,8 +574,8 @@
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			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);
+	if ( (res = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) )
+		warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
 
@@ -661,7 +662,7 @@
 			pegasus->tx_buff, PEGASUS_MAX_MTU, 
 			write_bulk_callback, pegasus );
 	pegasus->tx_urb->transfer_buffer_length = count;
-	if ((res = usb_submit_urb(pegasus->tx_urb))) {
+	if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
 		netif_start_queue( net );
@@ -721,15 +722,15 @@
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			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 );
+	if ( (res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)) )
+		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);
+	if ( (res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)) )
+		warn("%s: failed intr_urb %d", __FUNCTION__, res);
 #endif
 	netif_start_queue( net );
 	pegasus->flags |= PEGASUS_RUNNING;
@@ -885,6 +886,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 +914,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 +954,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	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/printer.c	Wed Feb  6 22:48:39 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,11 +255,13 @@
 
 	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;
 		usblp->readurb.dev = usblp->dev;
-		if (usb_submit_urb(&usblp->readurb) < 0) {
+		if (usb_submit_urb(&usblp->readurb, GFP_KERNEL) < 0) {
 			retval = -EIO;
 			usblp->used = 0;
 			file->private_data = NULL;
@@ -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, GFP_KERNEL)) {
+			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) {
@@ -479,7 +521,7 @@
 			usblp->minor, usblp->readurb.status);
 		usblp->readurb.dev = usblp->dev;
  		usblp->readcount = 0;
-		usb_submit_urb(&usblp->readurb);
+		usb_submit_urb(&usblp->readurb, GFP_KERNEL);
 		count = -EIO;
 		goto done;
 	}
@@ -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, GFP_KERNEL)) {
+			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/pwc-if.c b/drivers/usb/pwc-if.c
--- a/drivers/usb/pwc-if.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/pwc-if.c	Wed Feb  6 22:48:39 2002
@@ -869,7 +869,7 @@
 
 	/* link */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
-		ret = usb_submit_urb(pdev->sbuf[i].urb);
+		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
 		if (ret)
 			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
 		else
diff -Nru a/drivers/usb/scanner.c b/drivers/usb/scanner.c
--- a/drivers/usb/scanner.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/scanner.c	Wed Feb  6 22:48:39 2002
@@ -992,7 +992,7 @@
 			     // endpoint[(int)have_intr].bInterval);
 			     250);
 
-	        if (usb_submit_urb(scn->scn_irq)) {
+	        if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) {
 			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                 	kfree(scn);
 			up(&scn_mutex);
diff -Nru a/drivers/usb/se401.c b/drivers/usb/se401.c
--- a/drivers/usb/se401.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/se401.c	Wed Feb  6 22:48:39 2002
@@ -556,7 +556,7 @@
 	/* Resubmit urb for new data */
 	urb->status=0;
 	urb->dev=se401->dev;
-	if(usb_submit_urb(urb))
+	if(usb_submit_urb(urb, GFP_KERNEL))
 		info("urb burned down");
 	return;
 }
@@ -657,7 +657,7 @@
 
 		se401->urb[i]=urb;
 
-		err=usb_submit_urb(se401->urb[i]);
+		err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
 		if(err)
 			err("urb burned down");
 	}
@@ -1477,7 +1477,7 @@
 	    se401,
 	    HZ/10
 	);
-	if (usb_submit_urb(se401->inturb)) {
+	if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
 		info("int urb burned down");
 		return 1;
 	}
diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/belkin_sa.c	Wed Feb  6 22:48:38 2002
@@ -217,14 +217,14 @@
 		 *       enhance buffering.  Win trace shows 16 initial read URBs.
 		 */
 		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
+		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (retval) {
 			err("usb_submit_urb(read bulk) failed");
 			goto exit;
 		}
 
 		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb);
+		retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (retval)
 			err(" usb_submit_urb(read int) failed");
 	}
diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/cyberjack.c	Wed Feb  6 22:48:39 2002
@@ -173,7 +173,7 @@
 		usb_unlink_urb (port->interrupt_in_urb);
 
 		port->interrupt_in_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->interrupt_in_urb);
+		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (result)
 			err(" usb_submit_urb(read int) failed");
 		dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
@@ -271,7 +271,7 @@
 			      port);
 
 		/* send the data out the bulk port */
-		result = usb_submit_urb(port->write_urb);
+		result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 			/* Throw away data. No better idea what to do with it. */
@@ -342,7 +342,7 @@
 
 		if( !old_rdtodo ) {
 			port->read_urb->dev = port->serial->dev;
-			result = usb_submit_urb(port->read_urb);
+			result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 			if( result )
 				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 			dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
@@ -398,7 +398,7 @@
 	/* Continue to read if we have still urbs to do. */
 	if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
 		port->read_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 		dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
@@ -453,7 +453,7 @@
 			      port);
 
 		/* send the data out the bulk port */
-		result = usb_submit_urb(port->write_urb);
+		result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 			/* Throw away data. No better idea what to do with it. */
diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
--- a/drivers/usb/serial/digi_acceleport.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/digi_acceleport.c	Wed Feb  6 22:48:39 2002
@@ -676,7 +676,7 @@
 		oob_port->write_urb->transfer_buffer_length = len;
 		oob_port->write_urb->dev = port->serial->dev;
 
-		if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+		if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) {
 			oob_priv->dp_write_urb_in_use = 1;
 			count -= len;
 			buf += len;
@@ -764,7 +764,7 @@
 		}
 		port->write_urb->dev = port->serial->dev;
 
-		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+		if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) {
 			priv->dp_write_urb_in_use = 1;
 			priv->dp_out_buf_len = 0;
 			count -= len;
@@ -841,7 +841,7 @@
 	oob_port->write_urb->transfer_buffer_length = 8;
 	oob_port->write_urb->dev = port->serial->dev;
 
-	if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+	if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) {
 		oob_priv->dp_write_urb_in_use = 1;
 		port_priv->dp_modem_signals =
 			(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
@@ -962,7 +962,7 @@
 	/* restart read chain */
 	if( priv->dp_throttle_restart ) {
 		port->read_urb->dev = port->serial->dev;
-		ret = usb_submit_urb( port->read_urb );
+		ret = usb_submit_urb( port->read_urb, GFP_KERNEL );
 	}
 
 	/* turn throttle off */
@@ -1323,7 +1323,7 @@
 	/* copy in new data */
 	memcpy( data, from_user ? user_buf : buf, new_len );
 
-	if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+	if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) {
 		priv->dp_write_urb_in_use = 1;
 		ret = new_len;
 		priv->dp_out_buf_len = 0;
@@ -1399,7 +1399,7 @@
 		memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
 			priv->dp_out_buf_len );
 
-		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+		if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) {
 			priv->dp_write_urb_in_use = 1;
 			priv->dp_out_buf_len = 0;
 		}
@@ -1677,7 +1677,7 @@
 
 		port->write_urb->dev = port->serial->dev;
 
-		if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+		if( (ret=usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0 ) {
 			err(
 			__FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
 			ret, i );
@@ -1837,7 +1837,7 @@
 
 	/* continue read */
 	urb->dev = port->serial->dev;
-	if( (ret=usb_submit_urb(urb)) != 0 ) {
+	if( (ret=usb_submit_urb(urb, GFP_KERNEL)) != 0 ) {
 		err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d",
 			ret, priv->dp_port_num );
 	}
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/empeg.c	Wed Feb  6 22:48:39 2002
@@ -182,7 +182,7 @@
 
 		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
 		if (result)
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
@@ -296,7 +296,7 @@
 		urb->transfer_flags |= USB_QUEUE_BULK;
 
 		/* send it down the pipe */
-		status = usb_submit_urb(urb);
+		status = usb_submit_urb(urb, GFP_KERNEL);
 		if (status) {
 			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
 			bytes_sent = status;
@@ -449,7 +449,7 @@
 
 	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
@@ -484,7 +484,7 @@
 
 	port->read_urb->dev = port->serial->dev;
 
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/ftdi_sio.c	Wed Feb  6 22:48:39 2002
@@ -356,7 +356,7 @@
 			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 			      ftdi_sio_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
@@ -479,7 +479,7 @@
 		      port->write_urb->transfer_buffer, count,
 		      ftdi_sio_write_bulk_callback, port);
 		
-	result = usb_submit_urb(port->write_urb);
+	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 	if (result) {
 		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 		up (&port->sem);
@@ -644,7 +644,7 @@
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 		      ftdi_sio_read_bulk_callback, port);
 
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
--- a/drivers/usb/serial/io_edgeport.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/io_edgeport.c	Wed Feb  6 22:48:38 2002
@@ -787,7 +787,7 @@
 
 					/* we have pending bytes on the bulk in pipe, send a request */
 					edge_serial->read_urb->dev = edge_serial->serial->dev;
-					result = usb_submit_urb(edge_serial->read_urb);
+					result = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL);
 					if (result) {
 						dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result);
 					}
@@ -864,7 +864,7 @@
 
 			/* there is, so resubmit our urb */
 			edge_serial->read_urb->dev = edge_serial->serial->dev;
-			status = usb_submit_urb(edge_serial->read_urb);
+			status = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL);
 			if (status) {
 				err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status);
 			}
@@ -1031,7 +1031,7 @@
 
 			/* start interrupt read for this edgeport
 			 * this interrupt will continue as long as the edgeport is connected */
-			response = usb_submit_urb (edge_serial->interrupt_read_urb);
+			response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
 			if (response) {
 				err(__FUNCTION__" - Error %d submitting control urb", response);
 			}
@@ -1471,7 +1471,7 @@
 	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	urb->dev = edge_serial->serial->dev;
-	status = usb_submit_urb(urb);
+	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status) {
 		/* something went wrong */
 		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
@@ -2477,7 +2477,7 @@
 	urb->transfer_flags |= USB_QUEUE_BULK;
 
 	edge_port->commandPending = TRUE;
-	status = usb_submit_urb(urb);
+	status = usb_submit_urb(urb, GFP_KERNEL);
 
 	if (status) {
 		/* something went wrong */
diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
--- a/drivers/usb/serial/ipaq.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/ipaq.c	Wed Feb  6 22:48:39 2002
@@ -171,7 +171,7 @@
 			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 			      ipaq_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 		}
@@ -288,7 +288,7 @@
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 		      ipaq_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
@@ -403,7 +403,7 @@
 		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
 		      port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
 		      port);
-	result = usb_submit_urb(urb);
+	result = usb_submit_urb(urb, GFP_KERNEL);
 	if (result) {
 		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 	}
diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/ir-usb.c	Wed Feb  6 22:48:39 2002
@@ -289,7 +289,7 @@
 			ir_read_bulk_callback,
 			port);
 		port->read_urb->transfer_flags = USB_QUEUE_BULK;
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
@@ -382,7 +382,7 @@
 		= USB_QUEUE_BULK
 		| USB_ZERO_PACKET;
 
-	result = usb_submit_urb (port->write_urb);
+	result = usb_submit_urb (port->write_urb, GFP_KERNEL);
 	if (result)
 		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
@@ -492,7 +492,7 @@
 
 			port->read_urb->transfer_flags = USB_QUEUE_BULK;
 
-			result = usb_submit_urb(port->read_urb);
+			result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
 			if (result)
 				err("%s - failed resubmitting read urb, error %d",
@@ -591,7 +591,7 @@
 			= USB_QUEUE_BULK
 			| USB_ZERO_PACKET;
 
-		result = usb_submit_urb (port->write_urb);
+		result = usb_submit_urb (port->write_urb, GFP_KERNEL);
 		if (result)
 			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	}
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/keyspan.c	Wed Feb  6 22:48:38 2002
@@ -378,7 +378,7 @@
 
 		this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
-		if ((err = usb_submit_urb(this_urb)) != 0) {
+		if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) {
 			dbg("usb_submit_urb(write bulk) failed (%d)\n", err);
 		}
 		p_priv->tx_start_time[flip] = jiffies;
@@ -436,7 +436,7 @@
 				
 		/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
+	if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
 	}
 	return;
@@ -535,7 +535,7 @@
 exit:
 	/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
+	if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
 	}
 }
@@ -586,7 +586,7 @@
 
 		/* Resubmit urb so we continue receiving */
 		urb->dev = port->serial->dev;
-		if ((err = usb_submit_urb(urb)) != 0) {
+		if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 			dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n",
 err);
 		}
@@ -671,7 +671,7 @@
 exit:	
 		/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
+	if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
 	}
 }
@@ -764,7 +764,7 @@
 		/* Resubmit urb so we continue receiving */
 	urb->dev = serial->dev;
 
-	if ((err = usb_submit_urb(urb)) != 0) {
+	if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
 	}
 }
@@ -819,7 +819,7 @@
 				
 		/* Resubmit urb so we continue receiving */
 	urb->dev = port->serial->dev;
-	if ((err = usb_submit_urb(urb)) != 0) {
+	if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err);
 	}
 }
@@ -880,7 +880,7 @@
 		if ((urb = p_priv->in_urbs[i]) == NULL)
 			continue;
 		urb->dev = serial->dev;
-		if ((err = usb_submit_urb(urb)) != 0) {
+		if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
 			dbg(__FUNCTION__ " submit urb %d failed (%d)\n", i, err);
 		}
 	}
@@ -1408,7 +1408,7 @@
 	this_urb->transfer_buffer_length = sizeof(msg);
 
 	this_urb->dev = serial->dev;
-	if ((err = usb_submit_urb(this_urb)) != 0) {
+	if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)\n", err);
 	}
 #if 0
@@ -1494,7 +1494,7 @@
 	this_urb->transfer_buffer_length = sizeof(msg);
 
 	this_urb->dev = serial->dev;
-	if ((err = usb_submit_urb(this_urb)) != 0) {
+	if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
 	}
 #if 0
@@ -1622,7 +1622,7 @@
 	this_urb->transfer_buffer_length = sizeof(msg);
 
 	this_urb->dev = serial->dev;
-	if ((err = usb_submit_urb(this_urb)) != 0) {
+	if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)\n", err);
 	}
 #if 0
@@ -1708,7 +1708,7 @@
 	keyspan_setup_urbs(serial);
 
 	s_priv->instat_urb->dev = serial->dev;
-	if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+	if ((err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL)) != 0) {
 		dbg(__FUNCTION__ " submit instat urb failed %d\n", err);
 	}
 			
diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/keyspan_pda.c	Wed Feb  6 22:48:38 2002
@@ -292,7 +292,7 @@
 	/* just restart the receive interrupt URB */
 	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
 	port->interrupt_in_urb->dev = port->serial->dev;
-	if (usb_submit_urb(port->interrupt_in_urb))
+	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
 		dbg(" usb_submit_urb(read urb) failed");
 	return;
 }
@@ -584,7 +584,7 @@
 		priv->tx_room -= count;
 
 		port->write_urb->dev = port->serial->dev;
-		rc = usb_submit_urb(port->write_urb);
+		rc = usb_submit_urb(port->write_urb, GFP_KERNEL);
 		if (rc) {
 			dbg(" usb_submit_urb(write bulk) failed");
 			goto exit;
@@ -699,7 +699,7 @@
 
 		/*Start reading from the device*/
 		port->interrupt_in_urb->dev = serial->dev;
-		rc = usb_submit_urb(port->interrupt_in_urb);
+		rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (rc) {
 			dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
 			goto error;
diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/kl5kusb105.c	Wed Feb  6 22:48:38 2002
@@ -404,7 +404,7 @@
 			      port);
 		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-		rc = usb_submit_urb(port->read_urb);
+		rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (rc) {
 			err(__FUNCTION__ 
 			    " - failed submitting read urb, error %d", rc);
@@ -567,7 +567,7 @@
 
 
 		/* send the data out the bulk port */
-		result = usb_submit_urb(urb);
+		result = usb_submit_urb(urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__
 			    " - failed submitting write urb, error %d", result);
@@ -734,7 +734,7 @@
 		      port->read_urb->transfer_buffer_length,
 		      klsi_105_read_bulk_callback,
 		      port);
-	rc = usb_submit_urb(port->read_urb);
+	rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (rc)
 		err(__FUNCTION__ 
 		    " - failed resubmitting read urb, error %d", rc);
@@ -1041,7 +1041,7 @@
 	down (&port->sem);
 
 	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d",
 		    result);
diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/serial/mct_u232.c	Wed Feb  6 22:48:38 2002
@@ -384,14 +384,14 @@
 		}
 
 		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
+		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (retval) {
 			err("usb_submit_urb(read bulk) failed");
 			goto exit;
 		}
 
 		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb);
+		retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (retval)
 			err(" usb_submit_urb(read int) failed");
 
@@ -482,7 +482,7 @@
 			      port);
 		
 		/* send the data out the bulk port */
-		result = usb_submit_urb(port->write_urb);
+		result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__
 			    " - failed submitting write urb, error %d", result);
diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
--- a/drivers/usb/serial/omninet.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/omninet.c	Wed Feb  6 22:48:39 2002
@@ -179,7 +179,7 @@
 			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 			      omninet_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
@@ -274,7 +274,7 @@
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 		      urb->transfer_buffer, urb->transfer_buffer_length,
 		      omninet_read_bulk_callback, port);
-	result = usb_submit_urb(urb);
+	result = usb_submit_urb(urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
@@ -325,7 +325,7 @@
 	wport->write_urb->transfer_buffer_length = 64;
 
 	wport->write_urb->dev = serial->dev;
-	result = usb_submit_urb(wport->write_urb);
+	result = usb_submit_urb(wport->write_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 	else
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/pl2303.c	Wed Feb  6 22:48:39 2002
@@ -195,7 +195,7 @@
 
 	port->write_urb->transfer_buffer_length = count;
 	port->write_urb->dev = port->serial->dev;
-	result = usb_submit_urb (port->write_urb);
+	result = usb_submit_urb (port->write_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 	else
@@ -404,7 +404,7 @@
 
 		dbg (__FUNCTION__ " - submitting read urb");
 		port->read_urb->dev = serial->dev;
-		result = usb_submit_urb (port->read_urb);
+		result = usb_submit_urb (port->read_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 			up (&port->sem);
@@ -414,7 +414,7 @@
 
 		dbg (__FUNCTION__ " - submitting interrupt urb");
 		port->interrupt_in_urb->dev = serial->dev;
-		result = usb_submit_urb (port->interrupt_in_urb);
+		result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
 			up (&port->sem);
@@ -652,7 +652,7 @@
 			dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb");
 			urb->status = 0;
 			urb->dev = serial->dev;
-			result = usb_submit_urb(urb);
+			result = usb_submit_urb(urb, GFP_KERNEL);
 			if (result)
 				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 			return;
@@ -677,7 +677,7 @@
 	/* Schedule the next read _if_ we are still open */
 	if (port->open_count) {
 		urb->dev = serial->dev;
-		result = usb_submit_urb(urb);
+		result = usb_submit_urb(urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	}
@@ -706,7 +706,7 @@
 		dbg (__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
 		port->write_urb->transfer_buffer_length = 1;
 		port->write_urb->dev = port->serial->dev;
-		result = usb_submit_urb (port->write_urb);
+		result = usb_submit_urb (port->write_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed resubmitting write urb, error %d", result);
 
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/usbserial.c	Wed Feb  6 22:48:39 2002
@@ -813,7 +813,7 @@
 					     serial->type->read_bulk_callback :
 					     generic_read_bulk_callback),
 					   port);
-			result = usb_submit_urb(port->read_urb);
+			result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 			if (result)
 				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 		}
@@ -894,7 +894,7 @@
 				     generic_write_bulk_callback), port);
 
 		/* send the data out the bulk port */
-		result = usb_submit_urb(port->write_urb);
+		result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 		else
@@ -987,7 +987,7 @@
 			   ((serial->type->read_bulk_callback) ? 
 			     serial->type->read_bulk_callback : 
 			     generic_read_bulk_callback), port);
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 }
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/visor.c	Wed Feb  6 22:48:39 2002
@@ -274,7 +274,7 @@
 				   port->read_urb->transfer_buffer,
 				   port->read_urb->transfer_buffer_length,
 				   visor_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (result)
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
@@ -388,7 +388,7 @@
 		urb->transfer_flags |= USB_QUEUE_BULK;
 
 		/* send it down the pipe */
-		status = usb_submit_urb(urb);
+		status = usb_submit_urb(urb, GFP_KERNEL);
 		if (status) {
 			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
 			bytes_sent = status;
@@ -520,7 +520,7 @@
 			   port->read_urb->transfer_buffer,
 			   port->read_urb->transfer_buffer_length,
 			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
@@ -551,7 +551,7 @@
 	down (&port->sem);
 
 	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/serial/whiteheat.c	Wed Feb  6 22:48:39 2002
@@ -240,7 +240,7 @@
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 		      command_port_read_callback, port);
-	result = usb_submit_urb(port->read_urb);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		dbg(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 }
@@ -265,7 +265,7 @@
 	memcpy (&transfer_buffer[1], data, datasize);
 	port->write_urb->transfer_buffer_length = datasize + 1;
 	port->write_urb->dev = serial->dev;
-	retval = usb_submit_urb (port->write_urb);
+	retval = usb_submit_urb (port->write_urb, GFP_KERNEL);
 	if (retval) {
 		dbg (__FUNCTION__" - submit urb failed");
 		goto exit;
@@ -327,7 +327,7 @@
 			command_port->read_urb->complete = command_port_read_callback;
 			command_port->read_urb->dev = port->serial->dev;
 			command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
-			retval = usb_submit_urb (command_port->read_urb);
+			retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
 			if (retval) {
 				err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
 				goto error_exit;
@@ -336,7 +336,7 @@
 		
 		/* Start reading from the device */
 		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb);
+		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (retval) {
 			err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
 			goto error_exit;
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/storage/scsiglue.c	Wed Feb  6 22:48:39 2002
@@ -278,7 +278,7 @@
 	if (us->protocol == US_PR_CBI) {
 		down(&(us->irq_urb_sem));
 		us->irq_urb->dev = us->pusb_dev;
-		result = usb_submit_urb(us->irq_urb);
+		result = usb_submit_urb(us->irq_urb, GFP_NOIO);
 		US_DEBUGP("usb_submit_urb() returns %d\n", result);
 		up(&(us->irq_urb_sem));
 	}
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/storage/transport.c	Wed Feb  6 22:48:39 2002
@@ -414,7 +414,7 @@
 	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
 
 	/* submit the URB */
-	status = usb_submit_urb(us->current_urb);
+	status = usb_submit_urb(us->current_urb, GFP_NOIO);
 	if (status) {
 		/* something went wrong */
 		up(&(us->current_urb_sem));
@@ -461,7 +461,7 @@
 	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
 
 	/* submit the URB */
-	status = usb_submit_urb(us->current_urb);
+	status = usb_submit_urb(us->current_urb, GFP_NOIO);
 	if (status) {
 		/* something went wrong */
 		up(&(us->current_urb_sem));
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/storage/usb.c	Wed Feb  6 22:48:39 2002
@@ -534,7 +534,7 @@
 		     usb_stor_CBI_irq, ss, ss->ep_int->bInterval); 
 
 	/* submit the URB for processing */
-	result = usb_submit_urb(ss->irq_urb);
+	result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
 	US_DEBUGP("usb_submit_urb() returns %d\n", result);
 	if (result) {
 		usb_free_urb(ss->irq_urb);
diff -Nru a/drivers/usb/stv680.c b/drivers/usb/stv680.c
--- a/drivers/usb/stv680.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/stv680.c	Wed Feb  6 22:48:39 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 */
 
@@ -759,7 +765,7 @@
 	/* Resubmit urb for new data */
 	urb->status = 0;
 	urb->dev = stv680->udev;
-	if (usb_submit_urb (urb))
+	if (usb_submit_urb (urb, GFP_KERNEL))
 		PDEBUG (0, "STV(e): urb burned down in video irq");
 	return;
 }				/*  _video_irq  */
@@ -810,7 +816,7 @@
 		urb->timeout = PENCAM_TIMEOUT * 2;
 		urb->transfer_flags |= USB_QUEUE_BULK;
 		stv680->urb[i] = urb;
-		err = usb_submit_urb (stv680->urb[i]);
+		err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
 		if (err)
 			PDEBUG (0, "STV(e): urb burned down in start stream");
 	}			/* i STV680_NUMSBUF */
@@ -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/uhci-debug.h b/drivers/usb/uhci-debug.h
--- a/drivers/usb/uhci-debug.h	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/uhci-debug.h	Wed Feb  6 22:48:39 2002
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 #include <asm/io.h>
 
 #include "uhci.h"
@@ -476,7 +477,7 @@
 
 static int uhci_proc_open(struct inode *inode, struct file *file)
 {
-	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	const struct proc_dir_entry *dp = PDE(inode);
 	struct uhci *uhci = dp->data;
 	struct uhci_proc *up;
 	unsigned long flags;
@@ -507,8 +508,11 @@
 
 static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
 {
-	struct uhci_proc *up = file->private_data;
-	loff_t new;
+	struct uhci_proc *up;
+	loff_t new = -1;
+
+	lock_kernel();
+	up = file->private_data;
 
 	switch (whence) {
 	case 0:
@@ -517,12 +521,12 @@
 	case 1:
 		new = file->f_pos + off;
 		break;
-	case 2:
-	default:
-		return -EINVAL;
 	}
-	if (new < 0 || new > up->size)
+	if (new < 0 || new > up->size) {
+		unlock_kernel();
 		return -EINVAL;
+	}
+	unlock_kernel();
 	return (file->f_pos = new);
 }
 
diff -Nru a/drivers/usb/uhci.c b/drivers/usb/uhci.c
--- a/drivers/usb/uhci.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/uhci.c	Wed Feb  6 22:48:39 2002
@@ -1476,7 +1476,7 @@
 	return u;
 }
 
-static int uhci_submit_urb(struct urb *urb)
+static int uhci_submit_urb(struct urb *urb, int mem_flags)
 {
 	int ret = -EINVAL;
 	struct uhci *uhci;
@@ -1823,11 +1823,11 @@
 }
 
 struct usb_operations uhci_device_operations = {
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
+	allocate:		uhci_alloc_dev,
+	deallocate:		uhci_free_dev,
+	get_frame_number:	uhci_get_current_frame_number,
+	submit_urb:		uhci_submit_urb,
+	unlink_urb:		uhci_unlink_urb,
 };
 
 /* Virtual Root Hub */
@@ -2294,7 +2294,7 @@
 	} else {
 		if (is_ring && !killed) {
 			urb->dev = dev;
-			uhci_submit_urb(urb);
+			uhci_submit_urb(urb, GFP_KERNEL);
 		} else {
 			/* We decrement the usage count after we're done */
 			/*  with everything */
diff -Nru a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
--- a/drivers/usb/usb-ohci.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usb-ohci.c	Wed Feb  6 22:48:39 2002
@@ -532,7 +532,7 @@
 
 /* get a transfer request */
  
-static int sohci_submit_urb (struct urb * urb)
+static int sohci_submit_urb (struct urb * urb, int mem_flags)
 {
 	ohci_t * ohci;
 	ed_t * ed;
@@ -542,7 +542,6 @@
 	int i, size = 0;
 	unsigned long flags;
 	int bustime = 0;
-	int mem_flags = ALLOC_FLAGS;
 	
 	if (!urb->dev || !urb->dev->bus)
 		return -ENODEV;
@@ -612,8 +611,7 @@
 	}
 
 	/* allocate the private part of the URB */
-	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
-							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), mem_flags);
 	if (!urb_priv) {
 		usb_dec_dev_use (urb->dev);	
 		return -ENOMEM;
@@ -919,11 +917,11 @@
 /*-------------------------------------------------------------------------*/
 
 struct usb_operations sohci_device_operations = {
-	sohci_alloc_dev,
-	sohci_free_dev,
-	sohci_get_current_frame_number,
-	sohci_submit_urb,
-	sohci_unlink_urb
+	allocate:		sohci_alloc_dev,
+	deallocate:		sohci_free_dev,
+	get_frame_number:	sohci_get_current_frame_number,
+	submit_urb:		sohci_submit_urb,
+	unlink_urb:		sohci_unlink_urb,
 };
 
 /*-------------------------------------------------------------------------*
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usb-skeleton.c	Wed Feb  6 22:48:39 2002
@@ -431,7 +431,9 @@
 		      skel_write_bulk_callback, dev);
 
 	/* send the data out the bulk port */
-	retval = usb_submit_urb(dev->write_urb);
+	/* a character device write uses GFP_KERNEL,
+	 unless a spinlock is held */
+	retval = usb_submit_urb(dev->write_urb, GFP_KERNEL);
 	if (retval) {
 		err(__FUNCTION__ " - failed submitting write urb, error %d",
 		    retval);
diff -Nru a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
--- a/drivers/usb/usb-uhci.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usb-uhci.c	Wed Feb  6 22:48:39 2002
@@ -87,7 +87,6 @@
 #endif
 
 #define SLAB_FLAG     (in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt ()? GFP_ATOMIC : GFP_KERNEL)
 
 /* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
  * Reclamation: feature that puts loop on descriptor loop when
@@ -1502,7 +1501,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (struct urb *urb)
+_static int uhci_submit_iso_urb (struct urb *urb, int mem_flags)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1522,7 +1521,7 @@
 	if (ret)
 		goto err;
 
-	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
+	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), mem_flags);
 
 	if (!tdm) {
 		ret = -ENOMEM;
@@ -1619,7 +1618,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (struct urb *urb)
+_static int uhci_submit_urb (struct urb *urb, int mem_flags)
 {
 	uhci_t *s;
 	urb_priv_t *urb_priv;
@@ -1676,7 +1675,7 @@
 #ifdef DEBUG_SLAB
 	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
 #else
-	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kmalloc (sizeof (urb_priv_t), mem_flags);
 #endif
 	if (!urb_priv) {
 		usb_dec_dev_use (urb->dev);
@@ -1729,12 +1728,12 @@
 				if (bustime < 0) 
 					ret = bustime;
 				else {
-					ret = uhci_submit_iso_urb(urb);
+					ret = uhci_submit_iso_urb(urb, mem_flags);
 					if (ret == 0)
 						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
 				}
 			} else {        /* bandwidth is already set */
-				ret = uhci_submit_iso_urb(urb);
+				ret = uhci_submit_iso_urb(urb, mem_flags);
 			}
 			break;
 		case PIPE_INTERRUPT:
@@ -2279,11 +2278,11 @@
 
 struct usb_operations uhci_device_operations =
 {
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
+	allocate:		uhci_alloc_dev,
+	deallocate:		uhci_free_dev,
+	get_frame_number:	uhci_get_current_frame_number,
+	submit_urb:		uhci_submit_urb,
+	unlink_urb:		uhci_unlink_urb,
 };
 
 _static void correct_data_toggles(struct urb *urb)
@@ -2697,7 +2696,10 @@
 
 						spin_unlock(&s->urb_list_lock);
 
-						ret_submit=uhci_submit_urb(next_urb);
+						// FIXME!!!
+						// We need to know the real state, so 
+						// GFP_ATOMIC is probably not correct
+						ret_submit=uhci_submit_urb(next_urb, GFP_ATOMIC);
 						spin_lock(&s->urb_list_lock);
 						
 						if (ret_submit)
@@ -2721,7 +2723,10 @@
 				// Re-submit the URB if ring-linked
 				if (is_ring && !was_unlinked && !contains_killed) {
 					urb->dev=usb_dev;
-					uhci_submit_urb (urb);
+					// FIXME!!!
+					// We need to know the real state, so 
+					// GFP_ATOMIC is probably not correct
+					uhci_submit_urb (urb, GFP_ATOMIC);
 				}
 				spin_lock(&s->urb_list_lock);
 			}
diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c
--- a/drivers/usb/usb.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usb.c	Wed Feb  6 22:48:39 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;
@@ -1148,6 +1148,7 @@
 /**
  * usb_submit_urb - asynchronously issue a transfer request for an endpoint
  * @urb: pointer to the urb describing the request
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this.
  *
  * This submits a transfer request, and transfers control of the URB
  * describing that request to the USB subsystem.  Request completion will
@@ -1197,12 +1198,49 @@
  *
  * If the USB subsystem can't reserve sufficient bandwidth to perform
  * the periodic request, and bandwidth reservation is being done for
- * this controller, submitting such a periodic request will fail. 
+ * this controller, submitting such a periodic request will fail.
+ *
+ * Memory Flags:
+ *
+ * General rules for how to decide which mem_flags to use:
+ * 
+ * Basically the rules are the same as for kmalloc.  There are four
+ * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
+ * GFP_ATOMIC.
+ *
+ * GFP_NOFS is not ever used, as it has not been implemented yet.
+ *
+ * There are three situations you must use GFP_ATOMIC.
+ *    a) you are inside a completion handler, an interrupt, bottom half,
+ *       tasklet or timer.
+ *    b) you are holding a spinlock or rwlock (does not apply to
+ *       semaphores)
+ *    c) current->state != TASK_RUNNING, this is the case only after
+ *       you've changed it.
+ * 
+ * GFP_NOIO is used in the block io path and error handling of storage
+ * devices.
+ *
+ * All other situations use GFP_KERNEL.
+ *
+ * Specfic rules for how to decide which mem_flags to use:
+ *
+ *    - start_xmit, timeout, and receive methods of network drivers must
+ *      use GFP_ATOMIC (spinlock)
+ *    - queuecommand methods of scsi drivers must use GFP_ATOMIC (spinlock)
+ *    - If you use a kernel thread with a network driver you must use
+ *      GFP_NOIO, unless b) or c) apply
+ *    - After you have done a down() you use GFP_KERNEL, unless b) or c)
+ *      apply or your are in a storage driver's block io path
+ *    - probe and disconnect use GFP_KERNEL unless b) or c) apply
+ *    - Changing firmware on a running storage or net device uses
+ *      GFP_NOIO, unless b) or c) apply
+ *
  */
-int usb_submit_urb(struct urb *urb)
+int usb_submit_urb(struct urb *urb, int mem_flags)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
-		return urb->dev->bus->op->submit_urb(urb);
+		return urb->dev->bus->op->submit_urb(urb, mem_flags);
 	else
 		return -ENODEV;
 }
@@ -1272,7 +1310,7 @@
 	add_wait_queue(&awd.wqh, &wait);
 
 	urb->context = &awd;
-	status = usb_submit_urb(urb);
+	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status) {
 		// something went wrong
 		usb_free_urb(urb);
@@ -2283,7 +2321,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/usbkbd.c b/drivers/usb/usbkbd.c
--- a/drivers/usb/usbkbd.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usbkbd.c	Wed Feb  6 22:48:39 2002
@@ -129,7 +129,7 @@
 
 	kbd->leds = kbd->newleds;
 	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led))
+	if (usb_submit_urb(kbd->led, GFP_KERNEL))
 		err("usb_submit_urb(leds) failed");
 
 	return 0;
@@ -147,7 +147,7 @@
 
 	kbd->leds = kbd->newleds;
 	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led))
+	if (usb_submit_urb(kbd->led, GFP_KERNEL))
 		err("usb_submit_urb(leds) failed");
 }
 
@@ -159,7 +159,7 @@
 		return 0;
 
 	kbd->irq->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->irq))
+	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
 		return -EIO;
 
 	return 0;
diff -Nru a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c
--- a/drivers/usb/usbmouse.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usbmouse.c	Wed Feb  6 22:48:39 2002
@@ -85,7 +85,7 @@
 		return 0;
 
 	mouse->irq->dev = mouse->usbdev;
-	if (usb_submit_urb(mouse->irq))
+	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
 		return -EIO;
 
 	return 0;
diff -Nru a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
--- a/drivers/usb/usbnet.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/usbnet.c	Wed Feb  6 22:48:38 2002
@@ -373,7 +373,7 @@
 	// issue usb interrupt read
 	if (priv && priv->irq_urb) {
 		// submit urb
-		if ((retval = usb_submit_urb (priv->irq_urb)) != 0)
+		if ((retval = usb_submit_urb (priv->irq_urb, GFP_KERNEL)) != 0)
 			dbg ("gl_interrupt_read: submit fail - %X...", retval);
 		else
 			dbg ("gl_interrupt_read: submit success...");
@@ -1281,7 +1281,7 @@
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
 	if (netif_running (&dev->net)) {
-		if ((retval = usb_submit_urb (urb)) != 0) {
+		if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
 			dbg ("%s rx submit, %d", dev->net.name, retval);
 			tasklet_schedule (&dev->bh);
 		} else {
@@ -1642,7 +1642,7 @@
 #endif	/* CONFIG_USB_NET1080 */
 
 	netif_stop_queue (net);
-	if ((retval = usb_submit_urb (urb)) != 0) {
+	if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
 		netif_start_queue (net);
 		dbg ("%s tx: submit urb err %d", net->name, retval);
 	} else {
diff -Nru a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c
--- a/drivers/usb/usbvideo.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/usbvideo.c	Wed Feb  6 22:48:39 2002
@@ -1916,7 +1916,7 @@
 
 	/* Submit all URBs */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		errFlag = usb_submit_urb(uvd->sbuf[i].urb);
+		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
 		if (errFlag)
 			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
 	}
diff -Nru a/drivers/usb/vicam.c b/drivers/usb/vicam.c
--- a/drivers/usb/vicam.c	Wed Feb  6 22:48:39 2002
+++ b/drivers/usb/vicam.c	Wed Feb  6 22:48:39 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);
@@ -344,7 +350,7 @@
 	synchronize(vicam);
 	mdelay(10);
 	vicam_parameters(vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
+	printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
 #endif
 }
 
@@ -759,7 +765,7 @@
 		memcpy(vicam->fbuf, buf+64, 0x1e480);
 
 	if (!change_pending) {
-		if (usb_submit_urb(urb))
+		if (usb_submit_urb(urb, GFP_ATOMIC))
 			dbg("failed resubmitting read urb");
 	} else {
 		change_pending = 0;
@@ -843,7 +849,7 @@
 
 	FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
 		      buf, 0x1e480, vicam_bulk, vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
+	printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
 
 	return 0;
 error:
diff -Nru a/drivers/usb/wacom.c b/drivers/usb/wacom.c
--- a/drivers/usb/wacom.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/usb/wacom.c	Wed Feb  6 22:48:38 2002
@@ -336,7 +336,7 @@
 		return 0;
 
 	wacom->irq->dev = wacom->usbdev;
-	if (usb_submit_urb(wacom->irq))
+	if (usb_submit_urb(wacom->irq, GFP_KERNEL))
 		return -EIO;
 
 	return 0;
diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/video/neofb.c	Wed Feb  6 22:48:38 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/drivers/zorro/proc.c b/drivers/zorro/proc.c
--- a/drivers/zorro/proc.c	Wed Feb  6 22:48:38 2002
+++ b/drivers/zorro/proc.c	Wed Feb  6 22:48:38 2002
@@ -14,6 +14,7 @@
 #include <linux/zorro.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/amigahw.h>
 #include <asm/setup.h>
@@ -21,7 +22,7 @@
 static loff_t
 proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
 {
-	loff_t new;
+	loff_t new = -1;
 
 	switch (whence) {
 	case 0:
@@ -33,11 +34,12 @@
 	case 2:
 		new = sizeof(struct ConfigDev) + off;
 		break;
-	default:
-		return -EINVAL;
 	}
-	if (new < 0 || new > sizeof(struct ConfigDev))
+	if (new < 0 || new > sizeof(struct ConfigDev)) {
+		unlock_kernel();
 		return -EINVAL;
+	}
+	unlock_kernel();
 	return (file->f_pos = new);
 }
 
@@ -45,7 +47,7 @@
 proc_bus_zorro_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
 	struct inode *ino = file->f_dentry->d_inode;
-	struct proc_dir_entry *dp = ino->u.generic_ip;
+	struct proc_dir_entry *dp = PDE(ino);
 	struct zorro_dev *dev = dp->data;
 	struct ConfigDev cd;
 	int pos = *ppos;
diff -Nru a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
--- a/fs/autofs/autofs_i.h	Wed Feb  6 22:48:39 2002
+++ b/fs/autofs/autofs_i.h	Wed Feb  6 22:48:39 2002
@@ -145,7 +145,7 @@
 
 /* Initializing function */
 
-struct super_block *autofs_read_super(struct super_block *, void *,int);
+int autofs_fill_super(struct super_block *, void *, int);
 
 /* Queue management functions */
 
diff -Nru a/fs/autofs/init.c b/fs/autofs/init.c
--- a/fs/autofs/init.c	Wed Feb  6 22:48:38 2002
+++ b/fs/autofs/init.c	Wed Feb  6 22:48:38 2002
@@ -14,7 +14,17 @@
 #include <linux/init.h>
 #include "autofs_i.h"
 
-static DECLARE_FSTYPE(autofs_fs_type, "autofs", autofs_read_super, 0);
+static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, autofs_fill_super);
+}
+
+static struct file_system_type autofs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"autofs",
+	get_sb:		autofs_get_sb,
+};
 
 static int __init init_autofs_fs(void)
 {
diff -Nru a/fs/autofs/inode.c b/fs/autofs/inode.c
--- a/fs/autofs/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/autofs/inode.c	Wed Feb  6 22:48:39 2002
@@ -111,8 +111,7 @@
 	return (*pipefd < 0);
 }
 
-struct super_block *autofs_read_super(struct super_block *s, void *data,
-				      int silent)
+int autofs_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
 	struct dentry * root;
@@ -175,7 +174,7 @@
 	 * Success! Install the root dentry now to indicate completion.
 	 */
 	s->s_root = root;
-	return s;
+	return 0;
 
 fail_fput:
 	printk("autofs: pipe file descriptor does not contain proper ops\n");
@@ -189,7 +188,7 @@
 fail_free:
 	kfree(sbi);
 fail_unlock:
-	return NULL;
+	return -EINVAL;
 }
 
 static int autofs_statfs(struct super_block *sb, struct statfs *buf)
diff -Nru a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
--- a/fs/autofs4/autofs_i.h	Wed Feb  6 22:48:39 2002
+++ b/fs/autofs4/autofs_i.h	Wed Feb  6 22:48:39 2002
@@ -144,7 +144,7 @@
 
 /* Initializing function */
 
-struct super_block *autofs4_read_super(struct super_block *, void *,int);
+int autofs4_fill_super(struct super_block *, void *, int);
 struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info *sbi, mode_t mode);
 
 /* Queue management functions */
diff -Nru a/fs/autofs4/init.c b/fs/autofs4/init.c
--- a/fs/autofs4/init.c	Wed Feb  6 22:48:39 2002
+++ b/fs/autofs4/init.c	Wed Feb  6 22:48:39 2002
@@ -14,7 +14,17 @@
 #include <linux/init.h>
 #include "autofs_i.h"
 
-static DECLARE_FSTYPE(autofs_fs_type, "autofs", autofs4_read_super, 0);
+static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, autofs4_fill_super);
+}
+
+static struct file_system_type autofs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"autofs",
+	get_sb:		autofs_get_sb,
+};
 
 static int __init init_autofs4_fs(void)
 {
diff -Nru a/fs/autofs4/inode.c b/fs/autofs4/inode.c
--- a/fs/autofs4/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/autofs4/inode.c	Wed Feb  6 22:48:39 2002
@@ -173,8 +173,7 @@
 	return ino;
 }
 
-struct super_block *autofs4_read_super(struct super_block *s, void *data,
-				      int silent)
+int autofs4_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
 	struct dentry * root;
@@ -251,7 +250,7 @@
 	 * Success! Install the root dentry now to indicate completion.
 	 */
 	s->s_root = root;
-	return s;
+	return 0;
 	
 	/*
 	 * Failure ... clean up.
@@ -278,7 +277,7 @@
 fail_free:
 	kfree(sbi);
 fail_unlock:
-	return NULL;
+	return -EINVAL;
 }
 
 static int autofs4_statfs(struct super_block *sb, struct statfs *buf)
diff -Nru a/fs/binfmt_misc.c b/fs/binfmt_misc.c
--- a/fs/binfmt_misc.c	Wed Feb  6 22:48:39 2002
+++ b/fs/binfmt_misc.c	Wed Feb  6 22:48:39 2002
@@ -656,7 +656,7 @@
 	clear_inode:	bm_clear_inode,
 };
 
-static struct super_block *bm_read_super(struct super_block * sb, void * data, int silent)
+static int bm_fill_super(struct super_block * sb, void * data, int silent)
 {
 	struct qstr names[2] = {{name:"status"}, {name:"register"}};
 	struct inode * inode;
@@ -675,13 +675,13 @@
 
 	inode = bm_get_inode(sb, S_IFDIR | 0755);
 	if (!inode)
-		return NULL;
+		return -ENOMEM;
 	inode->i_op = &bm_dir_inode_operations;
 	inode->i_fop = &bm_dir_operations;
 	dentry[0] = d_alloc_root(inode);
 	if (!dentry[0]) {
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	dentry[1] = d_alloc(dentry[0], &names[0]);
 	if (!dentry[1])
@@ -701,7 +701,7 @@
 	d_add(dentry[2], inode);
 
 	sb->s_root = dentry[0];
-	return sb;
+	return 0;
 
 out3:
 	dput(dentry[2]);
@@ -709,14 +709,26 @@
 	dput(dentry[1]);
 out1:
 	dput(dentry[0]);
-	return NULL;
+	return -ENOMEM;
+}
+
+static struct super_block *bm_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, bm_fill_super);
 }
 
 static struct linux_binfmt misc_format = {
-	NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
+	module: THIS_MODULE,
+	load_binary: load_misc_binary,
 };
 
-static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
+static struct file_system_type bm_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"binfmt_misc",
+	get_sb:		bm_get_sb,
+	fs_flags:	FS_LITTER,
+};
 
 static int __init init_misc_binfmt(void)
 {
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Wed Feb  6 22:48:38 2002
+++ b/fs/bio.c	Wed Feb  6 22:48:38 2002
@@ -33,20 +33,24 @@
 
 struct biovec_pool {
 	int size;
+	char *name; 
 	kmem_cache_t *slab;
 	mempool_t *pool;
 };
 
-static struct biovec_pool bvec_array[BIOVEC_NR_POOLS];
-
 /*
  * if you change this list, also change bvec_alloc or things will
  * break badly! cannot be bigger than what you can fit into an
  * unsigned short
  */
-static const int bvec_pool_sizes[BIOVEC_NR_POOLS] = { 1, 4, 16, 64, 128, 256 };
 
-#define BIO_MAX_PAGES	(bvec_pool_sizes[BIOVEC_NR_POOLS - 1])
+#define BV(x) { x, "biovec-" #x }
+static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = { 
+	BV(1), BV(4), BV(16), BV(64), BV(128), BV(256)
+}; 
+#undef BV
+
+#define BIO_MAX_PAGES	(bvec_array[BIOVEC_NR_POOLS - 1].size)
 
 static void *slab_pool_alloc(int gfp_mask, void *data)
 {
@@ -64,7 +68,7 @@
 	struct bio_vec *bvl;
 
 	/*
-	 * see comment near bvec_pool_sizes define!
+	 * see comment near bvec_array define!
 	 */
 	switch (nr) {
 		case   1        : *idx = 0; break;
@@ -452,21 +456,17 @@
 
 static void __init biovec_init_pool(void)
 {
-	char name[16];
 	int i, size;
 
-	memset(&bvec_array, 0, sizeof(bvec_array));
-
 	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
 		struct biovec_pool *bp = bvec_array + i;
 
-		size = bvec_pool_sizes[i] * sizeof(struct bio_vec);
+		size = bp->size * sizeof(struct bio_vec);
 
 		printk("biovec: init pool %d, %d entries, %d bytes\n", i,
-						bvec_pool_sizes[i], size);
+						bp->size, size);
 
-		snprintf(name, sizeof(name) - 1,"biovec-%d",bvec_pool_sizes[i]);
-		bp->slab = kmem_cache_create(name, size, 0,
+		bp->slab = kmem_cache_create(bp->name, size, 0,
 						SLAB_HWCACHE_ALIGN, NULL, NULL);
 		if (!bp->slab)
 			panic("biovec: can't init slab cache\n");
@@ -474,7 +474,7 @@
 					slab_pool_free, bp->slab);
 		if (!bp->pool)
 			panic("biovec: can't init mempool\n");
-		bp->size = size;
+		bp->size = size;	
 	}
 }
 
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Wed Feb  6 22:48:39 2002
+++ b/fs/block_dev.c	Wed Feb  6 22:48:39 2002
@@ -220,7 +220,7 @@
  * pseudo-fs
  */
 
-static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent)
+static int bd_fill_super(struct super_block *sb, void *data, int silent)
 {
 	static struct super_operations sops = {};
 	struct inode *root;
@@ -232,22 +232,32 @@
 	sb->s_op = &sops;
 	root = new_inode(sb);
 	if (!root)
-		return NULL;
+		return -ENOMEM;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root->d_sb = sb;
 	sb->s_root->d_parent = sb->s_root;
 	d_instantiate(sb->s_root, root);
-	return sb;
+	return 0;
 }
 
-static DECLARE_FSTYPE(bd_type, "bdev", bd_read_super, FS_NOMOUNT);
+static struct super_block *bd_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, bd_fill_super);
+}
+
+static struct file_system_type bd_type = {
+	name:		"bdev",
+	get_sb:		bd_get_sb,
+	fs_flags:	FS_NOMOUNT,
+};
 
 static struct vfsmount *bd_mnt;
 
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Wed Feb  6 22:48:39 2002
+++ b/fs/dcache.c	Wed Feb  6 22:48:39 2002
@@ -1283,6 +1283,7 @@
 
 	dcache_init(mempages);
 	inode_init(mempages);
+	files_init(mempages); 
 	mnt_init(mempages);
 	bdev_cache_init();
 	cdev_cache_init();
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Wed Feb  6 22:48:39 2002
+++ b/fs/devfs/base.c	Wed Feb  6 22:48:39 2002
@@ -3218,8 +3218,7 @@
     setattr:        devfs_notify_change,
 };
 
-static struct super_block *devfs_read_super (struct super_block *sb,
-					     void *data, int silent)
+static int devfs_fill_super (struct super_block *sb, void *data, int silent)
 {
     struct inode *root_inode = NULL;
 
@@ -3238,17 +3237,24 @@
     sb->s_root = d_alloc_root (root_inode);
     if (!sb->s_root) goto out_no_root;
     DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp);
-    return sb;
+    return 0;
 
 out_no_root:
     PRINTK ("(): get root inode failed\n");
     if (root_inode) iput (root_inode);
-    return NULL;
+    return -EINVAL;
 }   /*  End Function devfs_read_super  */
 
+static struct super_block *devfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, devfs_fill_super);
+}
 
-static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, FS_SINGLE);
-
+static struct file_system_type devfs_fs_type = {
+	name:		DEVFS_NAME,
+	get_sb:		devfs_get_sb,
+};
 
 /*  File operations for devfsd follow  */
 
diff -Nru a/fs/devpts/inode.c b/fs/devpts/inode.c
--- a/fs/devpts/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/devpts/inode.c	Wed Feb  6 22:48:39 2002
@@ -118,9 +118,9 @@
 	return 0;
 }
 
-struct super_block *devpts_read_super(struct super_block *s, void *data,
-				      int silent)
+static int devpts_fill_super(struct super_block *s, void *data, int silent)
 {
+	int error = -ENOMEM;
 	struct inode * inode;
 	struct devpts_sb_info *sbi;
 
@@ -136,6 +136,7 @@
 	memset(sbi->inodes, 0, sizeof(struct inode *) * sbi->max_ptys);
 
 	if ( devpts_parse_options(data,sbi) && !silent) {
+		error = -EINVAL;
 		printk("devpts: called with bogus options\n");
 		goto fail_free;
 	}
@@ -160,14 +161,14 @@
 
 	s->s_root = d_alloc_root(inode);
 	if (s->s_root)
-		return s;
+		return 0;
 	
 	printk("devpts: get root dentry failed\n");
 	iput(inode);
 fail_free:
 	kfree(sbi);
 fail:
-	return NULL;
+	return error;
 }
 
 static int devpts_statfs(struct super_block *sb, struct statfs *buf)
@@ -178,7 +179,17 @@
 	return 0;
 }
 
-static DECLARE_FSTYPE(devpts_fs_type, "devpts", devpts_read_super, FS_SINGLE);
+static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, devpts_fill_super);
+}
+
+static struct file_system_type devpts_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"devpts",
+	get_sb:		devpts_get_sb,
+};
 
 void devpts_pty_new(int number, kdev_t device)
 {
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Wed Feb  6 22:48:38 2002
+++ b/fs/driverfs/inode.c	Wed Feb  6 22:48:38 2002
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/device.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -341,6 +342,7 @@
 {
 	loff_t retval = -EINVAL;
 
+	lock_kernel();
 	switch(orig) {
 	case 0:
 		if (offset > 0) {
@@ -357,6 +359,7 @@
 	default:
 		break;
 	}
+	unlock_kernel();
 	return retval;
 }
 
@@ -446,8 +449,7 @@
 	put_inode:	force_delete,
 };
 
-static struct super_block*
-driverfs_read_super(struct super_block *sb, void *data, int silent)
+static int driverfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
 	struct dentry *root;
@@ -460,20 +462,31 @@
 
 	if (!inode) {
 		DBG("%s: could not get inode!\n",__FUNCTION__);
-		return NULL;
+		return -ENOMEM;
 	}
 
 	root = d_alloc_root(inode);
 	if (!root) {
 		DBG("%s: could not get root dentry!\n",__FUNCTION__);
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root = root;
-	return sb;
+	return 0;
 }
 
-static DECLARE_FSTYPE(driverfs_fs_type, "driverfs", driverfs_read_super, FS_SINGLE | FS_LITTER);
+static struct super_block *driverfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, driverfs_fill_super);
+}
+
+static struct file_system_type driverfs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"driverfs",
+	get_sb:		driverfs_get_sb,
+	fs_flags:	FS_LITTER,
+};
 
 static int get_mount(void)
 {
diff -Nru a/fs/ext2/ext2.h b/fs/ext2/ext2.h
--- a/fs/ext2/ext2.h	Wed Feb  6 22:48:39 2002
+++ b/fs/ext2/ext2.h	Wed Feb  6 22:48:39 2002
@@ -96,7 +96,6 @@
 extern void ext2_put_super (struct super_block *);
 extern void ext2_write_super (struct super_block *);
 extern int ext2_remount (struct super_block *, int *, char *);
-extern struct super_block * ext2_read_super (struct super_block *,void *,int);
 extern int ext2_statfs (struct super_block *, struct statfs *);
 
 /*
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Wed Feb  6 22:48:38 2002
+++ b/fs/ext2/super.c	Wed Feb  6 22:48:38 2002
@@ -441,8 +441,7 @@
 	return res;
 }
 
-struct super_block * ext2_read_super (struct super_block * sb, void * data,
-				      int silent)
+static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
@@ -465,14 +464,13 @@
 
 	sb->u.ext2_sb.s_mount_opt = 0;
 	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
-	    &sb->u.ext2_sb.s_mount_opt)) {
-		return NULL;
-	}
+	    &sb->u.ext2_sb.s_mount_opt))
+		return -EINVAL;
 
 	blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
 	if (!blocksize) {
 		printk ("EXT2-fs: unable to set blocksize\n");
-		return NULL;
+		return -EINVAL;
 	}
 
 	/*
@@ -487,7 +485,7 @@
 
 	if (!(bh = sb_bread(sb, logic_sb_block))) {
 		printk ("EXT2-fs: unable to read superblock\n");
-		return NULL;
+		return -EINVAL;
 	}
 	/*
 	 * Note: s_es must be initialized as soon as possible because
@@ -533,7 +531,7 @@
 
 		if (!sb_set_blocksize(sb, blocksize)) {
 			printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n");
-			return NULL;
+			return -EINVAL;
 		}
 
 		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
@@ -684,14 +682,14 @@
 		goto failed_mount2;
 	}
 	ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
-	return sb;
+	return 0;
 failed_mount2:
 	for (i = 0; i < db_count; i++)
 		brelse(sb->u.ext2_sb.s_group_desc[i]);
 	kfree(sb->u.ext2_sb.s_group_desc);
 failed_mount:
 	brelse(bh);
-	return NULL;
+	return -EINVAL;
 }
 
 static void ext2_commit_super (struct super_block * sb,
@@ -843,7 +841,18 @@
 	return 0;
 }
 
-static DECLARE_FSTYPE_DEV(ext2_fs_type, "ext2", ext2_read_super);
+static struct super_block *ext2_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
+}
+
+static struct file_system_type ext2_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"ext2",
+	get_sb:		ext2_get_sb,
+	fs_flags:	FS_REQUIRES_DEV,
+};
 
 static int __init init_ext2_fs(void)
 {
diff -Nru a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
--- a/fs/fat/fatfs_syms.c	Wed Feb  6 22:48:39 2002
+++ b/fs/fat/fatfs_syms.c	Wed Feb  6 22:48:39 2002
@@ -47,5 +47,10 @@
 	return fat_init_inodecache();
 }
 
+static void __exit exit_fat_fs(void)
+{
+	fat_destroy_inodecache();
+}
+
 module_init(init_fat_fs)
-module_exit(fat_destroy_inodecache)
+module_exit(exit_fat_fs)
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	Wed Feb  6 22:48:38 2002
+++ b/fs/file_table.c	Wed Feb  6 22:48:38 2002
@@ -186,3 +186,17 @@
 	file_list_unlock();
 	return 0;
 }
+
+void __init files_init(unsigned long mempages)
+{ 
+	int n; 
+	/* One file with associated inode and dcache is very roughly 1K. 
+	 * Per default don't use more than 10% of our memory for files. 
+	 */ 
+
+	n = (mempages * (PAGE_SIZE / 1024)) / 10;
+	files_stat.max_files = n; 
+	if (files_stat.max_files < NR_FILE)
+		files_stat.max_files = NR_FILE;
+} 
+
diff -Nru a/fs/hfs/catalog.c b/fs/hfs/catalog.c
--- a/fs/hfs/catalog.c	Wed Feb  6 22:48:39 2002
+++ b/fs/hfs/catalog.c	Wed Feb  6 22:48:39 2002
@@ -1346,13 +1346,6 @@
 		return -EINVAL;
 	}
 
-	while (mdb->rename_lock) {
-		hfs_sleep_on(&mdb->rename_wait);
-	}
-	spin_lock(&entry_lock);
-	mdb->rename_lock = 1; /* XXX: should be atomic_inc */
-	spin_unlock(&entry_lock);
-
 	/* keep readers from getting confused by changing dir size */
 	start_write(new_dir);
 	if (old_dir != new_dir) {
@@ -1567,11 +1560,6 @@
 		end_write(old_dir);
 	}
 	end_write(new_dir);
-	spin_lock(&entry_lock);
-	mdb->rename_lock = 0; /* XXX: should use atomic_dec */
-	hfs_wake_up(&mdb->rename_wait);
-	spin_unlock(&entry_lock);
-
 	return error;
 }
 
diff -Nru a/fs/hfs/extent.c b/fs/hfs/extent.c
--- a/fs/hfs/extent.c	Wed Feb  6 22:48:39 2002
+++ b/fs/hfs/extent.c	Wed Feb  6 22:48:39 2002
@@ -48,10 +48,7 @@
  * Get an exclusive lock on the B-tree bitmap.
  */
 static inline void lock_bitmap(struct hfs_mdb *mdb) {
-	while (mdb->bitmap_lock) {
-		hfs_sleep_on(&mdb->bitmap_wait);
-	}
-	mdb->bitmap_lock = 1;
+	down(&mdb->bitmap_sem);
 }
 
 /*
@@ -60,8 +57,7 @@
  * Relinquish an exclusive lock on the B-tree bitmap.
  */
 static inline void unlock_bitmap(struct hfs_mdb *mdb) {
-	mdb->bitmap_lock = 0;
-	hfs_wake_up(&mdb->bitmap_wait);
+	up(&mdb->bitmap_sem);
 }
 
 /*
diff -Nru a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
--- a/fs/hfs/file_cap.c	Wed Feb  6 22:48:38 2002
+++ b/fs/hfs/file_cap.c	Wed Feb  6 22:48:38 2002
@@ -24,6 +24,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
+#include <linux/smp_lock.h>
 
 /*================ Forward declarations ================*/
 static loff_t      cap_info_llseek(struct file *, loff_t,
diff -Nru a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
--- a/fs/hfs/file_hdr.c	Wed Feb  6 22:48:38 2002
+++ b/fs/hfs/file_hdr.c	Wed Feb  6 22:48:38 2002
@@ -29,6 +29,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
+#include <linux/smp_lock.h>
 
 /* prodos types */
 #define PRODOSI_FTYPE_DIR   0x0F
diff -Nru a/fs/hfs/hfs.h b/fs/hfs/hfs.h
--- a/fs/hfs/hfs.h	Wed Feb  6 22:48:39 2002
+++ b/fs/hfs/hfs.h	Wed Feb  6 22:48:39 2002
@@ -271,10 +271,7 @@
 						   512-byte blocks per
 						   "allocation block" */
 	hfs_u16			attrib;		/* Attribute word */
-	hfs_wait_queue		rename_wait;
-	int			rename_lock;
-	hfs_wait_queue		bitmap_wait;
-	int			bitmap_lock;
+	struct semaphore	bitmap_sem;
         struct list_head        entry_dirty;
 };
 
diff -Nru a/fs/hfs/mdb.c b/fs/hfs/mdb.c
--- a/fs/hfs/mdb.c	Wed Feb  6 22:48:39 2002
+++ b/fs/hfs/mdb.c	Wed Feb  6 22:48:39 2002
@@ -100,8 +100,7 @@
 	mdb->magic = HFS_MDB_MAGIC;
 	mdb->sys_mdb = sys_mdb;
 	INIT_LIST_HEAD(&mdb->entry_dirty);
-	hfs_init_waitqueue(&mdb->rename_wait);
-	hfs_init_waitqueue(&mdb->bitmap_wait);
+	init_MUTEX(&mdb->bitmap_sem);
 
 	/* See if this is an HFS filesystem */
 	buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1);
diff -Nru a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
--- a/fs/hpfs/buffer.c	Wed Feb  6 22:48:39 2002
+++ b/fs/hpfs/buffer.c	Wed Feb  6 22:48:39 2002
@@ -14,8 +14,7 @@
 #ifdef DEBUG_LOCKS
 	printk("lock creation\n");
 #endif
-	while (s->s_hpfs_creation_de_lock) sleep_on(&s->s_hpfs_creation_de);
-	s->s_hpfs_creation_de_lock = 1;
+	down(&s->u.hpfs_sb.hpfs_creation_de);
 }
 
 void hpfs_unlock_creation(struct super_block *s)
@@ -23,8 +22,7 @@
 #ifdef DEBUG_LOCKS
 	printk("unlock creation\n");
 #endif
-	s->s_hpfs_creation_de_lock = 0;
-	wake_up(&s->s_hpfs_creation_de);
+	up(&s->u.hpfs_sb.hpfs_creation_de);
 }
 
 void hpfs_lock_iget(struct super_block *s, int mode)
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Wed Feb  6 22:48:38 2002
+++ b/fs/hpfs/super.c	Wed Feb  6 22:48:38 2002
@@ -427,8 +427,8 @@
 	s->s_hpfs_bmp_dir = NULL;
 	s->s_hpfs_cp_table = NULL;
 
-	s->s_hpfs_creation_de_lock = s->s_hpfs_rd_inode = 0;
-	init_waitqueue_head(&s->s_hpfs_creation_de);
+	s->s_hpfs_rd_inode = 0;
+	init_MUTEX(&s->u.hpfs_sb.hpfs_creation_de);
 	init_waitqueue_head(&s->s_hpfs_iget_q);
 
 	uid = current->uid;
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Wed Feb  6 22:48:38 2002
+++ b/fs/namespace.c	Wed Feb  6 22:48:38 2002
@@ -1048,15 +1048,9 @@
 	if (!mnt_cache)
 		panic("Cannot create vfsmount cache");
 
-	mempages >>= (16 - PAGE_SHIFT);
-	mempages *= sizeof(struct list_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
-		;
-
-	do {
-		mount_hashtable = (struct list_head *)
-			__get_free_pages(GFP_ATOMIC, order);
-	} while (mount_hashtable == NULL && --order >= 0);
+	order = 0; 
+	mount_hashtable = (struct list_head *)
+		__get_free_pages(GFP_ATOMIC, order);
 
 	if (!mount_hashtable)
 		panic("Failed to allocate mount hash table\n");
diff -Nru a/fs/ncpfs/file.c b/fs/ncpfs/file.c
--- a/fs/ncpfs/file.c	Wed Feb  6 22:48:38 2002
+++ b/fs/ncpfs/file.c	Wed Feb  6 22:48:38 2002
@@ -18,6 +18,7 @@
 #include <linux/locks.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
@@ -281,7 +282,7 @@
 
 struct file_operations ncp_file_operations =
 {
-	llseek:		generic_file_llseek,
+	llseek:		remote_llseek,
 	read:		ncp_file_read,
 	write:		ncp_file_write,
 	ioctl:		ncp_ioctl,
diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
--- a/fs/ncpfs/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/ncpfs/inode.c	Wed Feb  6 22:48:39 2002
@@ -365,7 +365,7 @@
 	sock_inode = ncp_filp->f_dentry->d_inode;
 	if (!S_ISSOCK(sock_inode->i_mode))
 		goto out_bad_file2;
-	sock = &sock_inode->u.socket_i;
+	sock = SOCKET_I(sock_inode);
 	if (!sock)
 		goto out_bad_file2;
 		
diff -Nru a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
--- a/fs/ncpfs/sock.c	Wed Feb  6 22:48:39 2002
+++ b/fs/ncpfs/sock.c	Wed Feb  6 22:48:39 2002
@@ -101,7 +101,7 @@
 	struct ncp_reply_header reply;
 
 	file = server->ncp_filp;
-	sock = &file->f_dentry->d_inode->u.socket_i;
+	sock = SOCKET_I(file->f_dentry->d_inode);
 
 	init_timeout = server->m.time_out;
 	max_timeout = NCP_MAX_RPC_TIMEOUT;
@@ -269,7 +269,7 @@
 	int result = 0;
 	
 	file = server->ncp_filp;
-	sock = &file->f_dentry->d_inode->u.socket_i;
+	sock = SOCKET_I(file->f_dentry->d_inode);
 	
 	dataread = 0;
 
@@ -348,7 +348,7 @@
 	*((struct ncp_request_header *) (server->packet));
 
 	file = server->ncp_filp;
-	sock = &file->f_dentry->d_inode->u.socket_i;
+	sock = SOCKET_I(file->f_dentry->d_inode);
 	
 	ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC);
 	ncptcp_xmit_hdr[1] = htonl(size + 16);
@@ -444,7 +444,7 @@
 	}
 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
 	file = server->ncp_filp;
-	sock = &file->f_dentry->d_inode->u.socket_i;
+	sock = SOCKET_I(file->f_dentry->d_inode);
 	/* N.B. this isn't needed ... check socket type? */
 	if (!sock) {
 		printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Wed Feb  6 22:48:39 2002
+++ b/fs/nfs/dir.c	Wed Feb  6 22:48:39 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/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Wed Feb  6 22:48:38 2002
+++ b/fs/nfs/file.c	Wed Feb  6 22:48:38 2002
@@ -41,7 +41,7 @@
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 
 struct file_operations nfs_file_operations = {
-	llseek:		generic_file_llseek,
+	llseek:		remote_llseek,
 	read:		nfs_file_read,
 	write:		nfs_file_write,
 	mmap:		nfs_file_mmap,
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/nfs/inode.c	Wed Feb  6 22:48:39 2002
@@ -245,8 +245,7 @@
  * and the root file handle obtained from the server's mount
  * daemon. We stash these away in the private superblock fields.
  */
-struct super_block *
-nfs_read_super(struct super_block *sb, void *raw_data, int silent)
+int nfs_fill_super(struct super_block *sb, void *raw_data, int silent)
 {
 	struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
 	struct nfs_server	*server;
@@ -455,6 +454,8 @@
                 server->namelen = maxlen;
 
 	sb->s_maxbytes = fsinfo.maxfilesize;
+	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
+		sb->s_maxbytes = MAX_LFS_FILESIZE; 
 
 	/* Fire up the writeback cache */
 	if (nfs_reqlist_alloc(server) < 0) {
@@ -467,7 +468,7 @@
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_up();
-	return sb;
+	return 0;
 
 	/* Yargs. It didn't work out. */
  failure_kill_reqlist:
@@ -506,7 +507,7 @@
 	printk("nfs_read_super: missing data argument\n");
 
 out_fail:
-	return NULL;
+	return -EINVAL;
 }
 
 static int
@@ -630,39 +631,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 +693,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 +766,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 +1004,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 +1078,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;
@@ -1157,7 +1138,25 @@
 /*
  * File system information
  */
-static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);
+
+/*
+ *  Right now we are using get_sb_nodev, but we ought to switch to
+ *  get_anon_super() with appropriate comparison function.  The only
+ *  question being, when two NFS mounts are the same?  Identical IP
+ *  of server + identical root fhandle?  Trond?
+ */
+static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, nfs_fill_super);
+}
+
+static struct file_system_type nfs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"nfs",
+	get_sb:		nfs_get_sb,
+	fs_flags:	FS_ODD_RENAME,
+};
 
 extern int nfs_init_nfspagecache(void);
 extern void nfs_destroy_nfspagecache(void);
@@ -1175,10 +1174,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	Wed Feb  6 22:48:39 2002
+++ b/fs/nfs/nfs3proc.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/fs/nfs/pagelist.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:38 2002
+++ b/fs/nfs/read.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/fs/nfs/write.c	Wed Feb  6 22:48:39 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/ntfs/fs.c b/fs/ntfs/fs.c
--- a/fs/ntfs/fs.c	Wed Feb  6 22:48:39 2002
+++ b/fs/ntfs/fs.c	Wed Feb  6 22:48:39 2002
@@ -1130,7 +1130,7 @@
 	/* Inform the kernel about which super operations are available. */
 	sb->s_op = &ntfs_super_operations;
 	sb->s_magic = NTFS_SUPER_MAGIC;
-	sb->s_maxbytes = ~0ULL >> 1;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	ntfs_debug(DEBUG_OTHER, "Reading special files\n");
 	if (ntfs_load_special_files(vol)) {
 		ntfs_error("Error loading special files\n");
diff -Nru a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
--- a/fs/openpromfs/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/openpromfs/inode.c	Wed Feb  6 22:48:39 2002
@@ -998,8 +998,7 @@
 	statfs:		openprom_statfs,
 };
 
-struct super_block *openprom_read_super(struct super_block *s,void *data, 
-				    int silent)
+static int openprom_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
 
@@ -1013,15 +1012,25 @@
 	s->s_root = d_alloc_root(root_inode);
 	if (!s->s_root)
 		goto out_no_root;
-	return s;
+	return 0;
 
 out_no_root:
-	printk("openprom_read_super: get root inode failed\n");
+	printk("openprom_fill_super: get root inode failed\n");
 	iput(root_inode);
-	return NULL;
+	return -ENOMEM;
 }
 
-static DECLARE_FSTYPE(openprom_fs_type, "openpromfs", openprom_read_super, 0);
+static struct super_block *openprom_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, openprom_fill_super);
+}
+
+static struct file_system_type openprom_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"openpromfs",
+	get_sb:		openprom_get_sb,
+};
 
 static int __init init_openprom_fs(void)
 {
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Wed Feb  6 22:48:38 2002
+++ b/fs/pipe.c	Wed Feb  6 22:48:38 2002
@@ -246,12 +246,6 @@
 	return -EPIPE;
 }
 
-static loff_t
-pipe_lseek(struct file *file, loff_t offset, int orig)
-{
-	return -ESPIPE;
-}
-
 static ssize_t
 bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos)
 {
@@ -381,7 +375,7 @@
  * are also used in linux/fs/fifo.c to do operations on FIFOs.
  */
 struct file_operations read_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		bad_pipe_w,
 	poll:		fifo_poll,
@@ -391,7 +385,7 @@
 };
 
 struct file_operations write_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		bad_pipe_r,
 	write:		pipe_write,
 	poll:		fifo_poll,
@@ -401,7 +395,7 @@
 };
 
 struct file_operations rdwr_fifo_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		pipe_write,
 	poll:		fifo_poll,
@@ -411,7 +405,7 @@
 };
 
 struct file_operations read_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		bad_pipe_w,
 	poll:		pipe_poll,
@@ -421,7 +415,7 @@
 };
 
 struct file_operations write_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		bad_pipe_r,
 	write:		pipe_write,
 	poll:		pipe_poll,
@@ -431,7 +425,7 @@
 };
 
 struct file_operations rdwr_pipe_fops = {
-	llseek:		pipe_lseek,
+	llseek:		no_llseek,
 	read:		pipe_read,
 	write:		pipe_write,
 	poll:		pipe_poll,
@@ -606,7 +600,7 @@
 	statfs:		pipefs_statfs,
 };
 
-static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
+static int pipefs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *root;
 
@@ -616,22 +610,32 @@
 	sb->s_op	= &pipefs_ops;
 	root = new_inode(sb);
 	if (!root)
-		return NULL;
+		return -ENOMEM;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root->d_sb = sb;
 	sb->s_root->d_parent = sb->s_root;
 	d_instantiate(sb->s_root, root);
-	return sb;
+	return 0;
 }
 
-static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super, FS_NOMOUNT);
+static struct super_block *pipefs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, pipefs_fill_super);
+}
+
+static struct file_system_type pipe_fs_type = {
+	name:		"pipefs",
+	get_sb:		pipefs_get_sb,
+	fs_flags:	FS_NOMOUNT,
+};
 
 static int __init init_pipe_fs(void)
 {
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Wed Feb  6 22:48:38 2002
+++ b/fs/proc/base.c	Wed Feb  6 22:48:38 2002
@@ -37,6 +37,11 @@
 
 #define fake_ino(pid,ino) (((pid)<<16)|(ino))
 
+static inline struct task_struct *proc_task(struct inode *inode)
+{
+	return PROC_I(inode)->task;
+}
+
 ssize_t proc_pid_read_maps(struct task_struct*,struct file*,char*,size_t,loff_t*);
 int proc_pid_stat(struct task_struct*,char*);
 int proc_pid_status(struct task_struct*,char*);
@@ -45,9 +50,10 @@
 
 static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	if (inode->u.proc_i.file) {
-		*mnt = mntget(inode->u.proc_i.file->f_vfsmnt);
-		*dentry = dget(inode->u.proc_i.file->f_dentry);
+	struct file *file = PROC_I(inode)->file;
+	if (file) {
+		*mnt = mntget(file->f_vfsmnt);
+		*dentry = dget(file->f_dentry);
 		return 0;
 	}
 	return -ENOENT;
@@ -58,7 +64,7 @@
 	struct mm_struct * mm;
 	struct vm_area_struct * vma;
 	int result = -ENOENT;
-	struct task_struct *task = inode->u.proc_i.task;
+	struct task_struct *task = proc_task(inode);
 
 	task_lock(task);
 	mm = task->mm;
@@ -89,11 +95,11 @@
 {
 	struct fs_struct *fs;
 	int result = -ENOENT;
-	task_lock(inode->u.proc_i.task);
-	fs = inode->u.proc_i.task->fs;
+	task_lock(proc_task(inode));
+	fs = proc_task(inode)->fs;
 	if(fs)
 		atomic_inc(&fs->count);
-	task_unlock(inode->u.proc_i.task);
+	task_unlock(proc_task(inode));
 	if (fs) {
 		read_lock(&fs->lock);
 		*mnt = mntget(fs->pwdmnt);
@@ -109,11 +115,11 @@
 {
 	struct fs_struct *fs;
 	int result = -ENOENT;
-	task_lock(inode->u.proc_i.task);
-	fs = inode->u.proc_i.task->fs;
+	task_lock(proc_task(inode));
+	fs = proc_task(inode)->fs;
 	if(fs)
 		atomic_inc(&fs->count);
-	task_unlock(inode->u.proc_i.task);
+	task_unlock(proc_task(inode));
 	if (fs) {
 		read_lock(&fs->lock);
 		*mnt = mntget(fs->rootmnt);
@@ -238,7 +244,7 @@
 			      size_t count, loff_t *ppos)
 {
 	struct inode * inode = file->f_dentry->d_inode;
-	struct task_struct *task = inode->u.proc_i.task;
+	struct task_struct *task = proc_task(inode);
 	ssize_t res;
 
 	res = proc_pid_read_maps(task, file, buf, count, ppos);
@@ -252,7 +258,7 @@
 extern struct seq_operations mounts_op;
 static int mounts_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *task = inode->u.proc_i.task;
+	struct task_struct *task = proc_task(inode);
 	int ret = seq_open(file, &mounts_op);
 
 	if (!ret) {
@@ -298,14 +304,14 @@
 	unsigned long page;
 	ssize_t length;
 	ssize_t end;
-	struct task_struct *task = inode->u.proc_i.task;
+	struct task_struct *task = proc_task(inode);
 
 	if (count > PROC_BLOCK_SIZE)
 		count = PROC_BLOCK_SIZE;
 	if (!(page = __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 
-	length = inode->u.proc_i.op.proc_read(task, (char*)page);
+	length = PROC_I(inode)->op.proc_read(task, (char*)page);
 
 	if (length < 0) {
 		free_page(page);
@@ -342,7 +348,7 @@
 static ssize_t mem_read(struct file * file, char * buf,
 			size_t count, loff_t *ppos)
 {
-	struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+	struct task_struct *task = proc_task(file->f_dentry->d_inode);
 	char *page;
 	unsigned long src = *ppos;
 	int copied = 0;
@@ -404,7 +410,7 @@
 {
 	int copied = 0;
 	char *page;
-	struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+	struct task_struct *task = proc_task(file->f_dentry->d_inode);
 	unsigned long dst = *ppos;
 
 	if (!MAY_PTRACE(task))
@@ -463,7 +469,7 @@
 	if (error)
 		goto out;
 
-	error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
+	error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
 	nd->last_type = LAST_BIND;
 out:
 	return error;
@@ -503,7 +509,7 @@
 	if (error)
 		goto out;
 
-	error = inode->u.proc_i.op.proc_get_link(inode, &de, &mnt);
+	error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
 	if (error)
 		goto out;
 
@@ -570,7 +576,7 @@
 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct task_struct *p = inode->u.proc_i.task;
+	struct task_struct *p = proc_task(inode);
 	unsigned int fd, pid, ino;
 	int retval;
 	char buf[NUMBUF];
@@ -598,6 +604,7 @@
 			task_unlock(p);
 			if (!files)
 				goto out;
+			read_lock(&files->file_lock);
 			for (fd = filp->f_pos-2;
 			     fd < files->max_fds;
 			     fd++, filp->f_pos++) {
@@ -605,6 +612,7 @@
 
 				if (!fcheck_files(files, fd))
 					continue;
+				read_unlock(&files->file_lock);
 
 				j = NUMBUF;
 				i = fd;
@@ -617,7 +625,9 @@
 				ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
 				if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0)
 					break;
+				read_lock(&files->file_lock);
 			}
+			read_unlock(&files->file_lock);
 			put_files_struct(files);
 	}
 out:
@@ -632,7 +642,7 @@
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct pid_entry *p;
 
-	pid = inode->u.proc_i.task->pid;
+	pid = proc_task(inode)->pid;
 	if (!pid)
 		return -ENOENT;
 	i = filp->f_pos;
@@ -684,6 +694,7 @@
 static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
 {
 	struct inode * inode;
+	struct proc_inode *ei;
 
 	/* We need a new inode */
 	
@@ -692,7 +703,9 @@
 		goto out;
 
 	/* Common stuff */
-
+	ei = PROC_I(inode);
+	ei->task = NULL;
+	ei->file = NULL;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_ino = fake_ino(task->pid, ino);
 
@@ -703,7 +716,7 @@
 	 * grab the reference to task.
 	 */
 	get_task_struct(task);
-	inode->u.proc_i.task = task;
+	ei->task = task;
 	inode->i_uid = 0;
 	inode->i_gid = 0;
 	if (ino == PROC_PID_INO || task_dumpable(task)) {
@@ -733,7 +746,7 @@
  */
 static int pid_base_revalidate(struct dentry * dentry, int flags)
 {
-	if (dentry->d_inode->u.proc_i.task->pid)
+	if (proc_task(dentry->d_inode)->pid)
 		return 1;
 	d_drop(dentry);
 	return 0;
@@ -767,10 +780,11 @@
 static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
 {
 	unsigned int fd, c;
-	struct task_struct *task = dir->u.proc_i.task;
+	struct task_struct *task = proc_task(dir);
 	struct file * file;
 	struct files_struct * files;
 	struct inode *inode;
+	struct proc_inode *ei;
 	const char *name;
 	int len;
 
@@ -792,6 +806,7 @@
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd);
 	if (!inode)
 		goto out;
+	ei = PROC_I(inode);
 	task_lock(task);
 	files = task->files;
 	if (files)
@@ -800,7 +815,7 @@
 	if (!files)
 		goto out_unlock;
 	read_lock(&files->file_lock);
-	file = inode->u.proc_i.file = fcheck_files(files, fd);
+	file = ei->file = fcheck_files(files, fd);
 	if (!file)
 		goto out_unlock2;
 	get_file(file);
@@ -809,7 +824,7 @@
 	inode->i_op = &proc_pid_link_inode_operations;
 	inode->i_size = 64;
 	inode->i_mode = S_IFLNK;
-	inode->u.proc_i.op.proc_get_link = proc_fd_link;
+	ei->op.proc_get_link = proc_fd_link;
 	if (file->f_mode & 1)
 		inode->i_mode |= S_IRUSR | S_IXUSR;
 	if (file->f_mode & 2)
@@ -844,8 +859,9 @@
 {
 	struct inode *inode;
 	int error;
-	struct task_struct *task = dir->u.proc_i.task;
+	struct task_struct *task = proc_task(dir);
 	struct pid_entry *p;
+	struct proc_inode *ei;
 
 	error = -ENOENT;
 	inode = NULL;
@@ -864,6 +880,7 @@
 	if (!inode)
 		goto out;
 
+	ei = PROC_I(inode);
 	inode->i_mode = p->mode;
 	/*
 	 * Yes, it does not scale. And it should not. Don't add
@@ -877,35 +894,35 @@
 			break;
 		case PROC_PID_EXE:
 			inode->i_op = &proc_pid_link_inode_operations;
-			inode->u.proc_i.op.proc_get_link = proc_exe_link;
+			ei->op.proc_get_link = proc_exe_link;
 			break;
 		case PROC_PID_CWD:
 			inode->i_op = &proc_pid_link_inode_operations;
-			inode->u.proc_i.op.proc_get_link = proc_cwd_link;
+			ei->op.proc_get_link = proc_cwd_link;
 			break;
 		case PROC_PID_ROOT:
 			inode->i_op = &proc_pid_link_inode_operations;
-			inode->u.proc_i.op.proc_get_link = proc_root_link;
+			ei->op.proc_get_link = proc_root_link;
 			break;
 		case PROC_PID_ENVIRON:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_environ;
+			ei->op.proc_read = proc_pid_environ;
 			break;
 		case PROC_PID_STATUS:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_status;
+			ei->op.proc_read = proc_pid_status;
 			break;
 		case PROC_PID_STAT:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_stat;
+			ei->op.proc_read = proc_pid_stat;
 			break;
 		case PROC_PID_CMDLINE:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_cmdline;
+			ei->op.proc_read = proc_pid_cmdline;
 			break;
 		case PROC_PID_STATM:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_statm;
+			ei->op.proc_read = proc_pid_statm;
 			break;
 		case PROC_PID_MAPS:
 			inode->i_fop = &proc_maps_operations;
@@ -913,7 +930,7 @@
 #ifdef CONFIG_SMP
 		case PROC_PID_CPU:
 			inode->i_fop = &proc_info_file_operations;
-			inode->u.proc_i.op.proc_read = proc_pid_cpu;
+			ei->op.proc_read = proc_pid_cpu;
 			break;
 #endif
 		case PROC_PID_MEM:
@@ -973,6 +990,7 @@
 	struct task_struct *task;
 	const char *name;
 	struct inode *inode;
+	struct proc_inode *ei;
 	int len;
 
 	pid = 0;
@@ -982,10 +1000,11 @@
 		inode = new_inode(dir->i_sb);
 		if (!inode)
 			return ERR_PTR(-ENOMEM);
+		ei = PROC_I(inode);
 		inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 		inode->i_ino = fake_ino(0, PROC_PID_INO);
-		inode->u.proc_i.file = NULL;
-		inode->u.proc_i.task = NULL;
+		ei->file = NULL;
+		ei->task = NULL;
 		inode->i_mode = S_IFLNK|S_IRWXUGO;
 		inode->i_uid = inode->i_gid = 0;
 		inode->i_size = 64;
@@ -1035,10 +1054,10 @@
 
 void proc_pid_delete_inode(struct inode *inode)
 {
-	if (inode->u.proc_i.file)
-		fput(inode->u.proc_i.file);
-	if (inode->u.proc_i.task)
-		free_task_struct(inode->u.proc_i.task);
+	if (PROC_I(inode)->file)
+		fput(PROC_I(inode)->file);
+	if (proc_task(inode))
+		free_task_struct(proc_task(inode));
 }
 
 #define PROC_NUMBUF 10
diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c
--- a/fs/proc/generic.c	Wed Feb  6 22:48:39 2002
+++ b/fs/proc/generic.c	Wed Feb  6 22:48:39 2002
@@ -58,7 +58,7 @@
 	char	*start;
 	struct proc_dir_entry * dp;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	dp = PDE(inode);
 	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 
@@ -128,7 +128,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	struct proc_dir_entry * dp;
 	
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	dp = PDE(inode);
 
 	if (!dp->write_proc)
 		return -EIO;
@@ -221,13 +221,13 @@
 
 static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
+	char *s=PDE(dentry->d_inode)->data;
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
 static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
+	char *s=PDE(dentry->d_inode)->data;
 	return vfs_follow_link(nd, s);
 }
 
@@ -264,7 +264,7 @@
 
 	error = -ENOENT;
 	inode = NULL;
-	de = (struct proc_dir_entry *) dir->u.generic_ip;
+	de = PDE(dir);
 	if (de) {
 		for (de = de->subdir; de ; de = de->next) {
 			if (!de || !de->low_ino)
@@ -306,7 +306,7 @@
 	struct inode *inode = filp->f_dentry->d_inode;
 
 	ino = inode->i_ino;
-	de = (struct proc_dir_entry *) inode->u.generic_ip;
+	de = PDE(inode);
 	if (!de)
 		return -EINVAL;
 	i = filp->f_pos;
@@ -413,7 +413,7 @@
 		if (dentry->d_op != &proc_dentry_operations)
 			continue;
 		inode = dentry->d_inode;
-		if (inode->u.generic_ip != de)
+		if (PDE(inode) != de)
 			continue;
 		fops = filp->f_op;
 		filp->f_op = NULL;
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/proc/inode.c	Wed Feb  6 22:48:39 2002
@@ -58,7 +58,7 @@
  */
 static void proc_delete_inode(struct inode *inode)
 {
-	struct proc_dir_entry *de = inode->u.generic_ip;
+	struct proc_dir_entry *de = PDE(inode);
 
 	inode->i_state = I_CLEAR;
 
@@ -91,14 +91,51 @@
 	return 0;
 }
 
+static kmem_cache_t * proc_inode_cachep;
+
+static struct inode *proc_alloc_inode(struct super_block *sb)
+{
+	struct proc_inode *ei;
+	ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void proc_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(proc_inode_cachep, PROC_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct proc_inode *ei = (struct proc_inode *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+int __init proc_init_inodecache(void)
+{
+	proc_inode_cachep = kmem_cache_create("proc_inode_cache",
+					     sizeof(struct proc_inode),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (proc_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 static struct super_operations proc_sops = { 
+	alloc_inode:	proc_alloc_inode,
+	destroy_inode:	proc_destroy_inode,
 	read_inode:	proc_read_inode,
 	put_inode:	force_delete,
 	delete_inode:	proc_delete_inode,
 	statfs:		proc_statfs,
 };
 
-
 static int parse_options(char *options,uid_t *uid,gid_t *gid)
 {
 	char *this_char,*value;
@@ -147,7 +184,7 @@
 	if (!inode)
 		goto out_fail;
 	
-	inode->u.generic_ip = (void *) de;
+	PROC_I(inode)->pde = de;
 	if (de) {
 		if (de->mode) {
 			inode->i_mode = de->mode;
@@ -176,8 +213,7 @@
 	goto out;
 }			
 
-struct super_block *proc_read_super(struct super_block *s,void *data, 
-				    int silent)
+int proc_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * root_inode;
 	struct task_struct *p;
@@ -200,11 +236,11 @@
 	if (!s->s_root)
 		goto out_no_root;
 	parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
-	return s;
+	return 0;
 
 out_no_root:
 	printk("proc_read_super: get root inode failed\n");
 	iput(root_inode);
-	return NULL;
+	return -ENOMEM;
 }
 MODULE_LICENSE("GPL");
diff -Nru a/fs/proc/root.c b/fs/proc/root.c
--- a/fs/proc/root.c	Wed Feb  6 22:48:39 2002
+++ b/fs/proc/root.c	Wed Feb  6 22:48:39 2002
@@ -23,11 +23,24 @@
 struct proc_dir_entry *proc_sys_root;
 #endif
 
-static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
+static struct super_block *proc_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, proc_fill_super);
+}
+
+static struct file_system_type proc_fs_type = {
+	name:		"proc",
+	get_sb:		proc_get_sb,
+};
 
+extern int __init proc_init_inodecache(void);
 void __init proc_root_init(void)
 {
-	int err = register_filesystem(&proc_fs_type);
+	int err = proc_init_inodecache();
+	if (err)
+		return;
+	err = register_filesystem(&proc_fs_type);
 	if (err)
 		return;
 	proc_mnt = kern_mount(&proc_fs_type);
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Wed Feb  6 22:48:39 2002
+++ b/fs/ramfs/inode.c	Wed Feb  6 22:48:39 2002
@@ -302,7 +302,7 @@
 	put_inode:	force_delete,
 };
 
-static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
+static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
 {
 	struct inode * inode;
 	struct dentry * root;
@@ -313,19 +313,33 @@
 	sb->s_op = &ramfs_ops;
 	inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
 	if (!inode)
-		return NULL;
+		return -ENOMEM;
 
 	root = d_alloc_root(inode);
 	if (!root) {
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root = root;
-	return sb;
+	return 0;
 }
 
-static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, FS_LITTER);
-static DECLARE_FSTYPE(rootfs_fs_type, "rootfs", ramfs_read_super, FS_NOMOUNT|FS_LITTER);
+static struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, ramfs_fill_super);
+}
+
+static struct file_system_type ramfs_fs_type = {
+	name:		"ramfs",
+	get_sb:		ramfs_get_sb,
+	fs_flags:	FS_LITTER,
+};
+static struct file_system_type rootfs_fs_type = {
+	name:		"rootfs",
+	get_sb:		ramfs_get_sb,
+	fs_flags:	FS_NOMOUNT|FS_LITTER,
+};
 
 static int __init init_ramfs_fs(void)
 {
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Wed Feb  6 22:48:38 2002
+++ b/fs/read_write.c	Wed Feb  6 22:48:38 2002
@@ -51,6 +51,31 @@
 	return retval;
 }
 
+loff_t remote_llseek(struct file *file, loff_t offset, int origin)
+{
+	long long retval;
+
+	lock_kernel();
+	switch (origin) {
+		case 2:
+			offset += file->f_dentry->d_inode->i_size;
+			break;
+		case 1:
+			offset += file->f_pos;
+	}
+	retval = -EINVAL;
+	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_reada = 0;
+			file->f_version = ++event;
+		}
+		retval = offset;
+	}
+	unlock_kernel();
+	return retval;
+}
+
 loff_t no_llseek(struct file *file, loff_t offset, int origin)
 {
 	return -ESPIPE;
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	Wed Feb  6 22:48:38 2002
+++ b/fs/reiserfs/dir.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/fix_node.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/inode.c	Wed Feb  6 22:48:39 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,15 @@
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
     inode->i_blksize = PAGE_SIZE;
 
+    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;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
+    /* nopack = 0, by default */
+    REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
+
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
 	unsigned long blocks;
@@ -947,13 +957,6 @@
 	    set_inode_item_key_version (inode, KEY_FORMAT_3_6);
 	REISERFS_I(inode)->i_first_direct_byte = 0;
     }
-    REISERFS_I(inode)->i_flags = 0;
-    REISERFS_I(inode)->i_prealloc_block = 0;
-    REISERFS_I(inode)->i_prealloc_count = 0;
-    REISERFS_I(inode)->i_trans_id = 0;
-    REISERFS_I(inode)->i_trans_index = 0;
-    /* nopack = 0, by default */
-    REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -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	Wed Feb  6 22:48:38 2002
+++ b/fs/reiserfs/journal.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 2002
+++ b/fs/reiserfs/namei.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/procfs.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/stree.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/super.c	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/fs/reiserfs/tail_conversion.c	Wed Feb  6 22:48:39 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/smbfs/file.c b/fs/smbfs/file.c
--- a/fs/smbfs/file.c	Wed Feb  6 22:48:39 2002
+++ b/fs/smbfs/file.c	Wed Feb  6 22:48:39 2002
@@ -381,7 +381,7 @@
 
 struct file_operations smb_file_operations =
 {
-	llseek:		generic_file_llseek,
+	llseek:		remote_llseek,
 	read:		smb_file_read,
 	write:		smb_file_write,
 	ioctl:		smb_ioctl,
diff -Nru a/fs/smbfs/sock.c b/fs/smbfs/sock.c
--- a/fs/smbfs/sock.c	Wed Feb  6 22:48:39 2002
+++ b/fs/smbfs/sock.c	Wed Feb  6 22:48:39 2002
@@ -176,7 +176,7 @@
 smb_valid_socket(struct inode * inode)
 {
 	return (inode && S_ISSOCK(inode->i_mode) && 
-		inode->u.socket_i.type == SOCK_STREAM);
+		SOCKET_I(inode)->type == SOCK_STREAM);
 }
 
 static struct socket *
@@ -190,7 +190,7 @@
 		if (!smb_valid_socket(file->f_dentry->d_inode))
 			PARANOIA("bad socket!\n");
 #endif
-		return &file->f_dentry->d_inode->u.socket_i;
+		return SOCKET_I(file->f_dentry->d_inode);
 	}
 	return NULL;
 }
diff -Nru a/fs/stat.c b/fs/stat.c
--- a/fs/stat.c	Wed Feb  6 22:48:39 2002
+++ b/fs/stat.c	Wed Feb  6 22:48:39 2002
@@ -25,68 +25,28 @@
 	return 0;
 }
 
-
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
-
-/*
- * For backward compatibility?  Maybe this should be moved
- * into arch/i386 instead?
- */
-static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
+static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
-	static int warncount = 5;
-	struct __old_kernel_stat tmp;
-
-	if (warncount > 0) {
-		warncount--;
-		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
-			current->comm);
-	} else if (warncount < 0) {
-		/* it's laughable, but... */
-		warncount = 0;
-	}
-
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	SET_OLDSTAT_UID(tmp, inode->i_uid);
-	SET_OLDSTAT_GID(tmp, inode->i_gid);
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-#if BITS_PER_LONG == 32
-	if (inode->i_size > MAX_NON_LFS)
-		return -EOVERFLOW;
-#endif	
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
-}
-
-#endif
-
-static int cp_new_stat(struct inode * inode, struct stat * statbuf)
-{
-	struct stat tmp;
+	int res = 0;
 	unsigned int blocks, indirect;
+	struct inode *inode = dentry->d_inode;
 
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	SET_STAT_UID(tmp, inode->i_uid);
-	SET_STAT_GID(tmp, inode->i_gid);
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-#if BITS_PER_LONG == 32
-	if (inode->i_size > MAX_NON_LFS)
-		return -EOVERFLOW;
-#endif	
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
+	res = do_revalidate(dentry);
+	if (res)
+		return res;
+
+	stat->dev = kdev_t_to_nr(inode->i_dev);
+	stat->ino = inode->i_ino;
+	stat->mode = inode->i_mode;
+	stat->nlink = inode->i_nlink;
+	stat->uid = inode->i_uid;
+	stat->gid = inode->i_gid;
+	stat->rdev = kdev_t_to_nr(inode->i_rdev);
+	stat->atime = inode->i_atime;
+	stat->mtime = inode->i_mtime;
+	stat->ctime = inode->i_ctime;
+	stat->ctime = inode->i_ctime;
+	stat->size = inode->i_size;
 /*
  * st_blocks and st_blksize are approximated with a simple algorithm if
  * they aren't supported directly by the filesystem. The minix and msdos
@@ -106,7 +66,7 @@
 #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
 
 	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+		blocks = (stat->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 		if (blocks > D_B) {
 			indirect = (blocks - D_B + I_B - 1) / I_B;
 			blocks += indirect;
@@ -117,130 +77,178 @@
 					blocks++;
 			}
 		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
+		stat->blocks = (BLOCK_SIZE / 512) * blocks;
+		stat->blksize = BLOCK_SIZE;
 	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
+		stat->blocks = inode->i_blocks;
+		stat->blksize = inode->i_blksize;
 	}
-	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+	return 0;
 }
 
-
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
-/*
- * For backward compatibility?  Maybe this should be moved
- * into arch/i386 instead?
- */
-asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
+int vfs_stat(char *name, struct kstat *stat)
 {
 	struct nameidata nd;
 	int error;
 
-	error = user_path_walk(filename, &nd);
+	error = user_path_walk(name, &nd);
 	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_old_stat(nd.dentry->d_inode, statbuf);
+		error = do_getattr(nd.mnt, nd.dentry, stat);
 		path_release(&nd);
 	}
 	return error;
 }
-#endif
 
-asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
+int vfs_lstat(char *name, struct kstat *stat)
 {
 	struct nameidata nd;
 	int error;
 
-	error = user_path_walk(filename, &nd);
+	error = user_path_walk_link(name, &nd);
 	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat(nd.dentry->d_inode, statbuf);
+		error = do_getattr(nd.mnt, nd.dentry, stat);
 		path_release(&nd);
 	}
 	return error;
 }
 
+int vfs_fstat(unsigned int fd, struct kstat *stat)
+{
+	struct file *f = fget(fd);
+	int error = -EBADF;
+
+	if (f) {
+		error = do_getattr(f->f_vfsmnt, f->f_dentry, stat);
+		fput(f);
+	}
+	return error;
+}
+
 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
  */
-asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
+static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat * statbuf)
 {
-	struct nameidata nd;
-	int error;
+	static int warncount = 5;
+	struct __old_kernel_stat tmp;
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_old_stat(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
+	if (warncount > 0) {
+		warncount--;
+		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+			current->comm);
+	} else if (warncount < 0) {
+		/* it's laughable, but... */
+		warncount = 0;
 	}
-	return error;
-}
 
-#endif
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_OLDSTAT_UID(tmp, stat->uid);
+	SET_OLDSTAT_GID(tmp, stat->gid);
+	tmp.st_rdev = stat->rdev;
+#if BITS_PER_LONG == 32
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+#endif	
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
 
-asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
+asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_old_stat(&stat, statbuf);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
+asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
+	if (!error)
+		error = cp_old_stat(&stat, statbuf);
 
-/*
- * For backward compatibility?  Maybe this should be moved
- * into arch/i386 instead?
- */
+	return error;
+}
 asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
+	if (!error)
+		error = cp_old_stat(&stat, statbuf);
 
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_old_stat(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	return error;
 }
 
 #endif
 
+static int cp_new_stat(struct kstat *stat, struct stat *statbuf)
+{
+	struct stat tmp;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_STAT_UID(tmp, stat->uid);
+	SET_STAT_GID(tmp, stat->gid);
+	tmp.st_rdev = stat->rdev;
+#if BITS_PER_LONG == 32
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+#endif	
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	tmp.st_blocks = stat->blocks;
+	tmp.st_blksize = stat->blksize;
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat(&stat, statbuf);
+
+	return error;
+}
+asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat(&stat, statbuf);
+
+	return error;
+}
 asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
+	if (!error)
+		error = cp_new_stat(&stat, statbuf);
 
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	return error;
 }
 
 asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
@@ -270,110 +278,59 @@
 /* ---------- LFS-64 ----------- */
 #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X)
 
-static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
+static long cp_new_stat64(struct kstat *stat, struct stat64 *statbuf)
 {
 	struct stat64 tmp;
-	unsigned int blocks, indirect;
 
 	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
 #ifdef STAT64_HAS_BROKEN_ST_INO
-	tmp.__st_ino = inode->i_ino;
+	tmp.__st_ino = stat->ino;
 #endif
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	tmp.st_uid = inode->i_uid;
-	tmp.st_gid = inode->i_gid;
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-	tmp.st_size = inode->i_size;
-/*
- * st_blocks and st_blksize are approximated with a simple algorithm if
- * they aren't supported directly by the filesystem. The minix and msdos
- * filesystems don't keep track of blocks, so they would either have to
- * be counted explicitly (by delving into the file itself), or by using
- * this simple algorithm to get a reasonable (although not 100% accurate)
- * value.
- */
-
-/*
- * Use minix fs values for the number of direct and indirect blocks.  The
- * count is now exact for the minix fs except that it counts zero blocks.
- * Everything is in units of BLOCK_SIZE until the assignment to
- * tmp.st_blksize.
- */
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-
-	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
-		if (blocks > D_B) {
-			indirect = (blocks - D_B + I_B - 1) / I_B;
-			blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				blocks += indirect;
-				if (indirect > 1)
-					blocks++;
-			}
-		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
-	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
-	}
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	tmp.st_uid = stat->uid;
+	tmp.st_gid = stat->gid;
+	tmp.st_rdev = stat->rdev;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
+	tmp.st_size = stat->size;
+	tmp.st_blocks = stat->blocks;
+	tmp.st_blksize = stat->blksize;
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
 asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat64(&stat, statbuf);
 
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat64(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
-
 asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+
+	if (!error)
+		error = cp_new_stat64(&stat, statbuf);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat64(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
-
 asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
 {
-	struct file * f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
+	if (!error)
+		error = cp_new_stat64(&stat, statbuf);
 
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat64(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	return error;
 }
 
 #endif /* LFS-64 */
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Wed Feb  6 22:48:39 2002
+++ b/fs/super.c	Wed Feb  6 22:48:39 2002
@@ -641,8 +641,9 @@
 	return s;
 }
 
-static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
-	int flags, char *dev_name, void * data)
+struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+	int flags, char *dev_name, void * data,
+	int (*fill_super)(struct super_block *, void *, int))
 {
 	struct inode *inode;
 	struct block_device *bdev;
@@ -698,7 +699,7 @@
 
 	list_for_each(p, &super_blocks) {
 		struct super_block *old = sb_entry(p);
-		if (!kdev_same(old->s_dev, dev))
+		if (old->s_bdev != bdev)
 			continue;
 		if (old->s_type != fs_type ||
 		    ((flags ^ old->s_flags) & MS_RDONLY)) {
@@ -718,8 +719,8 @@
 	s->s_flags = flags;
 	insert_super(s, fs_type);
 	strncpy(s->s_id, bdevname(dev), sizeof(s->s_id));
-	error = -EINVAL;
-	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
+	error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+	if (error)
 		goto failed;
 	s->s_flags |= MS_ACTIVE;
 	path_release(&nd);
@@ -736,19 +737,23 @@
 	return ERR_PTR(error);
 }
 
-static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
-	int flags, char *dev_name, void *data)
+struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+	int flags, void *data,
+	int (*fill_super)(struct super_block *, void *, int))
 {
+	int error;
 	struct super_block *s = get_anon_super(fs_type, NULL, NULL);
 
 	if (IS_ERR(s))
 		return s;
 
 	s->s_flags = flags;
-	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+
+	error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+	if (error) {
 		deactivate_super(s);
 		remove_super(s);
-		return ERR_PTR(-EINVAL);
+		return ERR_PTR(error);
 	}
 	s->s_flags |= MS_ACTIVE;
 	return s;
@@ -759,19 +764,22 @@
 	return 1;
 }
 
-static struct super_block *get_sb_single(struct file_system_type *fs_type,
-	int flags, char *dev_name, void *data)
+struct super_block *get_sb_single(struct file_system_type *fs_type,
+	int flags, void *data,
+	int (*fill_super)(struct super_block *, void *, int))
 {
+	int error;
 	struct super_block *s = get_anon_super(fs_type, compare_single, NULL);
 
 	if (IS_ERR(s))
 		return s;
 	if (!s->s_root) {
 		s->s_flags = flags;
-		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+		error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+		if (error) {
 			deactivate_super(s);
 			remove_super(s);
-			return ERR_PTR(-EINVAL);
+			return ERR_PTR(error);
 		}
 		s->s_flags |= MS_ACTIVE;
 	}
@@ -779,6 +787,22 @@
 	return s;
 }
 
+/* Will go away */
+static int fill_super(struct super_block *sb, void *data, int verbose)
+{
+	return sb->s_type->read_super(sb, data, verbose) ? 0 : -EINVAL;
+}
+static struct super_block *__get_sb_bdev(struct file_system_type *fs_type,
+	int flags, char *dev_name, void * data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, fill_super);
+}
+static struct super_block *__get_sb_nodev(struct file_system_type *fs_type,
+	int flags, char *dev_name, void * data)
+{
+	return get_sb_nodev(fs_type, flags, data, fill_super);
+}
+
 struct vfsmount *
 do_kern_mount(const char *fstype, int flags, char *name, void *data)
 {
@@ -792,12 +816,12 @@
 	mnt = alloc_vfsmnt(name);
 	if (!mnt)
 		goto out;
-	if (type->fs_flags & FS_REQUIRES_DEV)
-		sb = get_sb_bdev(type, flags, name, data);
-	else if (type->fs_flags & FS_SINGLE)
-		sb = get_sb_single(type, flags, name, data);
+	if (type->get_sb)
+		sb = type->get_sb(type, flags, name, data);
+	else if (type->fs_flags & FS_REQUIRES_DEV)
+		sb = __get_sb_bdev(type, flags, name, data);
 	else
-		sb = get_sb_nodev(type, flags, name, data);
+		sb = __get_sb_nodev(type, flags, name, data);
 	if (IS_ERR(sb))
 		goto out_mnt;
 	if (type->fs_flags & FS_NOMOUNT)
diff -Nru a/fs/udf/super.c b/fs/udf/super.c
--- a/fs/udf/super.c	Wed Feb  6 22:48:38 2002
+++ b/fs/udf/super.c	Wed Feb  6 22:48:38 2002
@@ -1544,7 +1544,7 @@
 		iput(inode);
 		goto error_out;
 	}
-	sb->s_maxbytes = ~0ULL;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	return sb;
 
 error_out:
diff -Nru a/fs/ufs/file.c b/fs/ufs/file.c
--- a/fs/ufs/file.c	Wed Feb  6 22:48:39 2002
+++ b/fs/ufs/file.c	Wed Feb  6 22:48:39 2002
@@ -35,40 +35,7 @@
 #include <linux/locks.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-
-/*
- * Make sure the offset never goes beyond the 32-bit mark..
- */
-static long long ufs_file_lseek(
-	struct file *file,
-	long long offset,
-	int origin )
-{
-	long long retval;
-	struct inode *inode = file->f_dentry->d_inode;
-
-	lock_kernel();
-
-	switch (origin) {
-		case 2:
-			offset += inode->i_size;
-			break;
-		case 1:
-			offset += file->f_pos;
-	}
-	retval = -EINVAL;
-	/* make sure the offset fits in 32 bits */
-	if (((unsigned long long) offset >> 32) == 0) {
-		if (offset != file->f_pos) {
-			file->f_pos = offset;
-			file->f_reada = 0;
-			file->f_version = ++event;
-		}
-		retval = offset;
-	}
-	unlock_kernel();
-	return retval;
-}
+#include <linux/smp_lock.h>
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -76,7 +43,7 @@
  */
  
 struct file_operations ufs_file_operations = {
-	llseek:		ufs_file_lseek,
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	write:		generic_file_write,
 	mmap:		generic_file_mmap,
diff -Nru a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h
--- a/include/asm-alpha/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-alpha/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
--- a/include/asm-alpha/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-alpha/unistd.h	Wed Feb  6 22:48:39 2002
@@ -318,6 +318,7 @@
 #define __NR_gettid			378
 #define __NR_readahead			379
 #define __NR_security			380 /* syscall for security modules */
+#define __NR_tkill			381
 
 #if defined(__GNUC__)
 
diff -Nru a/include/asm-arm/siginfo.h b/include/asm-arm/siginfo.h
--- a/include/asm-arm/siginfo.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-arm/siginfo.h	Wed Feb  6 22:48:38 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL        -6              /* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-cris/siginfo.h b/include/asm-cris/siginfo.h
--- a/include/asm-cris/siginfo.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-cris/siginfo.h	Wed Feb  6 22:48:38 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h
--- a/include/asm-cris/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-cris/unistd.h	Wed Feb  6 22:48:39 2002
@@ -230,6 +230,7 @@
 #define __NR_security           223     /* syscall for security modules */
 #define __NR_gettid             224
 #define __NR_readahead          225
+#define __NR_tkill              226
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h
--- a/include/asm-i386/pci.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-i386/pci.h	Wed Feb  6 22:48:39 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-i386/siginfo.h b/include/asm-i386/siginfo.h
--- a/include/asm-i386/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-i386/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-i386/unistd.h	Wed Feb  6 22:48:38 2002
@@ -242,6 +242,7 @@
 #define __NR_removexattr	235
 #define __NR_lremovexattr	236
 #define __NR_fremovexattr	237
+#define __NR_tkill		238
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -Nru a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h
--- a/include/asm-ia64/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-ia64/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -124,6 +124,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-ia64/unistd.h	Wed Feb  6 22:48:38 2002
@@ -206,6 +206,7 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
+#define __NR_tkill			1217
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Nru a/include/asm-m68k/siginfo.h b/include/asm-m68k/siginfo.h
--- a/include/asm-m68k/siginfo.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-m68k/siginfo.h	Wed Feb  6 22:48:38 2002
@@ -117,6 +117,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
--- a/include/asm-m68k/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-m68k/unistd.h	Wed Feb  6 22:48:39 2002
@@ -222,6 +222,8 @@
 #define __NR_setfsuid32		215
 #define __NR_setfsgid32		216
 #define __NR_getdents64		220
+#define __NR_gettid		221
+#define __NR_tkill		222
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -Nru a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h
--- a/include/asm-mips/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-mips/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -127,6 +127,7 @@
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
--- a/include/asm-mips/unistd.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-mips/unistd.h	Wed Feb  6 22:48:38 2002
@@ -233,6 +233,8 @@
 #define __NR_madvise			(__NR_Linux + 218)
 #define __NR_getdents64			(__NR_Linux + 219)
 #define __NR_fcntl64			(__NR_Linux + 220)
+#define __NR_gettid			(__NR_Linux + 221)
+#define __NR_tkill			(__NR_Linux + 222)
 
 /*
  * Offset of the last Linux flavoured syscall
diff -Nru a/include/asm-mips64/siginfo.h b/include/asm-mips64/siginfo.h
--- a/include/asm-mips64/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-mips64/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -127,6 +127,7 @@
 #define SI_TIMER __SI_CODE(__SI_TIMER,-3) /* sent by timer expiration */
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-mips64/unistd.h b/include/asm-mips64/unistd.h
--- a/include/asm-mips64/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-mips64/unistd.h	Wed Feb  6 22:48:39 2002
@@ -461,11 +461,13 @@
 #define __NR_mincore			(__NR_Linux + 211)
 #define __NR_madvise			(__NR_Linux + 212)
 #define __NR_getdents64			(__NR_Linux + 213)
+#define __NR_gettid			(__NR_Linux + 214)
+#define __NR_tkill			(__NR_Linux + 215)
 
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls		213
+#define __NR_Linux_syscalls		215
 
 #ifndef _LANGUAGE_ASSEMBLY
 
diff -Nru a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
--- a/include/asm-parisc/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-parisc/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
--- a/include/asm-parisc/unistd.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-parisc/unistd.h	Wed Feb  6 22:48:38 2002
@@ -689,8 +689,10 @@
 
 #define __NR_getpmsg            (__NR_Linux + 196)      /* some people actually want streams */
 #define __NR_putpmsg            (__NR_Linux + 197)      /* some people actually want streams */
+#define __NR_gettid             (__NR_Linux + 198)
+#define __NR_tkill              (__NR_Linux + 199)
 
-#define __NR_Linux_syscalls     197
+#define __NR_Linux_syscalls     199
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
diff -Nru a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
--- a/include/asm-ppc/siginfo.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-ppc/siginfo.h	Wed Feb  6 22:48:38 2002
@@ -108,6 +108,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-ppc/unistd.h	Wed Feb  6 22:48:39 2002
@@ -215,6 +215,7 @@
 #define __NR_madvise		205
 #define __NR_mincore		206
 #define __NR_gettid		207
+#define __NR_tkill		208
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h
--- a/include/asm-s390/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-s390/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -115,6 +115,7 @@
 #define SI_MESGQ	-3	/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
--- a/include/asm-s390/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-s390/unistd.h	Wed Feb  6 22:48:39 2002
@@ -211,6 +211,8 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64		220
+#define __NR_gettid		226
+#define __NR_tkill		227
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
diff -Nru a/include/asm-s390x/siginfo.h b/include/asm-s390x/siginfo.h
--- a/include/asm-s390x/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-s390x/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -115,6 +115,7 @@
 #define SI_MESGQ	-3	/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
+#define SI_TKILL	-6	/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-s390x/unistd.h b/include/asm-s390x/unistd.h
--- a/include/asm-s390x/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-s390x/unistd.h	Wed Feb  6 22:48:39 2002
@@ -181,6 +181,8 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64         220
+#define __NR_gettid		226
+#define __NR_tkill 	        227
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
diff -Nru a/include/asm-sh/siginfo.h b/include/asm-sh/siginfo.h
--- a/include/asm-sh/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sh/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -107,6 +107,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
--- a/include/asm-sh/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sh/unistd.h	Wed Feb  6 22:48:39 2002
@@ -231,6 +231,8 @@
 #define __NR_madvise		219
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
+#define __NR_gettid		222
+#define __NR_tkill		223
 
 /* user-visible error numbers are in the range -1 - -125: see <asm-sh/errno.h> */
 
diff -Nru a/include/asm-sparc/siginfo.h b/include/asm-sparc/siginfo.h
--- a/include/asm-sparc/siginfo.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-sparc/siginfo.h	Wed Feb  6 22:48:38 2002
@@ -112,6 +112,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Wed Feb  6 22:48:38 2002
+++ b/include/asm-sparc/unistd.h	Wed Feb  6 22:48:38 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                              */
@@ -271,6 +271,7 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_tkill              257
 
 #define _syscall0(type,name) \
 type name(void) \
diff -Nru a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
--- a/include/asm-sparc64/bitops.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sparc64/bitops.h	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sparc64/mmu_context.h	Wed Feb  6 22:48:39 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/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h
--- a/include/asm-sparc64/siginfo.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sparc64/siginfo.h	Wed Feb  6 22:48:39 2002
@@ -172,6 +172,7 @@
 #define SI_MESGQ	-3		/* sent by real time mesq state change */
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
+#define SI_TKILL	-6		/* sent by tkill system call */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Wed Feb  6 22:48:39 2002
+++ b/include/asm-sparc64/unistd.h	Wed Feb  6 22:48:39 2002
@@ -273,6 +273,7 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_tkill              256
 
 #define _syscall0(type,name) \
 type name(void) \
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/device.h	Wed Feb  6 22:48:39 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/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/fs.h	Wed Feb  6 22:48:39 2002
@@ -91,7 +91,6 @@
 #define FS_NO_PRELIM	4 /* prevent preloading of dentries, even if
 			   * FS_NO_DCACHE is not set.
 			   */
-#define FS_SINGLE	8 /* Filesystem that can have only one superblock */
 #define FS_NOMOUNT	16 /* Never mount from userland */
 #define FS_LITTER	32 /* Keeps the tree in dcache */
 #define FS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
@@ -208,6 +207,7 @@
 extern void buffer_init(unsigned long);
 extern void inode_init(unsigned long);
 extern void mnt_init(unsigned long);
+extern void files_init(unsigned long);
 
 /* bh state bits */
 enum bh_state_bits {
@@ -289,7 +289,6 @@
 #include <linux/pipe_fs_i.h>
 /* #include <linux/umsdos_fs_i.h> */
 #include <linux/romfs_fs_i.h>
-#include <linux/proc_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
 /*
@@ -455,12 +454,25 @@
 	union {
 		/* struct umsdos_inode_info	umsdos_i; */
 		struct romfs_inode_info		romfs_i;
-		struct proc_inode_info		proc_i;
-		struct socket			socket_i;
 		void				*generic_ip;
 	} u;
 };
 
+struct socket_alloc {
+	struct socket socket;
+	struct inode vfs_inode;
+};
+
+static inline struct socket *SOCKET_I(struct inode *inode)
+{
+	return &list_entry(inode, struct socket_alloc, vfs_inode)->socket;
+}
+
+static inline struct inode *SOCK_INODE(struct socket *socket)
+{
+	return &list_entry(socket, struct socket_alloc, socket)->vfs_inode;
+}
+
 #include <linux/shmem_fs.h>
 /* will die */
 #include <linux/coda_fs_i.h>
@@ -507,6 +519,14 @@
 
 #define	MAX_NON_LFS	((1UL<<31) - 1)
 
+/* Page cache limit. The filesystems should put that into their s_maxbytes 
+   limits, otherwise bad things can happen in VM. */ 
+#if BITS_PER_LONG==32
+#define MAX_LFS_FILESIZE	(((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
+#elif BITS_PER_LONG==64
+#define MAX_LFS_FILESIZE 	0x7fffffffffffffff
+#endif
+
 #define FL_POSIX	1
 #define FL_FLOCK	2
 #define FL_BROKEN	4	/* broken flock() emulation */
@@ -914,15 +934,36 @@
 	int (*transfer) (struct inode *, struct iattr *);
 };
 
+/*
+ *		NOTE NOTE NOTE
+ *
+ *	->read_super() is going to die.  New method (->get_sb) should replace
+ * it.  The only reason why ->read_super() is left for _SHORT_ transition
+ * period is to avoid a single patch touching every fs.  They will be
+ * converted one-by-one and ONCE THAT IS DONE OR TWO WEEKS HAD PASSED
+ * (whatever sooner) ->read_super() WILL DISAPPEAR.  
+ */
+
 struct file_system_type {
 	const char *name;
 	int fs_flags;
+	struct super_block *(*get_sb) (struct file_system_type *, int, char *, void *);
 	struct super_block *(*read_super) (struct super_block *, void *, int);
 	struct module *owner;
 	struct file_system_type * next;
 	struct list_head fs_supers;
 };
 
+struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+	int flags, char *dev_name, void * data,
+	int (*fill_super)(struct super_block *, void *, int));
+struct super_block *get_sb_single(struct file_system_type *fs_type,
+	int flags, void *data,
+	int (*fill_super)(struct super_block *, void *, int));
+struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+	int flags, void *data,
+	int (*fill_super)(struct super_block *, void *, int));
+
 #define DECLARE_FSTYPE(var,type,read,flags) \
 struct file_system_type var = { \
 	name:		type, \
@@ -1449,6 +1490,7 @@
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
+extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
 extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 
@@ -1463,6 +1505,10 @@
 extern int vfs_readdir(struct file *, filldir_t, void *);
 extern int dcache_readdir(struct file *, void *, filldir_t);
 
+extern int vfs_stat(char *, struct kstat *);
+extern int vfs_lstat(char *, struct kstat *);
+extern int vfs_fstat(unsigned int, struct kstat *);
+
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
 extern void drop_super(struct super_block *sb);
@@ -1475,8 +1521,6 @@
 	}
 	return 0;
 }
-unsigned long generate_cluster(kdev_t, int b[], int);
-unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
 extern char root_device_name[];
 
diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/gameport.h	Wed Feb  6 22:48:39 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/hpfs_fs_sb.h b/include/linux/hpfs_fs_sb.h
--- a/include/linux/hpfs_fs_sb.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/hpfs_fs_sb.h	Wed Feb  6 22:48:39 2002
@@ -30,9 +30,8 @@
 					/*	128 bytes lowercasing table */
 	unsigned *sb_bmp_dir;		/* main bitmap directory */
 	unsigned sb_c_bitmap;		/* current bitmap */
-	wait_queue_head_t sb_creation_de;/* when creating dirents, nobody else
+	struct semaphore hpfs_creation_de; /* when creating dirents, nobody else
 					   can alloc blocks */
-	unsigned sb_creation_de_lock : 1;
 	/*unsigned sb_mounting : 1;*/
 	int sb_timeshift;
 };
@@ -60,8 +59,6 @@
 #define s_hpfs_cp_table u.hpfs_sb.sb_cp_table
 #define s_hpfs_bmp_dir u.hpfs_sb.sb_bmp_dir
 #define s_hpfs_c_bitmap u.hpfs_sb.sb_c_bitmap
-#define s_hpfs_creation_de u.hpfs_sb.sb_creation_de
-#define s_hpfs_creation_de_lock u.hpfs_sb.sb_creation_de_lock
 #define s_hpfs_iget_q u.hpfs_sb.sb_iget_q
 /*#define s_hpfs_mounting u.hpfs_sb.sb_mounting*/
 #define s_hpfs_timeshift u.hpfs_sb.sb_timeshift
diff -Nru a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/net.h	Wed Feb  6 22:48:39 2002
@@ -23,6 +23,7 @@
 #include <linux/wait.h>
 
 struct poll_table_struct;
+struct inode;
 
 #define NPROTO		32		/* should be enough for now..	*/
 
@@ -68,7 +69,6 @@
 
 	unsigned long		flags;
 	struct proto_ops	*ops;
-	struct inode		*inode;
 	struct fasync_struct	*fasync_list;	/* Asynchronous wake up list	*/
 	struct file		*file;		/* File back pointer for gc	*/
 	struct sock		*sk;
@@ -77,8 +77,6 @@
 	short			type;
 	unsigned char		passcred;
 };
-
-#define SOCK_INODE(S)	((S)->inode)
 
 struct scm_cookie;
 struct vm_area_struct;
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/nfs_fs.h	Wed Feb  6 22:48:39 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)
@@ -226,7 +226,6 @@
 /*
  * linux/fs/nfs/inode.c
  */
-extern struct super_block *nfs_read_super(struct super_block *, void *, int);
 extern void nfs_zap_caches(struct inode *);
 extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
 				struct nfs_fattr *);
@@ -250,7 +249,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	Wed Feb  6 22:48:38 2002
+++ b/include/linux/nfs_page.h	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:39 2002
+++ b/include/linux/pci.h	Wed Feb  6 22:48:39 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/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Wed Feb  6 22:48:38 2002
+++ b/include/linux/proc_fs.h	Wed Feb  6 22:48:38 2002
@@ -97,7 +97,7 @@
 extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
 
 extern struct vfsmount *proc_mnt;
-extern struct super_block *proc_read_super(struct super_block *,void *,int);
+extern int proc_fill_super(struct super_block *,void *,int);
 extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
 
 extern int proc_match(int, const char *,struct proc_dir_entry *);
@@ -204,5 +204,27 @@
 extern struct proc_dir_entry proc_root;
 
 #endif /* CONFIG_PROC_FS */
+
+struct proc_inode {
+	struct task_struct *task;
+	int type;
+	union {
+		int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
+		int (*proc_read)(struct task_struct *task, char *page);
+	} op;
+	struct file *file;
+	struct proc_dir_entry *pde;
+	struct inode vfs_inode;
+};
+
+static inline struct proc_inode *PROC_I(struct inode *inode)
+{
+	return list_entry(inode, struct proc_inode, vfs_inode);
+}
+
+static inline struct proc_dir_entry *PDE(struct inode *inode)
+{
+	return PROC_I(inode)->pde;
+}
 
 #endif /* _LINUX_PROC_FS_H */
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/reiserfs_fs.h	Wed Feb  6 22:48:39 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	Wed Feb  6 22:48:39 2002
+++ b/include/linux/reiserfs_fs_sb.h	Wed Feb  6 22:48:39 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/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Wed Feb  6 22:48:38 2002
+++ b/include/linux/sched.h	Wed Feb  6 22:48:38 2002
@@ -564,6 +564,7 @@
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *);
+extern void sig_exit(int, int, struct siginfo *);
 extern int dequeue_signal(sigset_t *, siginfo_t *);
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
@@ -839,8 +840,13 @@
 #define for_each_task(p) \
 	for (p = &init_task ; (p = p->next_task) != &init_task ; )
 
+#define for_each_thread(task) \
+	for (task = next_thread(current) ; task != current ; task = next_thread(task))
+
 #define next_thread(p) \
 	list_entry((p)->thread_group.next, struct task_struct, thread_group)
+
+#define thread_group_leader(p)	(p->pid == p->tgid)
 
 static inline void unhash_process(struct task_struct *p)
 {
diff -Nru a/include/linux/stat.h b/include/linux/stat.h
--- a/include/linux/stat.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/stat.h	Wed Feb  6 22:48:39 2002
@@ -52,6 +52,25 @@
 #define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROTH)
 #define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)
 #define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)
+
+#include <linux/types.h>
+
+struct kstat {
+	unsigned long	ino;
+	dev_t		dev;
+	umode_t		mode;
+	nlink_t		nlink;
+	uid_t		uid;
+	gid_t		gid;
+	dev_t		rdev;
+	loff_t		size;
+	time_t		atime;
+	time_t		mtime;
+	time_t		ctime;
+	unsigned long	blksize;
+	unsigned long	blocks;
+};
+
 #endif
 
 #endif
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Wed Feb  6 22:48:39 2002
+++ b/include/linux/usb.h	Wed Feb  6 22:48:39 2002
@@ -857,7 +857,7 @@
 extern void usb_free_urb(struct urb *urb);
 #define usb_put_urb usb_free_urb
 extern struct urb *usb_get_urb(struct urb *urb);
-extern int usb_submit_urb(struct urb *urb);
+extern int usb_submit_urb(struct urb *urb, int mem_flags);
 extern int usb_unlink_urb(struct urb *urb);
 
 /*-------------------------------------------------------------------*
@@ -906,7 +906,7 @@
 	int (*allocate)(struct usb_device *);
 	int (*deallocate)(struct usb_device *);
 	int (*get_frame_number) (struct usb_device *usb_dev);
-	int (*submit_urb) (struct urb *urb);
+	int (*submit_urb) (struct urb *urb, int mem_flags);
 	int (*unlink_urb) (struct urb *urb);
 };
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Wed Feb  6 22:48:39 2002
+++ b/include/net/sock.h	Wed Feb  6 22:48:39 2002
@@ -1022,7 +1022,7 @@
 	int uid;
 
 	read_lock(&sk->callback_lock);
-	uid = sk->socket ? sk->socket->inode->i_uid : 0;
+	uid = sk->socket ? SOCK_INODE(sk->socket)->i_uid : 0;
 	read_unlock(&sk->callback_lock);
 	return uid;
 }
@@ -1032,7 +1032,7 @@
 	unsigned long ino;
 
 	read_lock(&sk->callback_lock);
-	ino = sk->socket ? sk->socket->inode->i_ino : 0;
+	ino = sk->socket ? SOCK_INODE(sk->socket)->i_ino : 0;
 	read_unlock(&sk->callback_lock);
 	return ino;
 }
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Wed Feb  6 22:48:39 2002
+++ b/init/main.c	Wed Feb  6 22:48:39 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/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Wed Feb  6 22:48:38 2002
+++ b/kernel/fork.c	Wed Feb  6 22:48:38 2002
@@ -724,10 +724,10 @@
 	/* Need tasklist lock for parent etc handling! */
 	write_lock_irq(&tasklist_lock);
 
-	/* CLONE_PARENT and CLONE_THREAD re-use the old parent */
+	/* CLONE_PARENT re-uses the old parent */
 	p->p_opptr = current->p_opptr;
 	p->p_pptr = current->p_pptr;
-	if (!(clone_flags & (CLONE_PARENT | CLONE_THREAD))) {
+	if (!(clone_flags & CLONE_PARENT)) {
 		p->p_opptr = current;
 		if (!(p->ptrace & PT_PTRACED))
 			p->p_pptr = current;
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Wed Feb  6 22:48:38 2002
+++ b/kernel/ksyms.c	Wed Feb  6 22:48:38 2002
@@ -251,6 +251,7 @@
 EXPORT_SYMBOL(vfs_statfs);
 EXPORT_SYMBOL(generic_read_dir);
 EXPORT_SYMBOL(generic_file_llseek);
+EXPORT_SYMBOL(remote_llseek);
 EXPORT_SYMBOL(no_llseek);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(poll_freewait);
@@ -274,6 +275,9 @@
 EXPORT_SYMBOL(dcache_readdir);
 EXPORT_SYMBOL(fd_install);
 EXPORT_SYMBOL(put_unused_fd);
+EXPORT_SYMBOL(get_sb_bdev);
+EXPORT_SYMBOL(get_sb_nodev);
+EXPORT_SYMBOL(get_sb_single);
 
 /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
 EXPORT_SYMBOL(default_llseek);
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Wed Feb  6 22:48:39 2002
+++ b/kernel/signal.c	Wed Feb  6 22:48:39 2002
@@ -142,6 +142,35 @@
 	}
 }
 
+/*
+ * sig_exit - cause the current task to exit due to a signal.
+ */
+
+void
+sig_exit(int sig, int exit_code, struct siginfo *info)
+{
+	struct task_struct *t;
+
+	sigaddset(&current->pending.signal, sig);
+	recalc_sigpending(current);
+	current->flags |= PF_SIGNALED;
+
+	/* Propagate the signal to all the tasks in
+	 *  our thread group
+	 */
+	if (info && (unsigned long)info != 1
+	    && info->si_code != SI_TKILL) {
+		read_lock(&tasklist_lock);
+		for_each_thread(t) {
+			force_sig_info(sig, info, t);
+		}
+		read_unlock(&tasklist_lock);
+	}
+
+	do_exit(exit_code);
+	/* NOTREACHED */
+}
+
 /* Notify the system that a driver wants to block all signals for this
  * process, and wants to be notified if any signals at all were to be
  * sent/acted upon.  If the notifier routine returns non-zero, then the
@@ -589,7 +618,7 @@
 		retval = -ESRCH;
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pgrp == pgrp) {
+			if (p->pgrp == pgrp && thread_group_leader(p)) {
 				int err = send_sig_info(sig, info, p);
 				if (retval)
 					retval = err;
@@ -636,8 +665,15 @@
 	read_lock(&tasklist_lock);
 	p = find_task_by_pid(pid);
 	error = -ESRCH;
-	if (p)
+	if (p) {
+		if (!thread_group_leader(p)) {
+                       struct task_struct *tg;
+                       tg = find_task_by_pid(p->tgid);
+                       if (tg)
+                               p = tg;
+                }
 		error = send_sig_info(sig, info, p);
+	}
 	read_unlock(&tasklist_lock);
 	return error;
 }
@@ -660,7 +696,7 @@
 
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pid > 1 && p != current) {
+			if (p->pid > 1 && p != current && thread_group_leader(p)) {
 				int err = send_sig_info(sig, info, p);
 				++count;
 				if (err != -EPERM)
@@ -983,6 +1019,36 @@
 	info.si_uid = current->uid;
 
 	return kill_something_info(sig, &info, pid);
+}
+
+/*
+ *  Kill only one task, even if it's a CLONE_THREAD task.
+ */
+asmlinkage long
+sys_tkill(int pid, int sig)
+{
+       struct siginfo info;
+       int error;
+       struct task_struct *p;
+
+       /* This is only valid for single tasks */
+       if (pid <= 0)
+           return -EINVAL;
+
+       info.si_signo = sig;
+       info.si_errno = 0;
+       info.si_code = SI_TKILL;
+       info.si_pid = current->pid;
+       info.si_uid = current->uid;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+       error = -ESRCH;
+       if (p) {
+               error = send_sig_info(sig, &info, p);
+       }
+       read_unlock(&tasklist_lock);
+       return error;
 }
 
 asmlinkage long
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Wed Feb  6 22:48:38 2002
+++ b/kernel/sysctl.c	Wed Feb  6 22:48:38 2002
@@ -677,7 +677,7 @@
 	size_t res;
 	ssize_t error;
 	
-	de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
+	de = PDE(file->f_dentry->d_inode);
 	if (!de || !de->data)
 		return -ENOTDIR;
 	table = (struct ctl_table *) de->data;
diff -Nru a/lib/crc32.c b/lib/crc32.c
--- a/lib/crc32.c	Wed Feb  6 22:48:38 2002
+++ b/lib/crc32.c	Wed Feb  6 22:48:38 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	Wed Feb  6 22:48:38 2002
+++ b/lib/zlib_inflate/inflate_syms.c	Wed Feb  6 22:48:38 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/mm/bootmem.c b/mm/bootmem.c
--- a/mm/bootmem.c	Wed Feb  6 22:48:39 2002
+++ b/mm/bootmem.c	Wed Feb  6 22:48:39 2002
@@ -247,19 +247,30 @@
 	bootmem_data_t *bdata = pgdat->bdata;
 	unsigned long i, count, total = 0;
 	unsigned long idx;
+	unsigned long *map; 
 
 	if (!bdata->node_bootmem_map) BUG();
 
 	count = 0;
 	idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
-	for (i = 0; i < idx; i++, page++) {
-		if (!test_bit(i, bdata->node_bootmem_map)) {
+	map = bdata->node_bootmem_map;
+	for (i = 0; i < idx; ) {
+		unsigned long v = ~map[i / BITS_PER_LONG];
+		if (v) { 
+			unsigned long m;
+			for (m = 1; m && i < idx; m<<=1, page++, i++) { 
+				if (v & m) {
 			count++;
 			ClearPageReserved(page);
 			set_page_count(page, 1);
 			__free_page(page);
 		}
 	}
+		} else {
+			i+=BITS_PER_LONG;
+			page+=BITS_PER_LONG; 
+		} 	
+	}	
 	total += count;
 
 	/*
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Wed Feb  6 22:48:39 2002
+++ b/mm/shmem.c	Wed Feb  6 22:48:39 2002
@@ -1267,7 +1267,7 @@
 }
 #endif
 
-static struct super_block *shmem_read_super(struct super_block * sb, void * data, int silent)
+static int shmem_fill_super(struct super_block * sb, void * data, int silent)
 {
 	struct inode * inode;
 	struct dentry * root;
@@ -1286,7 +1286,7 @@
 #ifdef CONFIG_TMPFS
 	if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
 		printk(KERN_ERR "tmpfs invalid option\n");
-		return NULL;
+		return -EINVAL;
 	}
 #endif
 
@@ -1302,15 +1302,15 @@
 	sb->s_op = &shmem_ops;
 	inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
 	if (!inode)
-		return NULL;
+		return -ENOMEM;
 
 	root = d_alloc_root(inode);
 	if (!root) {
 		iput(inode);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root = root;
-	return sb;
+	return 0;
 }
 
 static kmem_cache_t * shmem_inode_cachep;
@@ -1410,12 +1410,33 @@
 	nopage:	shmem_nopage,
 };
 
+static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, shmem_fill_super);
+}
+
 #ifdef CONFIG_TMPFS
 /* type "shm" will be tagged obsolete in 2.5 */
-static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER);
-static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER);
+static struct file_system_type shmem_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"shmem",
+	get_sb:		shmem_get_sb,
+	fs_flags:	FS_LITTER,
+};
+static struct file_system_type tmpfs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"tmpfs",
+	get_sb:		shmem_get_sb,
+	fs_flags:	FS_LITTER,
+};
 #else
-static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT);
+static struct file_system_type tmpfs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"tmpfs",
+	get_sb:		shmem_get_sb,
+	fs_flags:	FS_LITTER|FS_NOMOUNT,
+};
 #endif
 static struct vfsmount *shm_mnt;
 
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Wed Feb  6 22:48:39 2002
+++ b/mm/slab.c	Wed Feb  6 22:48:39 2002
@@ -186,8 +186,6 @@
  * manages a cache.
  */
 
-#define CACHE_NAMELEN	20	/* max name length for a slab cache */
-
 struct kmem_cache_s {
 /* 1) each alloc & free */
 	/* full, partial first, then free */
@@ -225,7 +223,7 @@
 	unsigned long		failures;
 
 /* 3) cache creation/removal */
-	char			name[CACHE_NAMELEN];
+	const char		*name;
 	struct list_head	next;
 #ifdef CONFIG_SMP
 /* 4) per-cpu data */
@@ -335,6 +333,7 @@
 	kmem_cache_t	*cs_dmacachep;
 } cache_sizes_t;
 
+/* These are the default caches for kmalloc. Custom caches can have other sizes. */
 static cache_sizes_t cache_sizes[] = {
 #if PAGE_SIZE == 4096
 	{    32,	NULL, NULL},
@@ -353,6 +352,29 @@
 	{131072,	NULL, NULL},
 	{     0,	NULL, NULL}
 };
+/* Must match cache_sizes above. Out of line to keep cache footprint low. */
+#define CN(x) { x, x " (DMA)" }
+static struct { 
+	char *name; 
+	char *name_dma;
+} cache_names[] = { 
+#if PAGE_SIZE == 4096
+	CN("size-32"),
+#endif
+	CN("size-64"),
+	CN("size-128"),
+	CN("size-256"),
+	CN("size-512"),
+	CN("size-1024"),
+	CN("size-2048"),
+	CN("size-4096"),
+	CN("size-8192"),
+	CN("size-16384"),
+	CN("size-32768"),
+	CN("size-65536"),
+	CN("size-131072")
+}; 
+#undef CN
 
 /* internal cache of cache description objs */
 static kmem_cache_t cache_cache = {
@@ -437,7 +459,6 @@
 void __init kmem_cache_sizes_init(void)
 {
 	cache_sizes_t *sizes = cache_sizes;
-	char name[20];
 	/*
 	 * Fragmentation resistance on low memory - only use bigger
 	 * page orders on machines with more than 32MB of memory.
@@ -450,9 +471,9 @@
 		 * eliminates "false sharing".
 		 * Note for systems short on memory removing the alignment will
 		 * allow tighter packing of the smaller caches. */
-		sprintf(name,"size-%Zd",sizes->cs_size);
 		if (!(sizes->cs_cachep =
-			kmem_cache_create(name, sizes->cs_size,
+			kmem_cache_create(cache_names[sizes-cache_sizes].name, 
+					  sizes->cs_size,
 					0, SLAB_HWCACHE_ALIGN, NULL, NULL))) {
 			BUG();
 		}
@@ -462,9 +483,10 @@
 			offslab_limit = sizes->cs_size-sizeof(slab_t);
 			offslab_limit /= 2;
 		}
-		sprintf(name, "size-%Zd(DMA)",sizes->cs_size);
-		sizes->cs_dmacachep = kmem_cache_create(name, sizes->cs_size, 0,
-			      SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
+		sizes->cs_dmacachep = kmem_cache_create(
+		    cache_names[sizes-cache_sizes].name_dma, 
+			sizes->cs_size, 0,
+			SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
 		if (!sizes->cs_dmacachep)
 			BUG();
 		sizes++;
@@ -604,6 +626,11 @@
  * Cannot be called within a int, but can be interrupted.
  * The @ctor is run when new pages are allocated by the cache
  * and the @dtor is run before the pages are handed back.
+ *
+ * @name must be valid until the cache is destroyed. This implies that
+ * the module calling this has to destroy the cache before getting 
+ * unloaded.
+ * 
  * The flags are
  *
  * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
@@ -632,7 +659,6 @@
 	 * Sanity checks... these are all serious usage bugs.
 	 */
 	if ((!name) ||
-		((strlen(name) >= CACHE_NAMELEN - 1)) ||
 		in_interrupt() ||
 		(size < BYTES_PER_WORD) ||
 		(size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
@@ -797,8 +823,7 @@
 		cachep->slabp_cache = kmem_find_general_cachep(slab_size,0);
 	cachep->ctor = ctor;
 	cachep->dtor = dtor;
-	/* Copy name over so we don't have problems with unloaded modules */
-	strcpy(cachep->name, name);
+	cachep->name = name;
 
 #ifdef CONFIG_SMP
 	if (g_cpucache_up)
@@ -811,10 +836,20 @@
 
 		list_for_each(p, &cache_chain) {
 			kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
-
-			/* The name field is constant - no lock needed. */
-			if (!strcmp(pc->name, name))
-				BUG();
+			char tmp;
+			/* This happens when the module gets unloaded and doesn't
+			   destroy its slab cache and noone else reuses the vmalloc
+			   area of the module. Print a warning. */
+			if (__get_user(tmp,pc->name)) { 
+				printk("SLAB: cache with size %d has lost its name\n", 
+					pc->objsize); 
+				continue; 
+			} 	
+			if (!strcmp(pc->name,name)) { 
+				printk("kmem_cache_create: duplicate cache %s\n",name); 
+				up(&cache_chain_sem); 
+				BUG(); 
+			}	
 		}
 	}
 
@@ -1878,6 +1913,7 @@
 		unsigned long	num_objs;
 		unsigned long	active_slabs = 0;
 		unsigned long	num_slabs;
+		const char *name; 
 		cachep = list_entry(p, kmem_cache_t, next);
 
 		spin_lock_irq(&cachep->spinlock);
@@ -1906,8 +1942,15 @@
 		num_slabs+=active_slabs;
 		num_objs = num_slabs*cachep->num;
 
+		name = cachep->name; 
+		{
+		char tmp; 
+		if (__get_user(tmp, name)) 
+			name = "broken"; 
+		} 	
+
 		len += sprintf(page+len, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
-			cachep->name, active_objs, num_objs, cachep->objsize,
+			name, active_objs, num_objs, cachep->objsize,
 			active_slabs, num_slabs, (1<<cachep->gfporder));
 
 #if STATS
diff -Nru a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
--- a/net/8021q/vlanproc.c	Wed Feb  6 22:48:39 2002
+++ b/net/8021q/vlanproc.c	Wed Feb  6 22:48:39 2002
@@ -236,7 +236,7 @@
 	if (count <= 0)
 		return 0;
 
-	dent = inode->u.generic_ip;
+	dent = PDE(inode);
 	if ((dent == NULL) || (dent->get_info == NULL))
 		return 0;
 
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Wed Feb  6 22:48:39 2002
+++ b/net/atm/proc.c	Wed Feb  6 22:48:39 2002
@@ -498,8 +498,7 @@
 	if (count == 0) return 0;
 	page = get_free_page(GFP_KERNEL);
 	if (!page) return -ENOMEM;
-	dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
-	    ->data;
+	dev = PDE(file->f_dentry->d_inode)->data;
 	if (!dev->ops->proc_read)
 		length = -EINVAL;
 	else {
@@ -521,8 +520,7 @@
 	unsigned long page;
 	int length;
 	int (*info)(loff_t,char *);
-	info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip)
-	    ->data;
+	info = PDE(file->f_dentry->d_inode)->data;
 
 	if (count == 0) return 0;
 	page = get_free_page(GFP_KERNEL);
diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c	Wed Feb  6 22:48:39 2002
+++ b/net/ax25/af_ax25.c	Wed Feb  6 22:48:39 2002
@@ -1756,7 +1756,7 @@
 			len += sprintf(buffer + len, " %d %d %ld\n",
 				atomic_read(&ax25->sk->wmem_alloc),
 				atomic_read(&ax25->sk->rmem_alloc),
-				ax25->sk->socket != NULL ? ax25->sk->socket->inode->i_ino : 0L);
+				ax25->sk->socket != NULL ? SOCK_INODE(ax25->sk->socket)->i_ino : 0L);
 		} else {
 			len += sprintf(buffer + len, " * * *\n");
 		}
diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c	Wed Feb  6 22:48:39 2002
+++ b/net/ipv6/icmp.c	Wed Feb  6 22:48:39 2002
@@ -637,21 +637,11 @@
 	struct sock *sk;
 	int err;
 
-	icmpv6_socket = sock_alloc();
-	if (icmpv6_socket == NULL) {
-		printk(KERN_ERR
-		       "Failed to create the ICMP6 control socket.\n");
-		return -1;
-	}
-	icmpv6_socket->inode->i_uid = 0;
-	icmpv6_socket->inode->i_gid = 0;
-	icmpv6_socket->type = SOCK_RAW;
-
-	if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) {
+	err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &icmpv6_socket);
+	if (err < 0) {
 		printk(KERN_ERR
 		       "Failed to initialize the ICMP6 control socket (err %d).\n",
 		       err);
-		sock_release(icmpv6_socket);
 		icmpv6_socket = NULL; /* for safety */
 		return err;
 	}
diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c
--- a/net/ipv6/mcast.c	Wed Feb  6 22:48:39 2002
+++ b/net/ipv6/mcast.c	Wed Feb  6 22:48:39 2002
@@ -751,21 +751,11 @@
 	struct sock *sk;
 	int err;
 
-	igmp6_socket = sock_alloc();
-	if (igmp6_socket == NULL) {
+	err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
+	if (err < 0) {
 		printk(KERN_ERR
-		       "Failed to create the IGMP6 control socket.\n");
-		return -1;
-	}
-	igmp6_socket->inode->i_uid = 0;
-	igmp6_socket->inode->i_gid = 0;
-	igmp6_socket->type = SOCK_RAW;
-
-	if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
-		printk(KERN_DEBUG 
 		       "Failed to initialize the IGMP6 control socket (err %d).\n",
 		       err);
-		sock_release(igmp6_socket);
 		igmp6_socket = NULL; /* For safety. */
 		return err;
 	}
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Wed Feb  6 22:48:38 2002
+++ b/net/ipv6/ndisc.c	Wed Feb  6 22:48:38 2002
@@ -1214,21 +1214,11 @@
 	struct sock *sk;
         int err;
 
-	ndisc_socket = sock_alloc();
-	if (ndisc_socket == NULL) {
+	err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
+	if (err < 0) {
 		printk(KERN_ERR
-		       "Failed to create the NDISC control socket.\n");
-		return -1;
-	}
-	ndisc_socket->inode->i_uid = 0;
-	ndisc_socket->inode->i_gid = 0;
-	ndisc_socket->type = SOCK_RAW;
-
-	if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) {
-		printk(KERN_DEBUG 
 		       "Failed to initialize the NDISC control socket (err %d).\n",
 		       err);
-		sock_release(ndisc_socket);
 		ndisc_socket = NULL; /* For safety. */
 		return err;
 	}
diff -Nru a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
--- a/net/netlink/netlink_dev.c	Wed Feb  6 22:48:39 2002
+++ b/net/netlink/netlink_dev.c	Wed Feb  6 22:48:39 2002
@@ -98,11 +98,6 @@
 	return sock_recvmsg(sock, &msg, count, msg.msg_flags);
 }
 
-static loff_t netlink_lseek(struct file * file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
 static int netlink_open(struct inode * inode, struct file * file)
 {
 	unsigned int minor = minor(inode->i_rdev);
@@ -166,7 +161,7 @@
 
 static struct file_operations netlink_fops = {
 	owner:		THIS_MODULE,
-	llseek:		netlink_lseek,
+	llseek:		no_llseek,
 	read:		netlink_read,
 	write:		netlink_write,
 	poll:		netlink_poll,
diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c	Wed Feb  6 22:48:39 2002
+++ b/net/netrom/af_netrom.c	Wed Feb  6 22:48:39 2002
@@ -1204,7 +1204,7 @@
 			s->protinfo.nr->window,
 			atomic_read(&s->wmem_alloc),
 			atomic_read(&s->rmem_alloc),
-			s->socket != NULL ? s->socket->inode->i_ino : 0L);
+			s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L);
 
 		pos = begin + len;
 
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Wed Feb  6 22:48:38 2002
+++ b/net/packet/af_packet.c	Wed Feb  6 22:48:38 2002
@@ -1575,7 +1575,7 @@
 {
 	struct file *file = vma->vm_file;
 	struct inode *inode = file->f_dentry->d_inode;
-	struct socket * sock = &inode->u.socket_i;
+	struct socket * sock = SOCKET_I(inode);
 	struct sock *sk = sock->sk;
 	
 	if (sk)
@@ -1586,7 +1586,7 @@
 {
 	struct file *file = vma->vm_file;
 	struct inode *inode = file->f_dentry->d_inode;
-	struct socket * sock = &inode->u.socket_i;
+	struct socket * sock = SOCKET_I(inode);
 	struct sock *sk = sock->sk;
 	
 	if (sk)
diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c	Wed Feb  6 22:48:39 2002
+++ b/net/rose/af_rose.c	Wed Feb  6 22:48:39 2002
@@ -1370,7 +1370,7 @@
 			s->protinfo.rose->idle / (60 * HZ),
 			atomic_read(&s->wmem_alloc),
 			atomic_read(&s->rmem_alloc),
-			s->socket != NULL ? s->socket->inode->i_ino : 0L);
+			s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L);
 
 		pos = begin + len;
 
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Wed Feb  6 22:48:39 2002
+++ b/net/socket.c	Wed Feb  6 22:48:39 2002
@@ -86,7 +86,6 @@
 #include <linux/netfilter.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static loff_t sock_lseek(struct file *file, loff_t offset, int whence);
 static ssize_t sock_read(struct file *file, char *buf,
 			 size_t size, loff_t *ppos);
 static ssize_t sock_write(struct file *file, const char *buf,
@@ -113,7 +112,7 @@
  */
 
 static struct file_operations socket_file_ops = {
-	llseek:		sock_lseek,
+	llseek:		no_llseek,
 	read:		sock_read,
 	write:		sock_write,
 	poll:		sock_poll,
@@ -272,36 +271,87 @@
 	return 0;
 }
 
+static kmem_cache_t * sock_inode_cachep;
+
+static struct inode *sock_alloc_inode(struct super_block *sb)
+{
+	struct socket_alloc *ei;
+	ei = (struct socket_alloc *)kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	init_waitqueue_head(&ei->socket.wait);
+	return &ei->vfs_inode;
+}
+
+static void sock_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(sock_inode_cachep,
+			list_entry(inode, struct socket_alloc, vfs_inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct socket_alloc *ei = (struct socket_alloc *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	sock_inode_cachep = kmem_cache_create("sock_inode_cache",
+					     sizeof(struct socket_alloc),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (sock_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 static struct super_operations sockfs_ops = {
+	alloc_inode:	sock_alloc_inode,
+	destroy_inode:	sock_destroy_inode,
 	statfs:		sockfs_statfs,
 };
 
-static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent)
+static int sockfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *root;
 	sb->s_blocksize = 1024;
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = SOCKFS_MAGIC;
-	sb->s_op	= &sockfs_ops;
+	sb->s_op = &sockfs_ops;
 	root = new_inode(sb);
 	if (!root)
-		return NULL;
+		return -ENOMEM;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "socket:", 7, 0 });
 	if (!sb->s_root) {
 		iput(root);
-		return NULL;
+		return -ENOMEM;
 	}
 	sb->s_root->d_sb = sb;
 	sb->s_root->d_parent = sb->s_root;
 	d_instantiate(sb->s_root, root);
-	return sb;
+	return 0;
+}
+
+static struct super_block *sockfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, sockfs_fill_super);
 }
 
 static struct vfsmount *sock_mnt;
-static DECLARE_FSTYPE(sock_fs_type, "sockfs", sockfs_read_super, FS_NOMOUNT);
+
+static struct file_system_type sock_fs_type = {
+	name:		"sockfs",
+	get_sb:		sockfs_get_sb,
+	fs_flags:	FS_NOMOUNT,
+};
 static int sockfs_delete_dentry(struct dentry *dentry)
 {
 	return 1;
@@ -347,10 +397,10 @@
 			goto out;
 		}
 
-		sprintf(name, "[%lu]", sock->inode->i_ino);
+		sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
 		this.name = name;
 		this.len = strlen(name);
-		this.hash = sock->inode->i_ino;
+		this.hash = SOCK_INODE(sock)->i_ino;
 
 		file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
 		if (!file->f_dentry) {
@@ -360,11 +410,11 @@
 			goto out;
 		}
 		file->f_dentry->d_op = &sockfs_dentry_operations;
-		d_add(file->f_dentry, sock->inode);
+		d_add(file->f_dentry, SOCK_INODE(sock));
 		file->f_vfsmnt = mntget(sock_mnt);
 
 		sock->file = file;
-		file->f_op = sock->inode->i_fop = &socket_file_ops;
+		file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
 		file->f_mode = 3;
 		file->f_flags = O_RDWR;
 		file->f_pos = 0;
@@ -375,11 +425,6 @@
 	return fd;
 }
 
-extern __inline__ struct socket *socki_lookup(struct inode *inode)
-{
-	return &inode->u.socket_i;
-}
-
 /**
  *	sockfd_lookup	- 	Go from a file number to its socket slot
  *	@fd: file handle
@@ -406,7 +451,7 @@
 	}
 
 	inode = file->f_dentry->d_inode;
-	if (!inode->i_sock || !(sock = socki_lookup(inode)))
+	if (!inode->i_sock || !(sock = SOCKET_I(inode)))
 	{
 		*err = -ENOTSOCK;
 		fput(file);
@@ -443,15 +488,13 @@
 		return NULL;
 
 	inode->i_dev = NODEV;
-	sock = socki_lookup(inode);
+	sock = SOCKET_I(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
 	inode->i_sock = 1;
 	inode->i_uid = current->fsuid;
 	inode->i_gid = current->fsgid;
 
-	sock->inode = inode;
-	init_waitqueue_head(&sock->wait);
 	sock->fasync_list = NULL;
 	sock->state = SS_UNCONNECTED;
 	sock->flags = 0;
@@ -493,7 +536,7 @@
 
 	sockets_in_use[smp_processor_id()].counter--;
 	if (!sock->file) {
-		iput(sock->inode);
+		iput(SOCK_INODE(sock));
 		return;
 	}
 	sock->file=NULL;
@@ -527,15 +570,6 @@
 
 
 /*
- *	Sockets are not seekable.
- */
-
-static loff_t sock_lseek(struct file *file, loff_t offset, int whence)
-{
-	return -ESPIPE;
-}
-
-/*
  *	Read data from a socket. ubuf is a user mode pointer. We make sure the user
  *	area ubuf...ubuf+size-1 is writable before asking the protocol.
  */
@@ -553,7 +587,7 @@
 	if (size==0)		/* Match SYS5 behaviour */
 		return 0;
 
-	sock = socki_lookup(file->f_dentry->d_inode); 
+	sock = SOCKET_I(file->f_dentry->d_inode); 
 
 	msg.msg_name=NULL;
 	msg.msg_namelen=0;
@@ -586,7 +620,7 @@
 	if(size==0)		/* Match SYS5 behaviour */
 		return 0;
 
-	sock = socki_lookup(file->f_dentry->d_inode); 
+	sock = SOCKET_I(file->f_dentry->d_inode); 
 
 	msg.msg_name=NULL;
 	msg.msg_namelen=0;
@@ -612,7 +646,7 @@
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
 
-	sock = socki_lookup(file->f_dentry->d_inode);
+	sock = SOCKET_I(file->f_dentry->d_inode);
 
 	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
 	if (more)
@@ -627,7 +661,7 @@
 	struct msghdr msg;
 	struct socket *sock;
 
-	sock = socki_lookup(inode);
+	sock = SOCKET_I(inode);
 
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
@@ -681,7 +715,7 @@
 	int err;
 
 	unlock_kernel();
-	sock = socki_lookup(inode);
+	sock = SOCKET_I(inode);
 	err = sock->ops->ioctl(sock, cmd, arg);
 	lock_kernel();
 
@@ -697,13 +731,13 @@
 	/*
 	 *	We can't return errors to poll, so it's either yes or no. 
 	 */
-	sock = socki_lookup(file->f_dentry->d_inode);
+	sock = SOCKET_I(file->f_dentry->d_inode);
 	return sock->ops->poll(file, sock, wait);
 }
 
 static int sock_mmap(struct file * file, struct vm_area_struct * vma)
 {
-	struct socket *sock = socki_lookup(file->f_dentry->d_inode);
+	struct socket *sock = SOCKET_I(file->f_dentry->d_inode);
 
 	return sock->ops->mmap(file, sock, vma);
 }
@@ -721,7 +755,7 @@
 		return 0;
 	}
 	sock_fasync(-1, filp, 0);
-	sock_release(socki_lookup(inode));
+	sock_release(SOCKET_I(inode));
 	return 0;
 }
 
@@ -754,7 +788,7 @@
 	}
 
 
-	sock = socki_lookup(filp->f_dentry->d_inode);
+	sock = SOCKET_I(filp->f_dentry->d_inode);
 	
 	if ((sk=sock->sk) == NULL)
 		return -EINVAL;
@@ -1521,7 +1555,7 @@
 {
 	struct socket *sock;
 
-	sock = socki_lookup (filp->f_dentry->d_inode);
+	sock = SOCKET_I (filp->f_dentry->d_inode);
 	if (sock && sock->ops)
 		return sock_no_fcntl(sock, cmd, arg);
 	return(-EINVAL);
@@ -1711,6 +1745,7 @@
 	 *	Initialize the protocols module. 
 	 */
 
+	init_inodecache();
 	register_filesystem(&sock_fs_type);
 	sock_mnt = kern_mount(&sock_fs_type);
 	/* The real protocol initialization is performed when
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Wed Feb  6 22:48:38 2002
+++ b/net/unix/af_unix.c	Wed Feb  6 22:48:38 2002
@@ -711,7 +711,7 @@
 		/*
 		 * All right, let's create it.
 		 */
-		mode = S_IFSOCK | (sock->inode->i_mode & ~current->fs->umask);
+		mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask);
 		err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0);
 		if (err)
 			goto out_mknod_dput;
diff -Nru a/net/unix/garbage.c b/net/unix/garbage.c
--- a/net/unix/garbage.c	Wed Feb  6 22:48:39 2002
+++ b/net/unix/garbage.c	Wed Feb  6 22:48:39 2002
@@ -101,7 +101,7 @@
 	 *	Socket ?
 	 */
 	if (inode->i_sock) {
-		struct socket * sock = &inode->u.socket_i;
+		struct socket * sock = SOCKET_I(inode);
 		struct sock * s = sock->sk;
 
 		/*
diff -Nru a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
--- a/net/wanrouter/wanmain.c	Wed Feb  6 22:48:39 2002
+++ b/net/wanrouter/wanmain.c	Wed Feb  6 22:48:39 2002
@@ -500,7 +500,7 @@
 	if ((cmd >> 8) != ROUTER_IOCTL)
 		return -EINVAL;
 		
-	dent = inode->u.generic_ip;
+	dent = PDE(inode);
 	if ((dent == NULL) || (dent->data == NULL))
 		return -EINVAL;
 		
diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
--- a/net/wanrouter/wanproc.c	Wed Feb  6 22:48:39 2002
+++ b/net/wanrouter/wanproc.c	Wed Feb  6 22:48:39 2002
@@ -248,7 +248,7 @@
 		if (count <= 0)
 			return 0;
 			
-		dent = inode->u.generic_ip;
+		dent = PDE(inode);
 		if ((dent == NULL) || (dent->get_info == NULL))
 			return 0;
 			
@@ -794,7 +794,7 @@
 		if (count <= 0)
 			return 0;
 			
-		dent = inode->u.generic_ip;
+		dent = PDE(inode);
 		if ((dent == NULL) || (dent->get_info == NULL))
 			return 0;
 			
@@ -828,7 +828,7 @@
 
 		if (count <= 0)
 			return 0;
-		dent = inode->u.generic_ip;
+		dent = PDE(inode);
 		if ((dent == NULL) || (dent->get_info == NULL))
 			return -ENODATA;
 		err = verify_area(VERIFY_WRITE, buf, count);
@@ -1068,7 +1068,7 @@
 
         if (err) return err;
 
-        dent = inode->u.generic_ip;
+        dent = PDE(inode);
         if ((dent == NULL) || (dent->data == NULL))
                 return -ENODATA;
 
diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c	Wed Feb  6 22:48:39 2002
+++ b/net/x25/af_x25.c	Wed Feb  6 22:48:39 2002
@@ -1239,7 +1239,7 @@
 			s->protinfo.x25->t23 / HZ,
 			atomic_read(&s->wmem_alloc),
 			atomic_read(&s->rmem_alloc),
-			s->socket != NULL ? s->socket->inode->i_ino : 0L);
+			s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L);
 
 		pos = begin + len;
 
diff -Nru a/scripts/header.tk b/scripts/header.tk
--- a/scripts/header.tk	Wed Feb  6 22:48:39 2002
+++ b/scripts/header.tk	Wed Feb  6 22:48:39 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 {
