diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Fri Jul  5 16:43:00 2002
+++ b/Documentation/DocBook/Makefile	Fri Jul  5 16:43:00 2002
@@ -15,6 +15,10 @@
 $(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \
 $(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc: doc-progs ;
 
+dochelp:
+	@echo  '  Linux kernel internal documentation in different formats:'
+	@echo  '  sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF), htmldocs (HTML)'
+
 .PHONY: doc-progs
 doc-progs:
 	@$(MAKE) -C $(TOPDIR)/scripts doc-progs
@@ -116,6 +120,7 @@
 		$(TOPDIR)/drivers/usb/core/urb.c \
 		$(TOPDIR)/drivers/usb/core/message.c \
 		$(TOPDIR)/drivers/usb/core/config.c \
+		$(TOPDIR)/drivers/usb/core/file.c \
 		$(TOPDIR)/drivers/usb/core/usb.c \
 		$(TOPDIR)/drivers/video/fbmem.c \
 		$(TOPDIR)/drivers/video/fbcmap.c \
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Fri Jul  5 16:42:44 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Fri Jul  5 16:42:44 2002
@@ -285,6 +285,7 @@
 !Edrivers/usb/core/urb.c
 !Edrivers/usb/core/config.c
 !Edrivers/usb/core/message.c
+!Edrivers/usb/core/file.c
 !Edrivers/usb/core/usb.c
     </sect1>
 
diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Fri Jul  5 16:42:59 2002
+++ b/Documentation/filesystems/Locking	Fri Jul  5 16:42:59 2002
@@ -108,7 +108,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	no	yes	maybe		(see below)
-statfs:		yes	no	no
+statfs:		no	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
 
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt	Fri Jul  5 16:43:00 2002
+++ b/Documentation/filesystems/ntfs.txt	Fri Jul  5 16:43:00 2002
@@ -247,6 +247,18 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.0.14:
+	- Internal changes improving run list merging code and minor locking
+	  change to not rely on BKL in ntfs_statfs().
+2.0.13:
+	- Internal changes towards using iget5_locked() in preparation for
+	  fake inodes and small cleanups to ntfs_volume structure.
+2.0.12:
+	- Internal cleanups in address space operations made possible by the
+	  changes introduced in the previous release.
+2.0.11:
+	- Internal updates and cleanups introducing the first step towards
+	  fake inode based attribute i/o.
 2.0.10:
 	- Microsoft says that the maximum number of inodes is 2^32 - 1. Update
 	  the driver accordingly to only use 32-bits to store inode numbers on
diff -Nru a/Documentation/filesystems/porting b/Documentation/filesystems/porting
--- a/Documentation/filesystems/porting	Fri Jul  5 16:42:59 2002
+++ b/Documentation/filesystems/porting	Fri Jul  5 16:42:59 2002
@@ -3,11 +3,13 @@
 --- 
 [recommended]
 
-New helpers: sb_bread(), sb_getblk(), sb_get_hash_table(), set_bh(),
+New helpers: sb_bread(), sb_getblk(), sb_find_get_block(), set_bh(),
 	sb_set_blocksize() and sb_min_blocksize().
 
 Use them.
 
+(sb_find_get_block() replaces 2.4's get_hash_table())
+
 --- 
 [recommended]
 
@@ -81,7 +83,7 @@
 [mandatory]
 
 ->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(),
-->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename(), ->permission()
+->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename()
 and ->readdir() are called without BKL now.  Grab it on entry, drop upon return
 - that will guarantee the same locking you used to have.  If your method or its
 parts do not need BKL - better yet, now you can shift lock_kernel() and
@@ -228,3 +230,37 @@
 	Use bdev_read_only(bdev) instead of is_read_only(kdev).  The latter
 is still alive, but only because of the mess in drivers/s390/block/dasd.c.
 As soon as it gets fixed is_read_only() will die.
+
+---
+[mandatory]
+
+->permission() is called without BKL now. Grab it on entry, drop upon
+return - that will guarantee the same locking you used to have.  If
+your method or its parts do not need BKL - better yet, now you can
+shift lock_kernel() and unlock_kernel() so that they would protect
+exactly what needs to be protected.
+
+---
+[mandatory]
+
+->statfs() is now called without BKL held.  BKL should have been
+shifted into individual fs sb_op functions where it's not clear that
+it's safe to remove it.  If you don't need it, remove it.
+
+---
+[mandatory]
+
+	is_read_only() is gone; use bdev_read_only() instead.
+
+---
+[mandatory]
+
+	destroy_buffers() is gone; use invalidate_bdev().
+
+---
+[mandatory]
+
+	fsync_dev() is gone; use fsync_bdev().  NOTE: lvm breakage is
+deliberate; as soon as struct block_device * is propagated in a reasonable
+way by that code fixing will become trivial; until then nothing can be
+done.
diff -Nru a/Documentation/swsusp.txt b/Documentation/swsusp.txt
--- a/Documentation/swsusp.txt	Fri Jul  5 16:42:44 2002
+++ b/Documentation/swsusp.txt	Fri Jul  5 16:42:44 2002
@@ -122,11 +122,9 @@
   interrupts AFAIK..
 - We should only make a copy of data related to kernel segment, since any
   process data won't be changed.
-- By copying pages back to their original position, copy_page caused General
-  Protection Fault. Why?
 - Hardware state restoring.  Now there's support for notifying via the notify
   chain, event handlers are welcome. Some devices may have microcodes loaded
-  into them. We should have event handlers for them aswell.
+  into them. We should have event handlers for them as well.
 - We should support other architectures (There are really only some arch
   related functions..)
 - We should also restore original state of swaps if the ``noresume'' kernel
@@ -148,6 +146,15 @@
   go there anyway..
 - If X is active while suspending then by resuming calling svgatextmode
   corrupts the virtual console of X.. (Maybe this has been fixed AFAIK).
+
+Drivers we support
+- IDE disks are okay
+- vesafb
+
+Drivers that need support
+- pc_keyb -- perhaps we can wait for vojtech's input patches
+- do IDE cdroms need some kind of support?
+- IDE CD-RW -- how to deal with that?
 
 Any other idea you might have tell me!
 
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Fri Jul  5 16:42:56 2002
+++ b/Makefile	Fri Jul  5 16:42:56 2002
@@ -1,8 +1,14 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 24
+SUBLEVEL = 25
 EXTRAVERSION =
 
+# *DOCUMENTATION*
+# Too see a list of typical targets execute "make help"
+# More info can be located in ./Documentation/kbuild
+# Comments in this file is targeted only to the developer, do not
+# expect to learn how to build the kernel reading this file.
+
 # We are using a recursive build, so we need to do a little thinking
 # to get the ordering right.
 #
@@ -140,16 +146,23 @@
 	CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
 	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS PERL
 
-export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS
+export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS OBJCOPYFLAGS
 export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
 export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 
+src	:= .
+obj	:= .
+srctree := $(TOPDIR)
+objtree := $(TOPDIR)
+
+export srctree objtree
+
 SUBDIRS		:= init kernel mm fs ipc lib drivers sound net
 
 noconfig_targets := xconfig menuconfig config oldconfig randconfig \
 		    defconfig allyesconfig allnoconfig allmodconfig \
 		    clean mrproper distclean \
-		    tags TAGS sgmldocs psdocs pdfdocs htmldocs \
+		    help tags TAGS sgmldocs psdocs pdfdocs htmldocs \
 		    checkconfig checkhelp checkincludes
 
 ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
@@ -217,7 +230,7 @@
 
 include arch/$(ARCH)/Makefile
 
-export	NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
+export	NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT ASFLAGS
 
 # boot target
 # ---------------------------------------------------------------------------
@@ -238,7 +251,7 @@
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
 quiet_cmd_link_vmlinux = LD     $@
-cmd_link_vmlinux = $(LD) $(LINKFLAGS) $(HEAD) $(INIT) \
+cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
 		--start-group \
 		$(CORE_FILES) \
 		$(LIBS) \
@@ -255,7 +268,7 @@
 	. scripts/mkversion > .tmpversion
 	mv -f .tmpversion .version
 	+$(MAKE) -C init
-	$(call cmd,cmd_link_vmlinux)
+	$(call cmd,link_vmlinux)
 	$(cmd_link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
@@ -679,6 +692,43 @@
 	find $(SUBDIRS) init -name SCCS -prune -o -name BitKeeper -prune -o \
 		-name '*.[ch]' -print | xargs ctags $$CTAGSF -a
 
+# Brief documentation of the typical targets used
+# ---------------------------------------------------------------------------
+
+help:
+	@echo  'Cleaning targets:'
+	@echo  '  clean		- remove most generated files but keep the config'
+	@echo  '  mrproper	- remove all generated files including the config'
+	@echo  '  distclean	- mrproper + remove files generated by editors and patch'
+	@echo  ''
+	@echo  'Configuration targets:'
+	@echo  '  oldconfig	- Update current config utilising a line-oriented program'
+	@echo  '  menuconfig	- Update current config utilising a menu based program'
+	@echo  '  xconfig	- Update current config utilising a X-based program'
+	@echo  '  defconfig	- New config with default answer to all options'
+	@echo  '  allmodconfig	- New config selecting modules when possible'
+	@echo  '  allyesconfig	- New config where all options are accepted with yes'
+	@echo  '  allnoconfig	- New minimal config'
+	@echo  ''
+	@echo  'Other generic targets:'
+	@echo  '  all		- Build all targets marked with [*]'
+	@echo  '  dep           - Create module version information'
+	@echo  '* vmlinux	- Build the bare kernel'
+	@echo  '* modules	- Build all modules'
+	@echo  '  dir/file.[ois]- Build specified target only'
+	@echo  '  rpm		- Build a kernel as an RPM package'
+	@echo  '  tags/TAGS	- Generate tags file for editors'
+	@echo  ''
+	@echo  'Documentation targets:'
+	@$(MAKE) --no-print-directory -f Documentation/DocBook/Makefile dochelp
+	@echo  ''
+	@echo  'Architecture specific targets ($(ARCH)):'
+	@$(MAKE) --no-print-directory -f arch/$(ARCH)/boot/Makefile archhelp
+	@echo  ''
+	@echo  'Execute "make" or "make all" to build all targets marked with [*] '
+	@echo  'For further info browse Documentation/kbuild/*'
+ 
+
 # Documentation targets
 # ---------------------------------------------------------------------------
 
@@ -735,9 +785,9 @@
 			       $(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
 	               @$(rule_$(1)))
 
-# If quiet is set, only print short version of rule
+# If quiet is set, only print short version of command
 
-cmd = @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1))
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
 
 define update-if-changed
 	if [ -r $@ ] && cmp -s $@ $@.tmp; then \
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Fri Jul  5 16:42:59 2002
+++ b/Rules.make	Fri Jul  5 16:42:59 2002
@@ -34,7 +34,7 @@
 # $(srctree)/include/linux/module.h   : Some file relative to the source
 #				        dir root
 #
-# Those can only be used in the section after
+# $(obj) and $(src) can only be used in the section after
 # include $(TOPDIR)/Rules.make, i.e for generated files and the like.
 # Intentionally.
 #
@@ -43,8 +43,10 @@
 
 obj := .
 src := .
-objtree := $(TOPDIR)
-srctree := $(TOPDIR)
+
+# For use in the quiet output
+
+echo_target = $(RELDIR)/$@
 
 # Figure out what we need to build from the various variables
 # ===========================================================================
@@ -269,25 +271,25 @@
 	  -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \
 	  $(export_flags) 
 
-quiet_cmd_cc_s_c = CC     $(RELDIR)/$@
+quiet_cmd_cc_s_c = CC     $(echo_target)
 cmd_cc_s_c       = $(CC) $(c_flags) -S -o $@ $< 
 
 %.s: %.c FORCE
 	$(call if_changed_dep,cc_s_c)
 
-quiet_cmd_cc_i_c = CPP    $(RELDIR)/$@
+quiet_cmd_cc_i_c = CPP    $(echo_target)
 cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 
 %.i: %.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
-quiet_cmd_cc_o_c = CC     $(RELDIR)/$@
+quiet_cmd_cc_o_c = CC     $(echo_target)
 cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
 
 %.o: %.c FORCE
 	$(call if_changed_dep,cc_o_c)
 
-quiet_cmd_cc_lst_c = '  Generating $(RELDIR)/$@'
+quiet_cmd_cc_lst_c = '  Generating $(echo_target)'
 cmd_cc_lst_c     = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
 
 %.lst: %.c FORCE
@@ -304,13 +306,13 @@
 a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
 
-quiet_cmd_as_s_S = CPP    $(RELDIR)/$@
+quiet_cmd_as_s_S = CPP    $(echo_target)
 cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
 
 %.s: %.S FORCE
 	$(call if_changed_dep,as_s_S)
 
-quiet_cmd_as_o_S = AS     $(RELDIR)/$@
+quiet_cmd_as_o_S = AS     $(echo_target)
 cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
 
 %.o: %.S FORCE
@@ -328,10 +330,10 @@
 # Rule to compile a set of .o files into one .o file
 #
 ifdef O_TARGET
-quiet_cmd_link_o_target = LD     $(RELDIR)/$@
+quiet_cmd_link_o_target = LD     $(echo_target)
 # If the list of objects to link is empty, just create an empty O_TARGET
 cmd_link_o_target = $(if $(strip $(obj-y)),\
-		      $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
+		      $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
 		      rm -f $@; $(AR) rcs $@)
 
 $(O_TARGET): $(obj-y) FORCE
@@ -344,7 +346,7 @@
 # Rule to compile a set of .o files into one .a file
 #
 ifdef L_TARGET
-quiet_cmd_link_l_target = AR     $(RELDIR)/$@
+quiet_cmd_link_l_target = AR     $(echo_target)
 cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
 
 $(L_TARGET): $(obj-y) FORCE
@@ -357,8 +359,8 @@
 # Rule to link composite objects
 #
 
-quiet_cmd_link_multi = LD     $(RELDIR)/$@
-cmd_link_multi = $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
+quiet_cmd_link_multi = LD     $(echo_target)
+cmd_link_multi = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
 
 # We would rather have a list of rules like
 # 	foo.o: $(foo-objs)
@@ -379,22 +381,22 @@
 host-progs-multi      := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m)))
 host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs))
 
-quiet_cmd_host_cc__c  = HOSTCC $(RELDIR)/$@
-cmd_host_cc__c        = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+quiet_cmd_host_cc__c  = HOSTCC $(echo_target)
+cmd_host_cc__c        = $(HOSTCC) -Wp,-MD,$(depfile) \
 			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
 			$(HOST_LOADLIBES) -o $@ $<
 
 $(host-progs-single): %: %.c FORCE
 	$(call if_changed_dep,host_cc__c)
 
-quiet_cmd_host_cc_o_c = HOSTCC $(RELDIR)/$@
-cmd_host_cc_o_c       = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+quiet_cmd_host_cc_o_c = HOSTCC $(echo_target)
+cmd_host_cc_o_c       = $(HOSTCC) -Wp,-MD,$(depfile) \
 			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
 
 $(host-progs-multi-objs): %.o: %.c FORCE
 	$(call if_changed_dep,host_cc_o_c)
 
-quiet_cmd_host_cc__o  = HOSTLD $(RELDIR)/$@
+quiet_cmd_host_cc__o  = HOSTLD $(echo_target)
 cmd_host_cc__o        = $(HOSTCC) $(HOSTLDFLAGS) -o $@ $($@-objs) \
 			$(HOST_LOADLIBES)
 
@@ -410,9 +412,39 @@
 # ===========================================================================
 
 %:: %_shipped
-	@echo '  CP     $(RELDIR)/$@'
+	@echo '  CP     $(echo_target)'
 	@cp $< $@
 
+# Commands useful for building a boot image
+# ===========================================================================
+# 
+#	Use as following:
+#
+#	target: source(s) FORCE
+#		$(if_changed,ld/objcopy)
+#
+#	and add target to EXTRA_TARGETS so that we know we have to
+#	read in the saved command line
+
+# Linking
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ld = LD     $(echo_target)
+cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$@) \
+	       $(filter-out FORCE,$^) -o $@ 
+
+# Objcopy
+# ---------------------------------------------------------------------------
+
+quiet_cmd_objcopy = OBJCPY $(echo_target)
+cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+
+# Gzip
+# ---------------------------------------------------------------------------
+
+quiet_cmd_gzip = GZIP   $(echo_target)
+cmd_gzip = gzip -f -9 < $< > $@
+
 # ===========================================================================
 # Generic stuff
 # ===========================================================================
@@ -520,4 +552,4 @@
 
 # If quiet is set, only print short version of command
 
-cmd = @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1))
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile
--- a/arch/alpha/Makefile	Fri Jul  5 16:42:56 2002
+++ b/arch/alpha/Makefile	Fri Jul  5 16:42:56 2002
@@ -10,7 +10,7 @@
 
 NM := $(NM) -B
 
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax
+LDFLAGS_vmlinux = -static -T arch/alpha/vmlinux.lds -N #-relax
 CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
 
 # Determine if we can use the BWX instructions with GAS.
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/arm/Makefile	Fri Jul  5 16:42:59 2002
@@ -7,7 +7,8 @@
 #
 # Copyright (C) 1995-2001 by Russell King
 
-LINKFLAGS	:=-p -X -T arch/arm/vmlinux.lds
+LDFLAGS_vmlinux	:=-p -X -T arch/arm/vmlinux.lds
+OBJCOPYFLAGS	:=-O binary -R .note -R .comment -S
 GZFLAGS		:=-9
 CFLAGS		+=-pipe
 
diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
--- a/arch/arm/boot/Makefile	Fri Jul  5 16:42:56 2002
+++ b/arch/arm/boot/Makefile	Fri Jul  5 16:42:56 2002
@@ -115,15 +115,15 @@
 export	SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS
 
 Image:	$(SYSTEM)
-	$(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) $@
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 bzImage: zImage
 
 zImage:	compressed/vmlinux
-	$(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 bootpImage: bootp/bootp
-	$(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	@$(MAKE) -C compressed vmlinux
diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
--- a/arch/arm/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/arm/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
@@ -78,7 +78,7 @@
 		$(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S)
 
 piggy.o:	$(SYSTEM)
-		$(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) piggy
+		$(OBJCOPY) $(OBJCOPYFLAGS) $(SYSTEM) piggy
 		gzip $(GZFLAGS) < piggy > piggy.gz
 		$(LD) -r -o $@ -b binary piggy.gz
 		rm -f piggy piggy.gz
diff -Nru a/arch/cris/Makefile b/arch/cris/Makefile
--- a/arch/cris/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/cris/Makefile	Fri Jul  5 16:43:00 2002
@@ -31,11 +31,11 @@
      else true; \
      fi && $(CROSS_COMPILE)ld -mcrislinux
 
-LINKFLAGS = -T $(LD_SCRIPT).tmp
+LDFLAGS_vmlinux = -T $(LD_SCRIPT).tmp
 
 # objcopy is used to make binary images from the resulting linked file
 
-OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
 
 # -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others
 
@@ -64,7 +64,7 @@
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux.bin: vmlinux
-	$(OBJCOPY) vmlinux vmlinux.bin
+	$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin
 
 timage: vmlinux.bin
 	cat vmlinux.bin cramfs.img >timage
diff -Nru a/arch/cris/boot/compressed/Makefile b/arch/cris/boot/compressed/Makefile
--- a/arch/cris/boot/compressed/Makefile	Fri Jul  5 16:42:50 2002
+++ b/arch/cris/boot/compressed/Makefile	Fri Jul  5 16:42:50 2002
@@ -8,7 +8,7 @@
 CFLAGS = -O2
 LD = ld-cris
 OBJCOPY = objcopy-cris
-
+OBJCOPYFLAGS = -O binary --remove-section=.bss
 OBJECTS = head.o misc.o
 
 # files to compress
@@ -18,7 +18,7 @@
 
 decompress.bin: $(OBJECTS)
 	$(LD) -T decompress.ld -o decompress.o $(OBJECTS)
-	$(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin
+	$(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin
 # save it for mkprod in the topdir.
 	cp decompress.bin $(TOPDIR)
 
diff -Nru a/arch/cris/boot/rescue/Makefile b/arch/cris/boot/rescue/Makefile
--- a/arch/cris/boot/rescue/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/cris/boot/rescue/Makefile	Fri Jul  5 16:42:59 2002
@@ -8,6 +8,7 @@
 CFLAGS = -O2
 LD = gcc-cris -mlinux -nostdlib
 OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
 
 all: rescue.bin testrescue.bin kimagerescue.bin
 
@@ -16,11 +17,11 @@
 
 rescue.bin: head.o
 	$(LD) -T rescue.ld -o rescue.o head.o
-	$(OBJCOPY) -O binary --remove-section=.bss rescue.o rescue.bin
+	$(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin
 	cp rescue.bin $(TOPDIR)
 
 testrescue.bin: testrescue.o
-	$(OBJCOPY) -O binary --remove-section=.bss testrescue.o tr.bin
+	$(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin
 # Pad it to 784 bytes
 	dd if=/dev/zero of=tmp2423 bs=1 count=784
 	cat tr.bin tmp2423 >testrescue_tmp.bin
@@ -28,7 +29,7 @@
 	rm tr.bin tmp2423 testrescue_tmp.bin
 
 kimagerescue.bin: kimagerescue.o
-	$(OBJCOPY) -O binary --remove-section=.bss kimagerescue.o ktr.bin
+	$(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin
 # Pad it to 784 bytes, that's what the rescue loader expects
 	dd if=/dev/zero of=tmp2423 bs=1 count=784
 	cat ktr.bin tmp2423 >kimagerescue_tmp.bin
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/i386/Makefile	Fri Jul  5 16:42:59 2002
@@ -16,10 +16,9 @@
 #           Added '-march' and '-mpreferred-stack-boundary' support
 #
 
-LD=$(CROSS_COMPILE)ld -m elf_i386
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS)
+LDFLAGS		:= -m elf_i386
+OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux := -T arch/i386/vmlinux.lds -e stext
 
 CFLAGS += -pipe
 
@@ -103,7 +102,7 @@
 DRIVERS	+= arch/i386/pci/pci.o
 endif
 
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEBOOT = +$(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux: arch/i386/vmlinux.lds
 
diff -Nru a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
--- a/arch/i386/boot/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/i386/boot/Makefile	Fri Jul  5 16:42:59 2002
@@ -25,25 +25,44 @@
 
 #RAMDISK := -DRAMDISK=512
 
+EXTRA_TARGETS	:= vmlinux.bin bvmlinux.bin bootsect bootsect.o \
+		   setup setup.o zImage bzImage
+
+host-progs	:= tools/build
+
+# 	Default
+
+boot: bzImage
+
+include $(TOPDIR)/Rules.make
+
 # ---------------------------------------------------------------------------
 
-BOOT_INCL =	$(TOPDIR)/include/linux/config.h \
-		$(TOPDIR)/include/linux/autoconf.h \
-		$(TOPDIR)/include/asm/boot.h
-
-zImage: bootsect setup compressed/vmlinux tools/build
-	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
-
-bzImage: bbootsect bsetup compressed/bvmlinux tools/build
-	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+zImage:  IMAGE_OFFSET := 0x1000
+zImage:  EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
+bzImage: IMAGE_OFFSET := 0x100000
+bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+bzImage: BUILDFLAGS   := -b
+
+quiet_cmd_image = BUILD  $(RELDIR)/$@
+cmd_image = tools/build $(BUILDFLAGS) bootsect setup vmlinux.bin \
+			$(ROOT_DEV) > $@
+
+zImage bzImage: bootsect setup vmlinux.bin tools/build FORCE
+	$(call if_changed,image)
+
+vmlinux.bin: compressed/vmlinux FORCE
+	$(call if_changed,objcopy)
+
+LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
+LDFLAGS_setup	 := -Ttext 0x0 -s --oformat binary -e begtext
 
-compressed/vmlinux: $(TOPDIR)/vmlinux
-	@$(MAKE) -C compressed vmlinux
+setup bootsect: %: %.o FORCE
+	$(call if_changed,ld)
+
+compressed/vmlinux: FORCE
+	@$(MAKE) IMAGE_OFFSET=$(IMAGE_OFFSET) -C compressed vmlinux
 
-compressed/bvmlinux: $(TOPDIR)/vmlinux
-	@$(MAKE) -C compressed bvmlinux
 
 zdisk: $(BOOTIMAGE)
 	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
@@ -58,48 +77,17 @@
 install: $(BOOTIMAGE)
 	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-tools/build: tools/build.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
-
-bootsect: bootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary -o $@ $<
-
-bootsect.o: bootsect.s
-	$(AS) -o $@ $<
-
-bootsect.s: bootsect.S Makefile $(BOOT_INCL)
-	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bbootsect: bbootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary $< -o $@
-
-bbootsect.o: bbootsect.s
-	$(AS) -o $@ $<
-
-bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
-	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-setup: setup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-setup.o: setup.s
-	$(AS) -o $@ $<
-
-setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bsetup: bsetup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-bsetup.o: bsetup.s
-	$(AS) -o $@ $<
-
-bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
 clean:
 	@echo 'Cleaning up (boot)'
-	@rm -f tools/build
+	@rm -f tools/build vmlinux.bin bvmlinux.bin
 	@rm -f setup bootsect zImage compressed/vmlinux.out
 	@rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
 	@$(MAKE) -C compressed clean
+
+archhelp:
+	@echo  '* bzImage	- Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
+	@echo  '  install	- Install kernel using'
+	@echo  '                  (your) ~/bin/installkernel or'
+	@echo  '                  (distribution) /sbin/installkernel or'
+	@echo  '        	  install to $$(INSTALL_PATH) and run lilo'
+
diff -Nru a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
--- a/arch/i386/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/i386/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
@@ -4,47 +4,26 @@
 # create a compressed vmlinux image from the original vmlinux
 #
 
-HEAD = head.o
-SYSTEM = $(TOPDIR)/vmlinux
+EXTRA_TARGETS	:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS	:= -traditional
 
-OBJECTS = $(HEAD) misc.o
+include $(TOPDIR)/Rules.make
 
-ZLDFLAGS = -e startup_32
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
 
-#
-# ZIMAGE_OFFSET is the load offset of the compression loader
-# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
-#
-ZIMAGE_OFFSET = 0x1000
-BZIMAGE_OFFSET = 0x100000
+vmlinux: head.o misc.o piggy.o FORCE
+	$(call if_changed,ld)
 
-ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
-BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
+vmlinux.bin: $(TOPDIR)/vmlinux FORCE
+	$(call if_changed,objcopy)
 
-all: vmlinux
+vmlinux.bin.gz: vmlinux.bin FORCE
+	$(call if_changed,gzip)
 
-vmlinux: piggy.o $(OBJECTS)
-	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
 
-bvmlinux: piggy.o $(OBJECTS)
-	$(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
-
-head.o: head.S
-	$(CC) $(AFLAGS) -traditional -c head.S
-
-comma	:= ,
-
-misc.o: misc.c
-	$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c
-
-piggy.o:	$(SYSTEM)
-	tmppiggy=_tmp_$$$$piggy; \
-	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
-	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
-	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
-	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-	$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
-	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
+piggy.o: vmlinux.scr vmlinux.bin.gz FORCE
+	$(call if_changed,ld)
 
 clean:
-	@rm -f vmlinux bvmlinux _tmp_*
+	@rm -f vmlinux vmlinux.bin vmlinux.bin.gz
diff -Nru a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/boot/compressed/vmlinux.scr	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,9 @@
+SECTIONS
+{
+  .data : { 
+	input_len = .;
+	LONG(input_data_end - input_data) input_data = .; 
+	*(.data) 
+	input_data_end = .; 
+	}
+}
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Fri Jul  5 16:42:56 2002
+++ b/arch/i386/kernel/apm.c	Fri Jul  5 16:42:56 2002
@@ -814,16 +814,16 @@
 	if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
 		use_apm_idle = 0;
 		last_jiffies = jiffies;
-		last_stime = current->times.tms_stime;
+		last_stime = current->stime;
 	} else if (jiffies_since_last_check > idle_period) {
 		unsigned int idle_percentage;
 
-		idle_percentage = current->times.tms_stime - last_stime;
+		idle_percentage = current->stime - last_stime;
 		idle_percentage *= 100;
 		idle_percentage /= jiffies_since_last_check;
 		use_apm_idle = (idle_percentage > idle_threshold);
 		last_jiffies = jiffies;
-		last_stime = current->times.tms_stime;
+		last_stime = current->stime;
 	}
 
 	bucket = IDLE_LEAKY_MAX;
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Fri Jul  5 16:42:48 2002
+++ b/arch/i386/mm/fault.c	Fri Jul  5 16:42:48 2002
@@ -56,12 +56,16 @@
 
 	for (;;) {
 	survive:
-		{
-			int fault = handle_mm_fault(current->mm, vma, start, 1);
-			if (!fault)
+		switch (handle_mm_fault(current->mm, vma, start, 1)) {
+			case VM_FAULT_SIGBUS:
 				goto bad_area;
-			if (fault < 0)
+			case VM_FAULT_OOM:
 				goto out_of_memory;
+			case VM_FAULT_MINOR:
+			case VM_FAULT_MAJOR:
+				break;
+			default:
+				BUG();
 		}
 		if (!size)
 			break;
@@ -239,16 +243,18 @@
 	 * the fault.
 	 */
 	switch (handle_mm_fault(mm, vma, address, write)) {
-	case 1:
-		tsk->min_flt++;
-		break;
-	case 2:
-		tsk->maj_flt++;
-		break;
-	case 0:
-		goto do_sigbus;
-	default:
-		goto out_of_memory;
+		case VM_FAULT_MINOR:
+			tsk->min_flt++;
+			break;
+		case VM_FAULT_MAJOR:
+			tsk->maj_flt++;
+			break;
+		case VM_FAULT_SIGBUS:
+			goto do_sigbus;
+		case VM_FAULT_OOM:
+			goto out_of_memory;
+		default:
+			BUG();
 	}
 
 	/*
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Fri Jul  5 16:42:50 2002
+++ b/arch/ia64/Makefile	Fri Jul  5 16:42:50 2002
@@ -13,7 +13,8 @@
 
 export AWK
 
-LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
+OBJCOPYFLAGS := --strip-all 
+LDFLAGS_vmlinux := -static -T arch/$(ARCH)/vmlinux.lds
 AFLAGS_KERNEL := -mconstant-gp
 EXTRA	=
 
@@ -100,7 +101,7 @@
 		-traditional arch/$(ARCH)/vmlinux.lds.S > $@
 
 compressed: vmlinux
-	$(OBJCOPY) --strip-all vmlinux vmlinux-tmp
+	$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux-tmp
 	gzip vmlinux-tmp
 	mv vmlinux-tmp.gz vmlinux.gz
 
diff -Nru a/arch/m68k/Makefile b/arch/m68k/Makefile
--- a/arch/m68k/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/m68k/Makefile	Fri Jul  5 16:43:00 2002
@@ -18,16 +18,16 @@
 
 # override top level makefile
 AS += -m68020
-LD += -m m68kelf
+LDFLAGS := -m m68kelf
 ifneq ($(COMPILE_ARCH),$(ARCH))
 	# prefix for cross-compiling binaries
 	CROSS_COMPILE = m68k-linux-
 endif
 
 ifndef CONFIG_SUN3
-LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
+LDFLAGS_vmlinux = -T $(TOPDIR)/arch/m68k/vmlinux.lds
 else
-LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N
+LDFLAGS_vmlinux = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N
 endif
 
 # without -fno-strength-reduce the 53c7xx.c driver fails ;-(
diff -Nru a/arch/mips/Makefile b/arch/mips/Makefile
--- a/arch/mips/Makefile	Fri Jul  5 16:42:50 2002
+++ b/arch/mips/Makefile	Fri Jul  5 16:42:50 2002
@@ -36,9 +36,9 @@
 # crossformat linking we rely on the elf2ecoff tool for format conversion.
 #
 GCCFLAGS	:= -G 0 -mno-abicalls -fno-pic
-LINKFLAGS	+= -static
+LDFLAGS_vmlinux	+= -static
 MODFLAGS	+= -mlong-calls
-LD		:= $(LD) -G 0
+LDFLAGS		:= -G 0
 
 ifdef CONFIG_REMOTE_DEBUG
 CFLAGS		:= $(CFLAGS) -g
@@ -270,7 +270,7 @@
 
 arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile
 	sed -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@
-LINKFLAGS	+= -T arch/$(ARCH)/ld.script
+LDFLAGS_vmlinux	+= -T arch/$(ARCH)/ld.script
 
 HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
 
diff -Nru a/arch/mips/philips/nino/ramdisk/Makefile b/arch/mips/philips/nino/ramdisk/Makefile
--- a/arch/mips/philips/nino/ramdisk/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/mips/philips/nino/ramdisk/Makefile	Fri Jul  5 16:42:59 2002
@@ -7,6 +7,6 @@
 #
 
 ramdisk.o: ramdisk.gz ld.script
-	$(LD) -T ld.script -b binary -o $@ ramdisk.gz
+	$(LD) $(LDFLAGS) -T ld.script -b binary -o $@ ramdisk.gz
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/mips64/Makefile b/arch/mips64/Makefile
--- a/arch/mips64/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/mips64/Makefile	Fri Jul  5 16:42:59 2002
@@ -35,7 +35,7 @@
 #
 CFLAGS		+= -I $(TOPDIR)/include/asm/gcc $(CFLAGS)
 CFLAGS		+= -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe
-LINKFLAGS	+= -G 0 -static # -N
+LDFLAGS_vmlinux	+= -G 0 -static # -N
 MODFLAGS	+= -mlong-calls
 
 ifdef CONFIG_REMOTE_DEBUG
@@ -118,7 +118,7 @@
 #
 ifdef CONFIG_BOOT_ELF32
 CFLAGS += -Wa,-32
-LINKFLAGS += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
 endif
 #
 # The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
@@ -126,13 +126,13 @@
 #
 ifdef CONFIG_BOOT_ELF64
 CFLAGS += -Wa,-32
-LINKFLAGS += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
 #AS += -64
-#LD += -m elf64bmip
-#LINKFLAGS += -T arch/mips64/ld.script.elf64
+#LDFLAGS += -m elf64bmip
+#LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf64
 endif
 
-LINKFLAGS += -Ttext $(LOADADDR)
+LDFLAGS_vmlinux += -Ttext $(LOADADDR)
 
 HEAD := arch/mips64/kernel/head.o arch/mips64/kernel/init_task.o
 
diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile
--- a/arch/parisc/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/parisc/Makefile	Fri Jul  5 16:42:59 2002
@@ -20,9 +20,8 @@
 FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
 
 CPP=$(CC) -E
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS =
-LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
+LDFLAGS_vmlinux =-T arch/parisc/vmlinux.lds
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
diff -Nru a/arch/ppc/8260_io/Config.help b/arch/ppc/8260_io/Config.help
--- a/arch/ppc/8260_io/Config.help	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/8260_io/Config.help	Fri Jul  5 16:43:00 2002
@@ -22,3 +22,6 @@
 CONFIG_SCC2_ENET
   Use MPC8xx serial communications controller 2 to drive Ethernet.
 
+CONFIG_DCACHE_DISABLE
+  This option allows you to run the kernel with data cache disabled.
+  Say Y if you experience CPM lock-ups.
diff -Nru a/arch/ppc/8260_io/Config.in b/arch/ppc/8260_io/Config.in
--- a/arch/ppc/8260_io/Config.in	Fri Jul  5 16:42:50 2002
+++ b/arch/ppc/8260_io/Config.in	Fri Jul  5 16:42:50 2002
@@ -2,7 +2,7 @@
 # MPC8260 Communication options
 #
 mainmenu_option next_comment
-comment 'MPC8260 Communication Options'
+comment 'MPC8260 CPM Options'
 bool 'Enable SCC Console' CONFIG_SCC_CONSOLE
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
@@ -30,4 +30,7 @@
       fi
   fi
 fi
+
+comment 'Generic MPC8260 Options'
+bool 'Disable data cache' CONFIG_DCACHE_DISABLE
 endmenu
diff -Nru a/arch/ppc/Config.help b/arch/ppc/Config.help
--- a/arch/ppc/Config.help	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/Config.help	Fri Jul  5 16:42:59 2002
@@ -1023,3 +1023,7 @@
   which has a small amount of memory.
 
   Say N here unless you know what you are doing.
+
+CONFIG_DEBUG_SPINLOCK
+  Say Y here and to CONFIG_SMP to include code to check for missing
+  spinlock initialization and some other common spinlock errors.
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Fri Jul  5 16:42:56 2002
+++ b/arch/ppc/Makefile	Fri Jul  5 16:42:56 2002
@@ -21,7 +21,7 @@
 KERNELLOAD	=0xc0000000
 endif
 
-LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
+LDFLAGS_vmlinux	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
 CPPFLAGS	:= $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
 AFLAGS		:= $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
 CFLAGS		:= $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \
@@ -108,7 +108,7 @@
 
 %_config: arch/ppc/configs/%_defconfig
 	rm -f .config arch/ppc/defconfig
-	cp -f arch/ppc/configs/$(@:config=defconfig) arch/ppc/defconfig
+	cp -f arch/ppc/configs/$(@:config=defconfig) .config
 
 archclean:
 	rm -f arch/ppc/kernel/{mk_defs,asm-offsets.h,find_name}
@@ -116,3 +116,24 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
+
+prepare: checkbin
+
+ifdef CONFIG_6xx
+# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later
+NEW_AS	:= $(shell echo dssall | $(AS) -o /dev/null >/dev/null 2>&1 ; echo $$?)
+GOODVER	:= 2.12.1
+else
+NEW_AS	:= 0
+endif
+
+ifneq ($(NEW_AS),0)
+checkbin:
+	@echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build'
+	@echo 'correctly with old versions of binutils.'
+	@echo '*** Please upgrade your binutils to ${GOODVER} or newer'
+	@false
+else
+checkbin:
+	@true
+endif
diff -Nru a/arch/ppc/boot/chrp/Makefile b/arch/ppc/boot/chrp/Makefile
--- a/arch/ppc/boot/chrp/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/boot/chrp/Makefile	Fri Jul  5 16:43:00 2002
@@ -11,7 +11,11 @@
 
 OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \
 	../common/ofcommon.o
+
+EXTRA_TARGETS	:= $(OBJS)
 LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
+
+# Utils
 ADDNOTE = ../utils/addnote
 PIGGYBACK = ../utils/piggyback
 
diff -Nru a/arch/ppc/boot/pmac/Makefile b/arch/ppc/boot/pmac/Makefile
--- a/arch/ppc/boot/pmac/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/boot/pmac/Makefile	Fri Jul  5 16:42:59 2002
@@ -15,6 +15,8 @@
 COMMONOBJS = start.o misc.o ../common/string.o ../common/ofcommon.o
 COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o
 CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o
+
+EXTRA_TARGETS	:= $(COFFOBJS) $(CHRPOBJS)
 LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
 
 MKNOTE := ../utils/mknote
diff -Nru a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile
--- a/arch/ppc/boot/prep/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/boot/prep/Makefile	Fri Jul  5 16:43:00 2002
@@ -21,14 +21,16 @@
 endif
 
 LD_ARGS				= -T ../ld.script -Ttext 0x00800000 -Bstatic
-obj-y				:= head.o ../simple/legacy.o misc.o of1275.o \
+boot-y				:= head.o ../simple/legacy.o misc.o of1275.o \
 					../common/util.o ../common/string.o \
 					../common/misc-common.o
 OBJCOPY_ARGS			= -O elf32-powerpc
 LIBS 				= ../lib/zlib.a
 
-obj-$(CONFIG_SERIAL_CONSOLE)	+= ../common/ns16550.o
-obj-$(CONFIG_VGA_CONSOLE)	+= vreset.o kbd.o
+boot-$(CONFIG_SERIAL_CONSOLE)	+= ../common/ns16550.o
+boot-$(CONFIG_VGA_CONSOLE)	+= vreset.o kbd.o
+
+EXTRA_TARGETS			:= $(boot-y)
 
 # Tools
 MKPREP				:= ../utils/mkprep
@@ -40,18 +42,18 @@
 
 all: zImage
 
-zImage: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o \
+zImage: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o \
 		$(MKPREP)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=.image=../images/vmlinux.gz \
 		--set-section-flags=.image=contents,alloc,load,readonly,data \
 		../common/dummy.o image.o
-	$(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS)
+	$(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr
 	$(MKPREP) -pbp $@ ../images/$@.prep
 	rm -f $@
 
-zImage.initrd: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz $(MKPREP) \
+zImage.initrd: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz $(MKPREP) \
 		../common/dummy.o
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=.ramdisk=../images/ramdisk.image.gz \
@@ -59,7 +61,7 @@
 		--add-section=.image=../images/vmlinux.gz \
 		--set-section-flags=.image=contents,alloc,load,readonly,data \
 		../common/dummy.o image.o
-	$(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS)
+	$(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr
 	$(MKPREP) -pbp $@ ../images/$@.prep
 	rm -f $@
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile	Fri Jul  5 16:42:48 2002
+++ b/arch/ppc/boot/simple/Makefile	Fri Jul  5 16:42:48 2002
@@ -122,24 +122,25 @@
 OBJCOPY_ARGS			:= -O elf32-powerpc
 
 # head.o and ../common/relocate.o must be at the start.
-obj-y				:= head.o ../common/relocate.o $(HEADHELP) \
+boot-y				:= head.o ../common/relocate.o $(HEADHELP) \
 				$(MISC) ../common/misc-common.o \
 				../common/string.o ../common/util.o
-obj-$(CONFIG_4xx)		+= embed_config.o
-obj-$(CONFIG_8xx)		+= embed_config.o
-obj-$(CONFIG_8260)		+= embed_config.o
-obj-$(CONFIG_BSEIP)		+= iic.o
-obj-$(CONFIG_MBX)		+= iic.o pci.o qspan_pci.o
-obj-$(CONFIG_RPXCLASSIC)	+= iic.o pci.o qspan_pci.o
-obj-$(CONFIG_RPXLITE)		+= iic.o
+boot-$(CONFIG_4xx)		+= embed_config.o
+boot-$(CONFIG_8xx)		+= embed_config.o
+boot-$(CONFIG_8260)		+= embed_config.o
+boot-$(CONFIG_BSEIP)		+= iic.o
+boot-$(CONFIG_MBX)		+= iic.o pci.o qspan_pci.o
+boot-$(CONFIG_RPXCLASSIC)	+= iic.o pci.o qspan_pci.o
+boot-$(CONFIG_RPXLITE)		+= iic.o
 # Different boards need different serial implementations.
 ifeq ($(CONFIG_SERIAL_CONSOLE),y)
-obj-$(CONFIG_8xx)		+= m8xx_tty.o
-obj-$(CONFIG_8260)		+= m8260_tty.o
-obj-$(CONFIG_GT64260_CONSOLE)   += gt64260_tty.o
-obj-$(CONFIG_SERIAL)		+= ../common/ns16550.o
+boot-$(CONFIG_8xx)		+= m8xx_tty.o
+boot-$(CONFIG_8260)		+= m8260_tty.o
+boot-$(CONFIG_GT64260_CONSOLE)   += gt64260_tty.o
+boot-$(CONFIG_SERIAL)		+= ../common/ns16550.o
 endif
 
+EXTRA_TARGETS			:= $(boot-y)
 LIBS				:= ../lib/zlib.a
 
 # Tools
@@ -147,16 +148,16 @@
 MKPREP				:= ../utils/mkprep
 MKTREE				:= ../utils/mktree
 
-zvmlinux: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
+zvmlinux: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
 	$(OBJCOPY) $(OBJCOPY_ARGS) \
 		--add-section=.image=../images/vmlinux.gz \
 		--set-section-flags=.image=contents,alloc,load,readonly,data \
 		../common/dummy.o image.o
-	$(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS)
+	$(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \
 		-R .ramdisk -R .sysmap
 
-zvmlinux.initrd: $(obj-y) $(LIBS) ../ld.script ../images/vmlinux.gz \
+zvmlinux.initrd: $(boot-y) $(LIBS) ../ld.script ../images/vmlinux.gz \
 		../common/dummy.o
 	$(OBJCOPY) $(OBJCOPY_ARGS) \
 		--add-section=.ramdisk=../images/ramdisk.image.gz \
@@ -164,7 +165,7 @@
 		--add-section=.image=../images/vmlinux.gz \
 		--set-section-flags=.image=contents,alloc,load,readonly,data \
 		../common/dummy.o image.o
-	$(LD) $(LD_ARGS) -o $@ $(obj-y) image.o $(LIBS)
+	$(LD) $(LD_ARGS) -o $@ $(boot-y) image.o $(LIBS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \
 		-R .sysmap
 
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Fri Jul  5 16:42:48 2002
+++ b/arch/ppc/config.in	Fri Jul  5 16:42:48 2002
@@ -288,9 +288,6 @@
    if [ "$CONFIG_8xx" = "y" ]; then
       bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
    fi
-   if [ "$CONFIG_40x" = "y" ]; then
-      bool "Pinned Kernel TLBs" CONFIG_PIN_TLB
-   fi
    if [ "$CONFIG_ALL_PPC" != "y" ]; then
       bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL
       if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then
@@ -605,6 +602,7 @@
 comment 'Kernel hacking'
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 if [ "$CONFIG_KGDB" = "y" ]; then
    choice 'Serial Port'			\
diff -Nru a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig
--- a/arch/ppc/configs/est8260_defconfig	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/configs/est8260_defconfig	Fri Jul  5 16:43:00 2002
@@ -421,6 +421,7 @@
 CONFIG_SCC_ENET=y
 CONFIG_SCC1_ENET=y
 # CONFIG_FEC_ENET is not set
+# CONFIG_DCACHE_DISABLE is not set
 
 #
 # USB support
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/cputable.c	Fri Jul  5 16:43:00 2002
@@ -204,7 +204,7 @@
     {	/* 7450 2.1 */
     	0xffffffff, 0x80000201, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -213,7 +213,7 @@
     {	/* 7450 2.3 and newer */
     	0xffff0000, 0x80000000, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -222,7 +222,7 @@
     {	/* 7455 */
     	0xffff0000, 0x80010000, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/kernel/entry.S	Fri Jul  5 16:42:59 2002
@@ -164,7 +164,6 @@
 	andi.	r0,r9,(_TIF_SYSCALL_TRACE|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
 	bne-	syscall_exit_work
 syscall_exit_cont:
-	PPC405_ERR77(0,r1)
 	stwcx.	r0,0,r1			/* to clear the reservation */
 	lwz	r4,_LINK(r1)
 	lwz	r5,_CCR(r1)
@@ -568,6 +567,7 @@
 exc_exit_restart_end:
 	PPC405_ERR77_SYNC
 	rfi
+	b	.			/* prevent prefetch past rfi */
 crit_exc_exit:
 	mtcrf	0xff,r10
 	/* avoid any possible TLB misses here by turning off MSR.DR, we
@@ -576,18 +576,40 @@
 	mtmsr	r10
 	isync
 	tophys(r1, r1)
-	lwz	r9,_SRR0(r1)
-	lwz	r10,_SRR1(r1)
-	mtspr	SRR0,r9
+	lwz	r9,_DEAR(r1)
+	lwz	r10,_ESR(r1)
+	mtspr	SPRN_DEAR,r9
+	mtspr	SPRN_ESR,r10
 	lwz	r11,_NIP(r1)
-	mtspr	SRR1,r10
 	lwz	r12,_MSR(r1)
 	mtspr	SRR2,r11
 	mtspr	SRR3,r12
-	REST_4GPRS(9, r1)
+	lwz	r9,GPR9(r1)
+	lwz	r12,GPR12(r1)
+	lwz	r10,crit_sprg0@l(0)
+	mtspr	SPRN_SPRG0,r10
+	lwz	r10,crit_sprg1@l(0)
+	mtspr	SPRN_SPRG1,r10
+	lwz	r10,crit_sprg4@l(0)
+	mtspr	SPRN_SPRG4,r10
+	lwz	r10,crit_sprg5@l(0)
+	mtspr	SPRN_SPRG5,r10
+	lwz	r10,crit_sprg6@l(0)
+	mtspr	SPRN_SPRG6,r10
+	lwz	r10,crit_sprg7@l(0)
+	mtspr	SPRN_SPRG7,r10
+	lwz	r10,crit_srr0@l(0)
+	mtspr	SRR0,r10
+	lwz	r10,crit_srr1@l(0)
+	mtspr	SRR1,r10
+	lwz	r10,crit_pid@l(0)
+	mtspr	SPRN_PID,r10
+	lwz	r10,crit_r10@l(0)
+	lwz	r11,crit_r11@l(0)
 	lwz	r1,GPR1(r1)
 	PPC405_ERR77_SYNC
 	rfci
+	b	.		/* prevent prefetch past rfci */
 #endif /* CONFIG_4xx */
 
 recheck:
@@ -650,6 +672,10 @@
 	mr	r12,r11		/* restart at exc_exit_restart */
 	blr
 3:	/* OK, we can't recover, kill this process */
+	/* but the 601 doesn't implement the RI bit, so assume it's OK */
+BEGIN_FTR_SECTION
+	blr
+END_FTR_SECTION_IFSET(CPU_FTR_601)
 	lwz	r3,TRAP(r1)
 	andi.	r0,r3,1
 	beq	4f
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Fri Jul  5 16:42:50 2002
+++ b/arch/ppc/kernel/head.S	Fri Jul  5 16:42:50 2002
@@ -832,7 +832,12 @@
 
 /* aargh, a nonrecoverable interrupt, panic */
 /* aargh, we don't know which trap this is */
-3:	li	r10,0
+/* but the 601 doesn't implement the RI bit, so assume it's OK */
+3:
+BEGIN_FTR_SECTION
+	b	2b
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+	li	r10,-1
 	stw	r10,TRAP(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	li	r10,MSR_KERNEL
@@ -887,9 +892,9 @@
 	add	r4,r4,r6
 	addi	r4,r4,THREAD	/* want THREAD of last_task_used_altivec */
 	SAVE_32VR(0,r10,r4)
-	MFVSCR(vr0)
+	mfvscr	vr0
 	li	r10,THREAD_VSCR
-	STVX(vr0,r10,r4)
+	stvx	vr0,r10,r4
 	lwz	r5,PT_REGS(r4)
 	add	r5,r5,r6
 	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
@@ -902,8 +907,8 @@
 	oris	r9,r9,MSR_VEC@h
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
 	li	r10,THREAD_VSCR
-	LVX(vr0,r10,r5)
-	MTVSCR(vr0)
+	lvx	vr0,r10,r5
+	mtvscr	vr0
 	REST_32VR(0,r10,r5)
 #ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
@@ -951,9 +956,9 @@
 	lwz	r5,PT_REGS(r3)
 	cmpi	0,r5,0
 	SAVE_32VR(0, r4, r3)
-	MFVSCR(vr0)
+	mfvscr	vr0
 	li	r4,THREAD_VSCR
-	STVX(vr0, r4, r3)
+	stvx	vr0,r4,r3
 	beq	1f
 	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	lis	r3,MSR_VEC@h
@@ -1272,7 +1277,11 @@
 setup_common_caches:
 	mfspr	r11,HID0
 	andi.	r0,r11,HID0_DCE
+#ifdef CONFIG_DCACHE_DISABLE
+	ori	r11,r11,HID0_ICE
+#else
 	ori	r11,r11,HID0_ICE|HID0_DCE
+#endif
 	ori	r8,r11,HID0_ICFI
 	bne	1f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
@@ -1362,7 +1371,7 @@
 	isync
 	blr
 
-/* 7450
+/* 7455
  * Enable Store Gathering (SGE), Branch Folding (FOLD)
  * Branch History Table (BHTE), Branch Target ICache (BTIC)
  * Dynamic Power Management (DPM), Speculative (SPD)
@@ -1546,7 +1555,7 @@
 #endif
 	li	r4,0
 BEGIN_FTR_SECTION
-	dssall	0
+	dssall
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 3:
diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/kernel/head_4xx.S	Fri Jul  5 16:42:59 2002
@@ -82,6 +82,7 @@
 	mtspr	SRR0,r0
 	SYNC
 	rfi				/* enables MMU */
+	b	.			/* prevent prefetch past rfi */
 
 /*
  * This area is used for temporarily saving registers during the
@@ -89,7 +90,28 @@
  */
 	. = 0xc0
 crit_save:
-	.space	8
+_GLOBAL(crit_r10)
+	.space	4
+_GLOBAL(crit_r11)
+	.space	4
+_GLOBAL(crit_sprg0)
+	.space	4
+_GLOBAL(crit_sprg1)
+	.space	4
+_GLOBAL(crit_sprg4)
+	.space	4
+_GLOBAL(crit_sprg5)
+	.space	4
+_GLOBAL(crit_sprg6)
+	.space	4
+_GLOBAL(crit_sprg7)
+	.space	4
+_GLOBAL(crit_pid)
+	.space	4
+_GLOBAL(crit_srr0)
+	.space	4
+_GLOBAL(crit_srr1)
+	.space	4
 
 /*
  * Exception vector entry code. This code runs with address translation
@@ -140,6 +162,59 @@
  * This is OK since we don't support SMP on these processors.
  */
 #define CRITICAL_EXCEPTION_PROLOG					     \
+	stw	r10,crit_r10@l(0);	/* save two registers to work with */\
+	stw	r11,crit_r11@l(0);					     \
+	mfspr	r10,SPRG0;						     \
+	stw	r10,crit_sprg0@l(0);					     \
+	mfspr	r10,SPRG1;						     \
+	stw	r10,crit_sprg1@l(0);					     \
+	mfspr	r10,SPRG4;						     \
+	stw	r10,crit_sprg4@l(0);					     \
+	mfspr	r10,SPRG5;						     \
+	stw	r10,crit_sprg5@l(0);					     \
+	mfspr	r10,SPRG6;						     \
+	stw	r10,crit_sprg6@l(0);					     \
+	mfspr	r10,SPRG7;						     \
+	stw	r10,crit_sprg7@l(0);					     \
+	mfspr	r10,SPRN_PID;						     \
+	stw	r10,crit_pid@l(0);					     \
+	mfspr	r10,SRR0;						     \
+	stw	r10,crit_srr0@l(0);					     \
+	mfspr	r10,SRR1;						     \
+	stw	r10,crit_srr1@l(0);					     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_SRR3;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	lis	r11,critical_stack_top@h;				     \
+	ori	r11,r11,critical_stack_top@l;				     \
+	beq	1f;							     \
+	/* COMING FROM USER MODE */					     \
+	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+	addi	r11,r11,THREAD_SIZE;					     \
+1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	tophys(r11,r11);						     \
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r12,SPRN_DEAR;		/* save DEAR and ESR in the frame  */\
+	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
+	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
+	stw	r9,_ESR(r11);		/* exception was taken		   */\
+	mfspr	r12,SRR2;						     \
+	stw	r1,GPR1(r11);						     \
+	mfspr	r9,SRR3;						     \
+	stw	r1,0(r11);						     \
+	tovirt(r1,r11);							     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+#if 0
+#define CRITICAL_EXCEPTION_PROLOG					     \
 	stw	r10,crit_save@l(0);	/* save two registers to work with */\
 	stw	r11,4+crit_save@l(0);					     \
 	mfcr	r10;			/* save CR in r10 for now	   */\
@@ -173,6 +248,7 @@
 	stw	r0,GPR0(r11);						     \
 	SAVE_4GPRS(3, r11);						     \
 	SAVE_2GPRS(7, r11)
+#endif
 
 /*
  * Exception vectors.
@@ -197,13 +273,14 @@
 	START_EXCEPTION(n, label);				\
 	CRITICAL_EXCEPTION_PROLOG;				\
 	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
-	EXC_XFER_TEMPLATE(hdlr, n+2, NOCOPY, transfer_to_handler_full, \
+	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+			  NOCOPY, transfer_to_handler_full, \
 			  ret_from_except_full)
 
-#define EXC_XFER_TEMPLATE(hdlr, trap, copyee, tfer, ret)	\
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)	\
 	li	r10,trap;					\
 	stw	r10,TRAP(r11);					\
-	li	r10,MSR_KERNEL;					\
+	li	r10,msr;					\
 	copyee(r10, r9);					\
 	bl	tfer;		 				\
 	.long	hdlr;						\
@@ -213,19 +290,19 @@
 #define NOCOPY(d, s)
 
 #define EXC_XFER_STD(n, hdlr)		\
-	EXC_XFER_TEMPLATE(hdlr, n, NOCOPY, transfer_to_handler_full, \
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
 			  ret_from_except_full)
 
 #define EXC_XFER_LITE(n, hdlr)		\
-	EXC_XFER_TEMPLATE(hdlr, n+1, NOCOPY, transfer_to_handler, \
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
 			  ret_from_except)
 
 #define EXC_XFER_EE(n, hdlr)		\
-	EXC_XFER_TEMPLATE(hdlr, n, COPY_EE, transfer_to_handler_full, \
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
 			  ret_from_except_full)
 
 #define EXC_XFER_EE_LITE(n, hdlr)	\
-	EXC_XFER_TEMPLATE(hdlr, n+1, COPY_EE, transfer_to_handler, \
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
 			  ret_from_except)
 
 
@@ -347,6 +424,7 @@
 	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
+	b	.		/* prevent prefetch past rfi */
 
 2:
 	/* The bailout.  Restore registers to pre-exception conditions
@@ -615,6 +693,7 @@
 	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
+	b	.		/* prevent prefetch past rfi */
 
 2:
 	/* The bailout.  Restore registers to pre-exception conditions
@@ -721,6 +800,7 @@
 
 	sync
 	rfci                            /* return to the exception handler  */
+	b	.			/* prevent prefetch past rfi */
 
 2:
 	mtcrf   0xff,r10                /* restore registers */
@@ -746,31 +826,18 @@
 	 * Actually, it will fit now, but oh well.....a common place
 	 * to load the TLB.
 	 */
+tlb_4xx_index:
+	.long	0
 finish_tlb_load:
-
-	/* Since it has a unified TLB, and we can take data faults on
-	 * instruction pages by copying data, we have to check if the
-	 * EPN is already in the TLB.
-	 */
-	tlbsx.	r9, 0, r10
-	beq	6f
-
 	/* load the next available TLB index.
 	*/
-	lis	r12, tlb_4xx_index@h
-	ori	r12, r12, tlb_4xx_index@l
-	tophys(r12, r12)
-	lwz	r9, 0(r12)
+	lwz	r9, tlb_4xx_index@l(0)
 	addi	r9, r9, 1
-#ifdef CONFIG_PIN_TLB
 	cmpwi	0, r9, 61		/* reserve entries 62, 63 for kernel */
 	ble	7f
 	li	r9, 0
 7:
-#else
-	andi.	r9, r9, (PPC4XX_TLB_SIZE-1)
-#endif
-	stw	r9, 0(r12)
+	stw	r9, tlb_4xx_index@l(0)
 
 6:
 	tlbwe	r11, r9, TLB_DATA		/* Load TLB LO */
@@ -804,6 +871,7 @@
 	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
+	b	.		/* prevent prefetch past rfi */
 
 /* extern void giveup_fpu(struct task_struct *prev)
  *
@@ -857,14 +925,11 @@
 	mtspr	SRR0,r4
 	mtspr	SRR1,r3
 	rfi
+	b	.		/* prevent prefetch past rfi */
 
 /* Load up the kernel context */
 2:
 	SYNC			/* Force all PTE updates to finish */
-#ifndef CONFIG_PIN_TLB
-	tlbia			/* Clear all TLB entries */
-	sync			/* wait for tlbia/tlbie to finish */
-#endif
 
 	/* set up the PTE pointers for the Abatron bdiGDB.
 	*/
@@ -883,6 +948,7 @@
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
+	b	.		/* prevent prefetch past rfi */
 
 /* Set up the initial MMU state so we can do the first level of
  * kernel initialization.  This maps the first 16 MBytes of memory 1:1
@@ -956,7 +1022,10 @@
 	lwz	r5, 0xf0(r5)
 	stw	r4, 0x4(r5)
 #endif
+	sync
 	mtspr	SPRN_PID,r3
+	isync				/* Need an isync to flush shadow */
+					/* TLBs after changing PID */
 	blr
 
 /* We put a few things here that have to be page-aligned. This stuff
@@ -968,6 +1037,14 @@
 	.space	4096
 _GLOBAL(swapper_pg_dir)
 	.space	4096
+
+	
+/* Stack for handling critical exceptions from kernel mode */
+	.section .bss
+critical_stack_bottom:
+	.space	4096
+critical_stack_top:
+	.previous
 
 /* This space gets a copy of optional info passed to us by the bootstrap
  * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
diff -Nru a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S
--- a/arch/ppc/kernel/l2cr.S	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/l2cr.S	Fri Jul  5 16:43:00 2002
@@ -255,7 +255,7 @@
 	isync
 
 	/* Stop DST streams */
-	dssall	0
+	dssall
 	
 	/* Get the current enable bit of the L3CR into r4 */
 	mfspr	r4,SPRN_L3CR
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/kernel/misc.S	Fri Jul  5 16:42:59 2002
@@ -354,7 +354,7 @@
  * Flush MMU TLB
  */
 _GLOBAL(_tlbia)
-#if defined(CONFIG_40x) && defined(CONFIG_PIN_TLB)
+#if defined(CONFIG_40x)
 	/* This needs to be coordinated with other pinning functions since
 	 * we don't keep a memory location of number of entries to reduce
 	 * cache pollution during these operations.
@@ -367,7 +367,7 @@
 	cmpwi	0, r3, 61		/* reserve last two entries */
 	ble	1b
 	isync
-#else
+#else /* ! defined(CONFIG_40x) */
 #if defined(CONFIG_SMP)
 	rlwinm	r8,r1,0,0,18
 	lwz	r8,TI_CPU(r8)
@@ -401,7 +401,7 @@
 	tlbia
 	sync
 #endif /* CONFIG_SMP */
-#endif /* defined(CONFIG_40x) && defined(CONFIG_PIN_TLB) */
+#endif /* ! defined(CONFIG_40x) */
 	blr	
 
 /*
@@ -412,7 +412,7 @@
 	tlbsx.	r3, 0, r3
 	bne	10f
 	sync
-	/* There are only 64 TLB entries, so r3 < 64, which means bit 25, is clear.
+	/* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear.
 	 * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate
 	 * the TLB entry. */
 	tlbwe	r3, r3, TLB_TAG
diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
--- a/arch/ppc/kernel/mk_defs.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/mk_defs.c	Fri Jul  5 16:43:00 2002
@@ -112,8 +112,6 @@
 	 */
 	DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
 	DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
-	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
-	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
 	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
 	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/open_pic.c	Fri Jul  5 16:43:00 2002
@@ -302,7 +302,7 @@
 		ISR[i] = src;
 }
 
-void __init openpic_init(int main_pic, int offset, int programmer_switch_irq)
+void __init openpic_init(int linux_irq_offset)
 {
 	u_int t, i;
 	u_int timerfreq;
@@ -351,16 +351,13 @@
 		printk("OpenPIC timer frequency is %d.%06d MHz\n",
 		       timerfreq / 1000000, timerfreq % 1000000);
 
-	if (!main_pic)
-		return;
-
-	open_pic_irq_offset = offset;
+	open_pic_irq_offset = linux_irq_offset;
 
 	/* Initialize timer interrupts */
 	if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		/* Disabled, Priority 0 */
-		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
+		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+linux_irq_offset);
 		/* No processor */
 		openpic_maptimer(i, 0);
 	}
@@ -370,10 +367,12 @@
 	if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 		/* Disabled, Priority 10..13 */
-		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
+		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+linux_irq_offset);
 		/* IPIs are per-CPU */
-		irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
-		irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
+		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].status |=
+			IRQ_PER_CPU;
+		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].handler =
+			&open_pic_ipi;
 	}
 #endif
 
@@ -384,15 +383,14 @@
 
 	/* Init all external sources, including possibly the cascade. */
 	for (i = 0; i < NumSources; i++) {
-		int pri, sense;
+		int sense;
 
 		if (ISR[i] == 0)
 			continue;
 
 		/* the bootloader may have left it enabled (bad !) */
-		openpic_disable_irq(i+offset);
+		openpic_disable_irq(i+linux_irq_offset);
 
-		pri = (i == programmer_switch_irq)? 9: 8;
 		/*
 		 * We find the vale from either the InitSenses table
 		 * or assume a negative polarity level interrupt.
@@ -400,26 +398,27 @@
 		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
 
 		if ((sense & IRQ_SENSE_MASK) == 1)
-			irq_desc[i+offset].status = IRQ_LEVEL;
+			irq_desc[i+linux_irq_offset].status = IRQ_LEVEL;
 
-		/* Enabled, Priority 8 or 9 */
-		openpic_initirq(i, pri, i+offset, (sense & IRQ_POLARITY_MASK),
+		/* Enabled, Priority 8 */
+		openpic_initirq(i, 8, i + linux_irq_offset,
+				(sense & IRQ_POLARITY_MASK),
 				(sense & IRQ_SENSE_MASK));
 		/* Processor 0 */
 		openpic_mapirq(i, 1<<0, 0);
 	}
 
 	/* Init descriptors */
-	for (i = offset; i < NumSources + offset; i++)
+	for (i = linux_irq_offset; i < NumSources + linux_irq_offset; i++)
 		irq_desc[i].handler = &open_pic;
 
 	/* Initialize the spurious interrupt */
 	if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
-	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
+	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+linux_irq_offset);
 
 	/* Initialize the cascade */
-	if (offset) {
-		if (request_irq(offset, no_action, SA_INTERRUPT,
+	if (linux_irq_offset) {
+		if (request_irq(linux_irq_offset, no_action, SA_INTERRUPT,
 				"82c59 cascade", NULL))
 			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
 	}
@@ -653,6 +652,31 @@
 		      physmask(cpumask));
 }
 
+/*
+ * Initalize the interrupt source which will generate an NMI (and disable it).
+ *
+ * irq: The logical IRQ which generates an NMI.
+ */
+void __init
+openpic_init_nmi_irq(u_int irq)
+{
+	int sense;
+
+	/* If this wasn't given, assume a level, negative polarity interrupt. */
+	sense = (irq < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[irq] :
+		(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
+
+	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
+				(9 << OPENPIC_PRIORITY_SHIFT) |
+				(irq + open_pic_irq_offset) |
+				((sense & IRQ_POLARITY_MASK) ?
+				 OPENPIC_POLARITY_POSITIVE :
+				 OPENPIC_POLARITY_NEGATIVE) |
+				((sense & IRQ_SENSE_MASK) ? OPENPIC_SENSE_LEVEL
+				 : OPENPIC_SENSE_EDGE));
+}
 
 /*
  *
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/pci.c	Fri Jul  5 16:43:00 2002
@@ -923,6 +923,7 @@
 			   struct device_node *dev, int primary)
 {
 	unsigned int *ranges, *prev;
+	unsigned int size;
 	int rlen = 0;
 	int memno = 0;
 	struct resource *res;
@@ -963,12 +964,16 @@
 	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
 	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
+		size = ranges[na+4];
 		switch (ranges[0] >> 24) {
 		case 1:		/* I/O space */
 			if (ranges[2] != 0)
 				break;
 			hose->io_base_phys = ranges[na+2];
-			hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]);
+			/* limit I/O space to 16MB */
+			if (size > 0x01000000)
+				size = 0x01000000;
+			hose->io_base_virt = ioremap(ranges[na+2], size);
 			if (primary)
 				isa_io_base = (unsigned long) hose->io_base_virt;
 			res = &hose->io_resource;
@@ -997,7 +1002,7 @@
 		}
 		if (res != NULL) {
 			res->name = dev->full_name;
-			res->end = res->start + ranges[na+4] - 1;
+			res->end = res->start + size - 1;
 			res->parent = NULL;
 			res->sibling = NULL;
 			res->child = NULL;
diff -Nru a/arch/ppc/kernel/ppc4xx_pic.c b/arch/ppc/kernel/ppc4xx_pic.c
--- a/arch/ppc/kernel/ppc4xx_pic.c	Fri Jul  5 16:42:41 2002
+++ b/arch/ppc/kernel/ppc4xx_pic.c	Fri Jul  5 16:42:41 2002
@@ -15,10 +15,14 @@
  * there are eight internal interrupts for the on-chip serial port
  * (SPU), DMA controller, and JTAG controller.
  *
- * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
- * possible interrupts as well. There are seven, configurable external
- * interrupt pins and there are 17 internal interrupts for the on-chip
- * serial port, DMA controller, on-chip Ethernet controller, PCI, etc.
+ * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has
+ * 32 possible interrupts as well.  Depending on the core and SoC
+ * implementation, a portion of the interrrupts are used for on-chip
+ * peripherals and a portion of the interrupts are available to be
+ * configured for external devices generating interrupts.
+ *
+ * The PowerNP and 440GP (and most likely future implementations) have
+ * cascaded UICs.
  *
  */
 
@@ -30,11 +34,9 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <asm/ibm4xx.h>
 #include <asm/ppc4xx_pic.h>
 
 /* Global Variables */
-
 struct hw_interrupt_type *ppc4xx_pic;
 
 /* Six of one, half dozen of the other....#ifdefs, separate files,
@@ -128,7 +130,11 @@
 	mtdcr(DCRN_EXISR, (1 << (31 - bit)));
 }
 
-#else				/* !CONFIG_403 */
+#else
+
+#ifndef UIC1
+#define UIC1 UIC0
+#endif
 
 static void
 ppc405_uic_enable(unsigned int irq)
@@ -137,9 +143,18 @@
 
 	bit = irq & 0x1f;
 	word = irq >> 5;
-
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
 	ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-	mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]);
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+		break;
+		case 1:
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+		break;
+	}
 }
 
 static void
@@ -149,9 +164,18 @@
 
 	bit = irq & 0x1f;
 	word = irq >> 5;
-
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_disable - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
 	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]);
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+		break;
+		case 1:
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+		break;
+	}
 }
 
 static void
@@ -162,9 +186,20 @@
 	bit = irq & 0x1f;
 	word = irq >> 5;
 
+#ifdef UIC_DEBUG	
+printk("ppc405_uic_disable_and_ack - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
 	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]);
-	mtdcr(DCRN_UIC0_SR, (1 << (31 - bit)));
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+			mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
+		break;
+		case 1:	
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+			mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
+		break;
+	}
 }
 
 static void
@@ -176,23 +211,49 @@
 	bit = irq & 0x1f;
 	word = irq >> 5;
 
-	tr_bits = mfdcr(DCRN_UIC0_TR);
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_end - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
+
+	switch (word){
+		case 0:
+			tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
+		break;
+		case 1:
+			tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
+		break;
+	}
+
 	if ((tr_bits & (1 << (31 - bit))) == 0) {
 		/* level trigger */
-		mtdcr(DCRN_UIC0_SR, 1 << (31 - bit));
+		switch (word){
+			case 0:
+				mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
+			break;
+			case 1:
+				mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
+			break;
+		}
 	}
 
 	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 		ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-		mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]);
+		switch (word){
+			case 0:
+				mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+			break;
+			case 1:
+				mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+			break;
+		}
 	}
 }
 
 static struct hw_interrupt_type ppc405_uic = {
-#if defined (CONFIG_405GP)
-	"405GP UIC",
+#if (NR_UICS == 1)
+	"IBM UIC",
 #else
-	"NP405 UIC",
+	"IBM UIC Cascade",
 #endif
 	NULL,
 	NULL,
@@ -206,16 +267,27 @@
 int
 ppc405_pic_get_irq(struct pt_regs *regs)
 {
-	int irq;
+	int irq, cas_irq;
 	unsigned long bits;
-
+	cas_irq = 0;
 	/*
 	 * Only report the status of those interrupts that are actually
 	 * enabled.
 	 */
 
-	bits = mfdcr(DCRN_UIC0_MSR);
+	bits = mfdcr(DCRN_UIC_MSR(UIC0));
 
+#if (NR_UICS > 1) 
+	if (bits & UIC_CASCADE_MASK){
+		bits = mfdcr(DCRN_UIC_MSR(UIC1));
+		cas_irq = 32 - ffs(bits);
+		irq = 32 + cas_irq;
+	} else {
+		irq = 32 - ffs(bits);
+		if (irq == 32)
+			irq= -1;
+	}
+#else
 	/*
 	 * Walk through the interrupts from highest priority to lowest, and
 	 * report the first pending interrupt found.
@@ -223,10 +295,14 @@
 	 * result from 32.
 	 */
 	irq = 32 - ffs(bits);
-
-	if (irq == NR_AIC_IRQS)
+#endif
+	if (irq == (NR_UIC_IRQS * NR_UICS))
 		irq = -1;
 
+#ifdef UIC_DEBUG
+printk("ppc405_pic_get_irq - irq %d bit 0x%x\n",irq, bits);
+#endif
+
 	return (irq);
 }
 #endif
@@ -239,18 +315,31 @@
 	 * explicity requested.
 	 */
 	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0;
 
-#ifdef CONFIG_403
+#if defined CONFIG_403
 	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
 
 	ppc4xx_pic = &ppc403_aic;
 	ppc_md.get_irq = ppc403_pic_get_irq;
 #else
-	mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[0]);
+#if  (NR_UICS > 1) 
+	ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC ); /* enable cascading interrupt */
+	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
+	mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]);
+
+	/* Set all interrupts to non-critical.
+	 */
+	mtdcr(DCRN_UIC_CR(UIC0), 0);
+	mtdcr(DCRN_UIC_CR(UIC1), 0);
+
+#else	
+	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
 
 	/* Set all interrupts to non-critical.
 	 */
-	mtdcr(DCRN_UIC0_CR, 0);
+	mtdcr(DCRN_UIC_CR(UIC0), 0);
+#endif
 
 	ppc4xx_pic = &ppc405_uic;
 	ppc_md.get_irq = ppc405_pic_get_irq;
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Fri Jul  5 16:43:00 2002
@@ -77,10 +77,6 @@
 
 extern unsigned long mm_ptov (unsigned long paddr);
 
-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
-extern void consistent_free(void *vaddr);
-extern void consistent_sync(void *vaddr, size_t size, int direction);
-
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
 EXPORT_SYMBOL(do_syscall_trace);
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/kernel/process.c	Fri Jul  5 16:43:00 2002
@@ -197,7 +197,7 @@
 	return 1;
 }
 
-void switch_to(struct task_struct *prev, struct task_struct *new)
+void __switch_to(struct task_struct *prev, struct task_struct *new)
 {
 	struct thread_struct *new_thread, *old_thread;
 	unsigned long s;
diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
--- a/arch/ppc/kernel/prom.c	Fri Jul  5 16:42:56 2002
+++ b/arch/ppc/kernel/prom.c	Fri Jul  5 16:42:56 2002
@@ -520,6 +520,38 @@
 }
 
 static unsigned long __init
+map_addr(struct device_node *np, unsigned long space, unsigned long addr)
+{
+	int na;
+	unsigned int *ranges;
+	int rlen = 0;
+	unsigned int type;
+
+	type = (space >> 24) & 3;
+	if (type == 0)
+		return addr;
+
+	while ((np = np->parent) != NULL) {
+		if (strcmp(np->type, "pci") != 0)
+			continue;
+		/* PCI bridge: map the address through the ranges property */
+		na = prom_n_addr_cells(np);
+		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
+		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
+			if (((ranges[0] >> 24) & 3) == type
+			    && ranges[2] <= addr
+			    && addr - ranges[2] < ranges[na+4]) {
+				/* ok, this matches, translate it */
+				addr += ranges[na+2] - ranges[2];
+				break;
+			}
+			ranges += na + 5;
+		}
+	}
+	return addr;
+}
+
+static unsigned long __init
 interpret_pci_props(struct device_node *np, unsigned long mem_start,
 		    int naddrc, int nsizec)
 {
@@ -533,9 +565,9 @@
 		i = 0;
 		adr = (struct address_range *) mem_start;
 		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			/* XXX assumes PCI addresses mapped 1-1 to physical */
 			adr[i].space = pci_addrs[i].addr.a_hi;
-			adr[i].address = pci_addrs[i].addr.a_lo;
+			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
+						  pci_addrs[i].addr.a_lo);
 			adr[i].size = pci_addrs[i].size_lo;
 			++i;
 		}
@@ -772,13 +804,14 @@
 	for (np = allnodes; np != 0; np = np->allnext) {
 		for (j = 0; j < np->n_intrs; j++) {
 			i = np->intrs[j].line;
-			if (i >= off && i < max)
+			if (i >= off && i < max) {
 				if (np->intrs[j].sense == 1)
 					senses[i-off] = (IRQ_SENSE_LEVEL
 						| IRQ_POLARITY_NEGATIVE);
 				else
 					senses[i-off] = (IRQ_SENSE_EDGE 
 						| IRQ_POLARITY_POSITIVE);
+			}
 		}
 	}
 }
diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
--- a/arch/ppc/kernel/syscalls.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/kernel/syscalls.c	Fri Jul  5 16:42:59 2002
@@ -117,7 +117,7 @@
 			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
 			    || (ret = copy_from_user(&tmp,
 						(struct ipc_kludge *) ptr,
-						sizeof (tmp)) ? -EFAULT : 0)
+						sizeof (tmp)) ? -EFAULT : 0))
 				break;
 			ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
 					  third);
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/kernel/traps.c	Fri Jul  5 16:42:59 2002
@@ -123,6 +123,7 @@
 	unsigned long msr = regs->msr;
 
 	if (user_mode(regs)) {
+		regs->msr |= MSR_RI;
 		_exception(SIGSEGV, regs);
 		return;
 	}
@@ -134,6 +135,7 @@
 #endif
 	if (debugger_fault_handler) {
 		debugger_fault_handler(regs);
+		regs->msr |= MSR_RI;
 		return;
 	}
 
diff -Nru a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
--- a/arch/ppc/lib/string.S	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/lib/string.S	Fri Jul  5 16:43:00 2002
@@ -461,7 +461,7 @@
 53:
 #if !defined(CONFIG_8xx)
 	dcbt	r3,r4
-	dcbz	r11,r6
+54:	dcbz	r11,r6
 #endif
 /* had to move these to keep extable in order */
 	.section __ex_table,"a"
@@ -470,7 +470,9 @@
 	.long	71b,101f
 	.long	72b,102f
 	.long	73b,103f
-	.long	53b,105f
+#if !defined(CONFIG_8xx)
+	.long	54b,105f
+#endif
 	.text
 /* the main body of the cacheline loop */
 	COPY_16_BYTES_WITHEX(0)
@@ -613,11 +615,11 @@
 	add	r4,r0,r4
 	subf	r6,r0,r6
 	srwi	r0,r4,2
+	andi.	r4,r4,3
 	mtctr	r0
-	bdz	6f
+	bdz	7f
 1:	stwu	r5,4(r6)
 	bdnz	1b
-6:	andi.	r4,r4,3
 	/* clear byte sized chunks */
 7:	cmpwi	0,r4,0
 	beqlr
@@ -626,14 +628,20 @@
 8:	stbu	r5,1(r6)
 	bdnz	8b
 	blr
-99:	li	r3,-EFAULT
+90:	mr	r3,r4
+	blr
+91:	mfctr	r3
+	slwi	r3,r3,2
+	add	r3,r3,r4
+	blr
+92:	mfctr	r3
 	blr
 
 	.section __ex_table,"a"
 	.align	2
-	.long	11b,99b
-	.long	1b,99b
-	.long	8b,99b
+	.long	11b,90b
+	.long	1b,91b
+	.long	8b,92b
 	.text
 
 _GLOBAL(__strncpy_from_user)
diff -Nru a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c
--- a/arch/ppc/mm/4xx_mmu.c	Fri Jul  5 16:42:48 2002
+++ b/arch/ppc/mm/4xx_mmu.c	Fri Jul  5 16:42:48 2002
@@ -54,11 +54,6 @@
 #include <asm/machdep.h>
 #include <asm/setup.h>
 
-/* Used by the 4xx TLB replacement exception handler.
- * Just needed it declared someplace (and initialized to zero).
- */
-unsigned int tlb_4xx_index;
-
 /*
  * MMU_init_hw does the chip-specific initialization of the MMU hardware.
  */
diff -Nru a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c
--- a/arch/ppc/mm/cachemap.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/mm/cachemap.c	Fri Jul  5 16:43:00 2002
@@ -50,6 +50,8 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 
+int map_page(unsigned long va, unsigned long pa, int flags);
+
 /* This function will allocate the requested contiguous pages and
  * map them into the kernel's vmalloc() space.  This is done so we
  * get unique mapping for these pages, outside of the kernel's 1:1
@@ -96,7 +98,7 @@
 
 	/* This gives us the real physical address of the first page.
 	*/
-	*dma_handle = pa = virt_to_bus(page);
+	*dma_handle = pa = virt_to_bus((void *)page);
 
 	flags = _PAGE_KERNEL | _PAGE_NO_CACHE;
 
@@ -151,10 +153,10 @@
  */
 
 void consistent_sync_page(struct page *page, unsigned long offset,
-size_t size, int direction)
+	size_t size, int direction)
 {
 	unsigned long start;
 
 	start = page_address(page) + offset;
-	consistent_sync(start, size, direction);
+	consistent_sync((void *)start, size, direction);
 }
diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/mm/init.c	Fri Jul  5 16:42:59 2002
@@ -559,18 +559,19 @@
 
 	if (page->mapping && !PageReserved(page)
 	    && !test_bit(PG_arch_1, &page->flags)) {
-		phys = ((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART;
+		phys = page_to_pfn(page) << PAGE_SHIFT;
 		__flush_dcache_icache_phys(phys);
 		set_bit(PG_arch_1, &page->flags);
 	}
 }
 
-void clear_user_page(void *page, unsigned long vaddr)
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
 	clear_page(page);
 }
 
-void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+		    struct page *pg)
 {
 	copy_page(vto, vfrom);
 	__flush_dcache_icache(vto);
diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/platforms/chrp_setup.c	Fri Jul  5 16:42:59 2002
@@ -389,7 +389,6 @@
 	int i;
 	unsigned long chrp_int_ack;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
-	int nmi_irq = -1;
 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)	
 	struct device_node *kbd;
 #endif
@@ -412,7 +411,7 @@
 	OpenPIC_InitSenses = init_senses;
 	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
 
-	openpic_init(1, NUM_8259_INTERRUPTS, nmi_irq);
+	openpic_init(NUM_8259_INTERRUPTS);
 
 	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
@@ -465,35 +464,6 @@
 #endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
 }
 
-/*
- * One of the main thing these mappings are needed for is so that
- * xmon can get to the serial port early on.  We probably should
- * handle the machines with the mpc106 as well as the python (F50)
- * and the GG2 (longtrail).  Actually we should look in the device
- * tree and do the right thing.
- */
-static void __init
-chrp_map_io(void)
-{
-	char *name;
-
-	/*
-	 * The code below tends to get removed, please don't take it out.
-	 * The F50 needs this mapping and it you take it out I'll track you
-	 * down and slap your hands.  If it causes problems please email me.
-	 *  -- Cort <cort@fsmlabs.com>
-	 */
-	name = get_property(find_path_device("/"), "name", NULL);
-	if (name && strncmp(name, "IBM-70", 6) == 0
-	    && strstr(name, "-F50")) {
-		io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-		io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO);
-		return;
-	} else {
-		io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO);
-	}
-}
-
 void __init
 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7)
@@ -531,7 +501,6 @@
 	ppc_md.calibrate_decr = chrp_calibrate_decr;
 
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-	ppc_md.setup_io_mappings = chrp_map_io;
 
 #ifdef CONFIG_VT
 	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
diff -Nru a/arch/ppc/platforms/ep405.c b/arch/ppc/platforms/ep405.c
--- a/arch/ppc/platforms/ep405.c	Fri Jul  5 16:42:56 2002
+++ b/arch/ppc/platforms/ep405.c	Fri Jul  5 16:42:56 2002
@@ -65,12 +65,10 @@
 {
 	bd_t *bip = (bd_t *) __res;
 
-#ifdef CONFIG_PPC_RTC
 	if (bip->bi_nvramsize == 512*1024) {
 		/* FIXME: we should properly handle NVRTCs of different sizes */
 		TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
 	}
-#endif
 }
 
 void __init
@@ -178,9 +176,9 @@
 void __init
 board_init(void)
 {
+#ifdef CONFIG_PPC_RTC
 	bd_t *bip = (bd_t *) __res;
 
-#ifdef CONFIG_PPC_RTC
 	/* FIXME: we should be able to access the NVRAM even if PPC_RTC is not configured */
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
diff -Nru a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec_setup.c
--- a/arch/ppc/platforms/lopec_setup.c	Fri Jul  5 16:42:50 2002
+++ b/arch/ppc/platforms/lopec_setup.c	Fri Jul  5 16:42:50 2002
@@ -207,7 +207,7 @@
 	/* Skip reserved space and map Message Unit Interrupt (I2O) */
 	openpic_set_sources(19, 1, OpenPIC_Addr + 0x110C0);
 
-	openpic_init(1, NUM_8259_INTERRUPTS, -1);
+	openpic_init(NUM_8259_INTERRUPTS);
 
 	/* Map i8259 interrupts */
 	for(i = 0; i < NUM_8259_INTERRUPTS; i++)
diff -Nru a/arch/ppc/platforms/mbx.h b/arch/ppc/platforms/mbx.h
--- a/arch/ppc/platforms/mbx.h	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/platforms/mbx.h	Fri Jul  5 16:43:00 2002
@@ -88,11 +88,33 @@
 #define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
 #define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
 #define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
-#endif /* !__ASSEMBLY__ */
+
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
+ * to the MBX860 board.  Any two of the four available clocks could be
+ * used, and the MPC860 cookbook manual has an example using different
+ * clock pins.
+ */
+#define PA_ENET_RXD	((ushort)0x0001)
+#define PA_ENET_TXD	((ushort)0x0002)
+#define PA_ENET_TCLK	((ushort)0x0200)
+#define PA_ENET_RCLK	((ushort)0x0800)
+#define PC_ENET_TENA	((ushort)0x0001)
+#define PC_ENET_CLSN	((ushort)0x0010)
+#define PC_ENET_RENA	((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x000000ff)
+#define SICR_ENET_CLKRT	((uint)0x0000003d)
 
 /* The MBX uses the 8259.
 */
 #define NR_8259_INTS	16
 
-#endif
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_MBX_DEFS */
 #endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c
--- a/arch/ppc/platforms/pmac_nvram.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/platforms/pmac_nvram.c	Fri Jul  5 16:42:59 2002
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/string.h>
 #include <linux/nvram.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff -Nru a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
--- a/arch/ppc/platforms/pmac_pic.c	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/platforms/pmac_pic.c	Fri Jul  5 16:42:59 2002
@@ -375,26 +375,28 @@
 		printk("PowerMac using OpenPIC irq controller\n");
 		if (irqctrler->n_addrs > 0)
 		{
-			int nmi_irq = -1;
 			unsigned char senses[NR_IRQS];
-#ifdef CONFIG_XMON
-			struct device_node* pswitch;
 
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs)
-				nmi_irq = pswitch->intrs[0].line;
-#endif /* CONFIG_XMON */
 			prom_get_irq_senses(senses, 0, NR_IRQS);
 			OpenPIC_InitSenses = senses;
 			OpenPIC_NumInitSenses = NR_IRQS;
 			ppc_md.get_irq = openpic_get_irq;
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, nmi_irq);
+			openpic_init(0);
 #ifdef CONFIG_XMON
-			if (nmi_irq >= 0)
-				request_irq(nmi_irq, xmon_irq, 0,
-					    "NMI - XMON", 0);
+			{
+				struct device_node* pswitch;
+				int nmi_irq;
+
+				pswitch = find_devices("programmer-switch");
+				if (pswitch && pswitch->n_intrs) {
+					nmi_irq = pswitch->intrs[0].line;
+					openpic_init_nmi_irq(nmi_irq);
+					request_irq(nmi_irq, xmon_irq, 0,
+							"NMI - XMON", 0);
+				}
+			}
 #endif	/* CONFIG_XMON */
 			return;
 		}
diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/platforms/prep_pci.c	Fri Jul  5 16:43:00 2002
@@ -665,9 +665,9 @@
 #define	MPIC_HAWK_ID		0x48030000
 #define	MOT_PROC2_BIT		0x800
 
-static u_char mvme2600_openpic_initsenses[] __initdata = {
-    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_SIO */
-    (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_FALCN_ECC_ERR */
+static u_char prep_openpic_initsenses[] __initdata = {
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+    (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCON_ECC_ERR */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
@@ -737,8 +737,8 @@
 	/* Map the Raven MPIC registers to virtual memory. */
 	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
 
-	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
 
 	ppc_md.get_irq = openpic_get_irq;
 	
@@ -821,6 +821,9 @@
 			addr += PREP_ISA_MEM_BASE;
 			OpenPIC_Addr = ioremap(addr, 0x40000);
 			ppc_md.get_irq = openpic_get_irq;
+
+			OpenPIC_InitSenses = prep_openpic_initsenses;
+			OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
 		}
 	}
 
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Fri Jul  5 16:43:00 2002
+++ b/arch/ppc/platforms/prep_setup.c	Fri Jul  5 16:43:00 2002
@@ -692,7 +692,7 @@
 	int i;
 
 	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, -1);
+		openpic_init(NUM_8259_INTERRUPTS);
 	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
 		irq_desc[i].handler = &i8259_pic;
 	i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR);
diff -Nru a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
--- a/arch/ppc/platforms/rpxclassic.h	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/platforms/rpxclassic.h	Fri Jul  5 16:42:59 2002
@@ -94,11 +94,31 @@
 */
 #define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
 
-#endif /* !__ASSEMBLY__ */
+
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0001)
+#define PA_ENET_TXD	((ushort)0x0002)
+#define PA_ENET_TCLK	((ushort)0x0200)
+#define PA_ENET_RCLK	((ushort)0x0800)
+#define PB_ENET_TENA	((uint)0x00001000)
+#define PC_ENET_CLSN	((ushort)0x0010)
+#define PC_ENET_RENA	((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x000000ff)
+#define SICR_ENET_CLKRT	((uint)0x0000003d)
 
 /* We don't use the 8259.
 */
+
 #define NR_8259_INTS	0
 
-#endif
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_RPX_DEFS */
 #endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
--- a/arch/ppc/platforms/rpxlite.h	Fri Jul  5 16:42:56 2002
+++ b/arch/ppc/platforms/rpxlite.h	Fri Jul  5 16:42:56 2002
@@ -65,7 +65,6 @@
 #if defined(CONFIG_HTDMSOUND)
 #include <platforms/rpxhiox.h>
 #endif
-#endif /* !__ASSEMBLY__ */
 
 /* define IO_BASE for pcmcia */
 #define _IO_BASE 0x80000000
@@ -76,9 +75,27 @@
 # define request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
 #endif
 
+/* CPM Ethernet through SCCx.
+ *
+ * This ENET stuff is for the MPC850 with ethernet on SCC2.  Some of
+ * this may be unique to the RPX-Lite configuration.
+ * Note TENA is on Port B.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)
+#define PA_ENET_TXD	((ushort)0x0008)
+#define PA_ENET_TCLK	((ushort)0x0200)
+#define PA_ENET_RCLK	((ushort)0x0800)
+#define PB_ENET_TENA	((uint)0x00002000)
+#define PC_ENET_CLSN	((ushort)0x0040)
+#define PC_ENET_RENA	((ushort)0x0080)
+
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00003d00)
+
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
 
-#endif
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_RPX_DEFS */
 #endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h
--- a/arch/ppc/platforms/spd8xx.h	Fri Jul  5 16:42:56 2002
+++ b/arch/ppc/platforms/spd8xx.h	Fri Jul  5 16:42:56 2002
@@ -15,6 +15,7 @@
  
 #include <asm/ppcboot.h>
 
+#ifndef __ASSEMBLY__
 #define SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
 #define SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
 
@@ -61,9 +62,34 @@
 #define IDE1_CONTROL_REG_OFFSET		0x0106
 #define IDE1_IRQ_REG_OFFSET		0x000A	/* not used */
 
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC2 use.
+ */
+#define PA_ENET_MDC	((ushort)0x0001)	/* PA 15 !!! */
+#define PA_ENET_MDIO	((ushort)0x0002)	/* PA 14 !!! */
+#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
+#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
+#define PA_ENET_RCLK	((ushort)0x0200)	/* PA  6 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
+
+#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
+#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
+#define PC_ENET_RESET	((ushort)0x0100)	/* PC  7 !!! */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002E00)
+
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
 
+#endif /* !__ASSEMBLY__ */
 #endif /* __ASM_SPD8XX_H__ */
 #endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h
--- a/arch/ppc/platforms/tqm8xx.h	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc/platforms/tqm8xx.h	Fri Jul  5 16:42:59 2002
@@ -7,6 +7,7 @@
  * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
  */
 
+#ifdef __KERNEL__
 #ifndef __MACH_TQM8xx_H
 #define __MACH_TQM8xx_H
 
@@ -14,6 +15,7 @@
  
 #include <asm/ppcboot.h>
 
+#ifndef __ASSEMBLY__
 #define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
 #define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
 
@@ -47,8 +49,106 @@
 #define	IDE0_INTERRUPT			13
 
 
+/*-----------------------------------------------------------------------
+ * CPM Ethernet through SCCx.
+ *-----------------------------------------------------------------------
+ *
+ */
+
+/***  TQM823L, TQM850L  ***********************************************/
+
+#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L)
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
+#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
+
+#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
+#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002600)
+#endif	/* CONFIG_TQM823L, CONFIG_TQM850L */
+
+/***  TQM860L  ********************************************************/
+
+#ifdef CONFIG_TQM860L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0001)	/* PA 15 */
+#define PA_ENET_TXD	((ushort)0x0002)	/* PA 14 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PC_ENET_TENA	((ushort)0x0001)	/* PC 15 */
+#define PC_ENET_CLSN	((ushort)0x0010)	/* PC 11 */
+#define PC_ENET_RENA	((ushort)0x0020)	/* PC 10 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x000000ff)
+#define SICR_ENET_CLKRT	((uint)0x00000026)
+#endif	/* CONFIG_TQM860L */
+
+/***  FPS850L  *********************************************************/
+
+#ifdef CONFIG_FPS850L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
+#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PC_ENET_TENA	((ushort)0x0002)	/* PC 14 */
+#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
+#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002600)
+#endif	/* CONFIG_FPS850L */
+
+/***  SM850  *********************************************************/
+
+/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
+
+#ifdef CONFIG_SM850
+#define PB_ENET_RXD	((uint)0x00000004)	/* PB 29 */
+#define PB_ENET_TXD	((uint)0x00000002)	/* PB 30 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PC_ENET_LBK	((ushort)0x0008)	/* PC 12 */
+#define PC_ENET_TENA	((ushort)0x0004)	/* PC 13 */
+
+#define PC_ENET_RENA	((ushort)0x0800)	/* PC  4 */
+#define PC_ENET_CLSN	((ushort)0x0400)	/* PC  5 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC3.  Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x00FF0000)
+#define SICR_ENET_CLKRT	((uint)0x00260000)
+#endif	/* CONFIG_SM850 */
+
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
 
+#endif /* !__ASSEMBLY__ */
 #endif	/* __MACH_TQM8xx_H */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc64/Makefile	Fri Jul  5 16:42:59 2002
@@ -15,7 +15,7 @@
 
 KERNELLOAD	=0xc000000000000000
 
-LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
+LDFLAGS_vmlinux	= -T arch/ppc64/vmlinux.lds -Bstatic \
 		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
 CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
 		-Wno-uninitialized -mminimal-toc -mtraceback=full \
diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
--- a/arch/ppc64/boot/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/ppc64/boot/Makefile	Fri Jul  5 16:42:59 2002
@@ -36,6 +36,7 @@
 
 CFLAGS	= $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
 LD_ARGS = -Ttext 0x00400000 -e _start
+OBJCOPYFLAGS := -S -O binary
 
 OBJS = crt0.o start.o main.o zlib.o image.o imagesize.o
 #LIBS = $(TOPDIR)/lib/lib.a
@@ -109,9 +110,8 @@
 	$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) initrd.o $(LIBS)
 	./addnote $@
 
-
 vmlinux.gz: $(TOPDIR)/vmlinux
-	$(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux
+	$(OBJCOPY) $(OBJCOPYFLAGS) $(TOPDIR)/vmlinux vmlinux
 	ls -l vmlinux | awk '{printf "/* generated -- do not edit! */\nint uncompressed_size = %d;\n", $$5}' > imagesize.c
 	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "long vmlinux_end = 0x%s;\n", substr($$1,8)}' >> imagesize.c
 	gzip -vf9 vmlinux
diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/s390/Makefile	Fri Jul  5 16:42:59 2002
@@ -13,15 +13,14 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-LD=$(CROSS_COMPILE)ld -m elf_s390
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e start
+LDFLAGS		:= -m elf_s390
+OBJCOPYFLAGS	:= -O binary
 ifeq ($(CONFIG_SHARED_KERNEL),y)
   LINKSCRIPT := arch/s390/vmlinux-shared.lds
 else
   LINKSCRIPT := arch/s390/vmlinux.lds
 endif
-LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
+LDFLAGS_vmlinux := -T $(LINKSCRIPT) -e start
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
diff -Nru a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
--- a/arch/s390/boot/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/s390/boot/Makefile	Fri Jul  5 16:43:00 2002
@@ -2,21 +2,19 @@
 # arch/s390/boot/Makefile
 #
 
-OBJCOPY = $(CROSS_COMPILE)objcopy
-
 EXTRA_AFLAGS := -traditional
 
 include $(TOPDIR)/Rules.make
 
 %.lnk: %.o
-	$(LD) -Ttext 0x0 -o $@ $<
+	$(LD) $(LDFLAGS) -Ttext 0x0 -o $@ $<
 
 %.boot: %.lnk
-	$(OBJCOPY) -O binary $< $@
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 image: $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
-	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+	$(OBJCOPY) $(OBJCOPYFLAGS) $(TOPDIR)/vmlinux image
 	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
 
 listing: ../../../vmlinux
diff -Nru a/arch/s390x/Makefile b/arch/s390x/Makefile
--- a/arch/s390x/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/s390x/Makefile	Fri Jul  5 16:43:00 2002
@@ -13,16 +13,15 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-LD=$(CROSS_COMPILE)ld -m elf64_s390
+LDFLAGS		:= -m elf64_s390
 CPP=$(CC) -E
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e start
+OBJCOPYFLAGS	:= -O binary
 ifeq ($(CONFIG_SHARED_KERNEL),y)
   LINKSCRIPT := arch/s390x/vmlinux-shared.lds
 else
   LINKSCRIPT := arch/s390x/vmlinux.lds
 endif
-LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
+LDFLAGS_vmlinux := -T $(LINKSCRIPT) -e start
 MODFLAGS += -fpic
 
 CFLAGS_PIPE := -pipe
diff -Nru a/arch/s390x/boot/Makefile b/arch/s390x/boot/Makefile
--- a/arch/s390x/boot/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/s390x/boot/Makefile	Fri Jul  5 16:43:00 2002
@@ -2,8 +2,6 @@
 # Makefile for the linux s390-specific parts of the memory manager.
 #
 
-OBJCOPY = $(CROSS_COMPILE)objcopy
-
 O_TARGET := 
 
 EXTRA_AFLAGS := -traditional
@@ -14,11 +12,11 @@
 	$(LD) -Ttext 0x0 -o $@ $<
 
 %.boot: %.lnk
-	$(OBJCOPY) -O binary $< $@
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 image: $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
-	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
 
 listing: ../../../vmlinux
diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile
--- a/arch/sh/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/sh/Makefile	Fri Jul  5 16:43:00 2002
@@ -15,17 +15,16 @@
 ifdef CONFIG_CPU_LITTLE_ENDIAN
 CFLAGS		+= -ml
 AFLAGS		+= -ml
-# LINKFLAGS	+= -EL
+# LDFLAGS_vmlinux	+= -EL
 LDFLAGS		:= -EL
 else
 CFLAGS		+= -mb
 AFLAGS		+= -mb
-# LINKFLAGS	+= -EB
+# LDFLAGS_vmlinux	+= -EB
 LDFLAGS		:= -EB
 endif
 
-LD	=$(CROSS_COMPILE)ld $(LDFLAGS)
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr -S
+OBJCOPYFLAGS	:= -O binary -R .note -R .comment -R .stab -R .stabstr -S
 
 MODFLAGS	+=
 
@@ -47,10 +46,10 @@
 # none has been choosen above.
 #
 LINKSCRIPT    = arch/sh/vmlinux.lds
-LINKFLAGS     += -T $(word 1,$(LINKSCRIPT)) -e _stext
+LDFLAGS_vmlinux     += -T $(word 1,$(LINKSCRIPT)) -e _stext
 
 ifdef LOADADDR
-LINKFLAGS     += -Ttext $(word 1,$(LOADADDR))
+LDFLAGS_vmlinux     += -Ttext $(word 1,$(LOADADDR))
 endif
 
 #
diff -Nru a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
--- a/arch/sh/boot/Makefile	Fri Jul  5 16:42:56 2002
+++ b/arch/sh/boot/Makefile	Fri Jul  5 16:42:56 2002
@@ -11,10 +11,10 @@
 SYSTEM  =$(TOPDIR)/vmlinux
 
 Image:	$(SYSTEM)
-	$(OBJCOPY) $(SYSTEM) Image
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 zImage: compressed/vmlinux
-	$(OBJCOPY) compressed/vmlinux zImage
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	$(MAKE) -C compressed vmlinux
diff -Nru a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
--- a/arch/sh/boot/compressed/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/sh/boot/compressed/Makefile	Fri Jul  5 16:43:00 2002
@@ -25,7 +25,7 @@
 all: vmlinux
 
 vmlinux: piggy.o $(OBJECTS)
-	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+	$(LD) $(LDFLAGS) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
 
 head.o: head.S
 	$(CC) $(AFLAGS) -traditional -c head.S
@@ -33,10 +33,10 @@
 piggy.o:	$(SYSTEM)
 	tmppiggy=_tmp_$$$$piggy; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
-	$(OBJCOPY) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \
+	$(OBJCOPY) $(OBJCOPYFLAGS) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \
 	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-	$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \
+	$(LD) $(LDFLAGS) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
 
 clean:
diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile
--- a/arch/sparc/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/sparc/Makefile	Fri Jul  5 16:42:59 2002
@@ -20,7 +20,7 @@
 
 ifeq ($(NEW_GAS),y)
 AS              := $(AS) -32
-LD              := $(LD) -m elf32_sparc
+LDFLAGS		:= -m elf32_sparc
 endif
 
 #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
@@ -30,8 +30,8 @@
 CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
 endif
 
-#LINKFLAGS = -N -Ttext 0xf0004000
-LINKFLAGS = -T arch/sparc/vmlinux.lds
+#LDFLAGS_vmlinux = -N -Ttext 0xf0004000
+LDFLAGS_vmlinux = -T arch/sparc/vmlinux.lds
 
 HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
 
diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
--- a/arch/sparc/boot/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/sparc/boot/Makefile	Fri Jul  5 16:43:00 2002
@@ -31,7 +31,7 @@
 # properly as it will cause head.o to be built with the implicit
 # rules not the ones in kernel/Makefile.  Someone please fix. --DaveM
 vmlinux.o: FORCE
-	$(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
+	$(LD) $(LDFLAGS) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
 		--start-group \
 		$(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \
 		$(LIBS) \
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Fri Jul  5 16:43:00 2002
+++ b/arch/sparc/kernel/signal.c	Fri Jul  5 16:43:00 2002
@@ -1090,7 +1090,7 @@
 
 #ifdef DEBUG_SIGNALS_MAPS
 
-#define MAPS_LINE_FORMAT	  "%08lx-%08lx %s %08lx %s %lu "
+#define MAPS_LINE_FORMAT	  "%08lx-%08lx %s %08lx %02x:%02x %lu "
 
 static inline void read_maps (void)
 {
@@ -1107,7 +1107,7 @@
 		char *line;
 		char str[5], *cp = str;
 		int flags;
-		kdev_t dev;
+		dev_t dev;
 		unsigned long ino;
 
 		/*
@@ -1132,7 +1132,7 @@
 				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      kdevname(dev), ino);
+			      MAJOR(dev), MINOR(dev), ino);
 		if (map->vm_file != NULL)
 			printk("%s\n", line);
 		else
diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile
--- a/arch/sparc64/Makefile	Fri Jul  5 16:43:00 2002
+++ b/arch/sparc64/Makefile	Fri Jul  5 16:43:00 2002
@@ -28,7 +28,7 @@
 RANLIB		= sparc64-linux-ranlib
 else
 AS		:= $(AS) -64
-LD		:= $(LD) -m elf64_sparc
+LDFLAGS		:= -m elf64_sparc
 endif
 ELFTOAOUT	= elftoaout
 ifneq ($(UNDECLARED_REGS),y)
@@ -53,7 +53,7 @@
   CFLAGS := $(CFLAGS) -pg
 endif
 
-LINKFLAGS = -T arch/sparc64/vmlinux.lds
+LDFLAGS_vmlinux = -T arch/sparc64/vmlinux.lds
 
 HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
 
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Fri Jul  5 16:43:00 2002
+++ b/arch/sparc64/kernel/signal.c	Fri Jul  5 16:43:00 2002
@@ -633,7 +633,7 @@
 
 #ifdef DEBUG_SIGNALS_MAPS
 
-#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %s %lu "
+#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %02x:%02x %lu "
 
 static inline void read_maps (void)
 {
@@ -650,7 +650,7 @@
 		char *line;
 		char str[5], *cp = str;
 		int flags;
-		kdev_t dev;
+		dev_t dev;
 		unsigned long ino;
 
 		/*
@@ -675,7 +675,7 @@
 				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      kdevname(dev), ino);
+			      MAJOR(dev), MINOR(dev), ino);
 		if (map->vm_file != NULL)
 			printk("%s\n", line);
 		else
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Fri Jul  5 16:42:48 2002
+++ b/arch/sparc64/kernel/signal32.c	Fri Jul  5 16:42:48 2002
@@ -1319,7 +1319,7 @@
 
 #ifdef DEBUG_SIGNALS_MAPS
 
-#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %s %lu "
+#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %02x:%02x %lu "
 
 static inline void read_maps (void)
 {
@@ -1336,7 +1336,7 @@
 		char *line;
 		char str[5], *cp = str;
 		int flags;
-		kdev_t dev;
+		dev_t dev;
 		unsigned long ino;
 
 		/*
@@ -1361,7 +1361,7 @@
 				      buffer, PAGE_SIZE);
 		}
 		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      kdevname(dev), ino);
+			      MAJOR(dev), MINOR(dev), ino);
 		if (map->vm_file != NULL)
 			printk("%s\n", line);
 		else
diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile
--- a/arch/x86_64/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/x86_64/Makefile	Fri Jul  5 16:42:59 2002
@@ -34,9 +34,8 @@
 
 
 LD=$(CROSS_COMPILE)ld -m elf_x86_64
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/x86_64/vmlinux.lds $(LDFLAGS)
+OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux := -T arch/x86_64/vmlinux.lds -e stext
 
 CFLAGS += -mno-red-zone
 CFLAGS += -mcmodel=kernel
diff -Nru a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
--- a/arch/x86_64/boot/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/x86_64/boot/Makefile	Fri Jul  5 16:42:59 2002
@@ -28,11 +28,11 @@
 		$(TOPDIR)/include/asm/boot.h
 
 zImage: bootsect setup compressed/vmlinux tools/build
-	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
+	$(OBJCOPY) $(OBJCOPYFLAGS) compressed/vmlinux compressed/vmlinux.out
 	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
 
 bzImage: bbootsect bsetup compressed/bvmlinux tools/build
-	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
+	$(OBJCOPY) $(OBJCOPYFLAGS) compressed/bvmlinux compressed/bvmlinux.out
 	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
 
 bzImage-padded: bzImage
diff -Nru a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
--- a/arch/x86_64/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
+++ b/arch/x86_64/boot/compressed/Makefile	Fri Jul  5 16:42:59 2002
@@ -33,7 +33,7 @@
 piggy.o:	$(SYSTEM)
 	tmppiggy=_tmp_$$$$piggy; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
-	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $$tmppiggy; \
 	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
 	$(IA32_LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
--- a/drivers/acorn/char/Makefile	Fri Jul  5 16:42:56 2002
+++ b/drivers/acorn/char/Makefile	Fri Jul  5 16:42:56 2002
@@ -20,5 +20,16 @@
 
 include $(TOPDIR)/Rules.make
 
-$(obj)/%.c: $(src)/%.map
+$(obj)/defkeymap-acorn.o: $(obj)/defkeymap-acorn.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap-acorn.c: $(obj)/%.c: $(src)/%.map
 	loadkeys --mktable $< > $@
+
+endif
diff -Nru a/drivers/acorn/char/defkeymap-acorn.c b/drivers/acorn/char/defkeymap-acorn.c
--- a/drivers/acorn/char/defkeymap-acorn.c	Fri Jul  5 16:43:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-	0xf01b,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
-	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf209,	0xf205,
-	0xf060,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,	0xf037,
-	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf0a3,	0xf07f,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb71,
-	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
-	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb61,	0xfb73,	0xfb64,	0xfb66,
-	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
-	0xfb63,	0xfb76,	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-	0xf01b,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,	0xf10f,	0xf110,
-	0xf111,	0xf112,	0xf113,	0xf10a,	0xf10b,	0xf200,	0xf203,	0xf205,
-	0xf07e,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,
-	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf0a4,	0xf07f,	0xf115,
-	0xf114,	0xf20b,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb51,
-	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,	0xfb4f,
-	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf116,	0xf117,	0xf20a,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb41,	0xfb53,	0xfb44,	0xfb46,
-	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb5a,	0xfb58,
-	0xfb43,	0xfb56,	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-	0xf200,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,	0xf511,	0xf512,
-	0xf513,	0xf514,	0xf515,	0xf516,	0xf517,	0xf200,	0xf202,	0xf205,
-	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,
-	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xfb71,
-	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
-	0xfb70,	0xf200,	0xf07e,	0xf200,	0xf116,	0xf117,	0xf119,	0xf911,
-	0xf912,	0xf913,	0xf30b,	0xf702,	0xf914,	0xfb73,	0xf917,	0xf919,
-	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,
-	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
-	0xf916,	0xfb76,	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf90b,	0xf90c,	0xf90d,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf90a,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
-	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf204,	0xf205,
-	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,
-	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf008,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
-	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
-	0xf010,	0xf01b,	0xf01d,	0xf01c,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
-	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf000,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf209,	0xf205,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
-	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
-	0xf010,	0xf200,	0xf200,	0xf200,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
-	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-	0xf81b,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
-	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
-	0xf860,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,
-	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf8a3,	0xf87f,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf809,	0xf871,
-	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,	0xf86f,
-	0xf870,	0xf85b,	0xf85d,	0xf85c,	0xf116,	0xf117,	0xf119,	0xf907,
-	0xf908,	0xf909,	0xf30b,	0xf702,	0xf861,	0xf873,	0xf864,	0xf866,
-	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf80d,
-	0xf904,	0xf905,	0xf906,	0xf30a,	0xf700,	0xf200,	0xf87a,	0xf878,
-	0xf863,	0xf876,	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,
-	0xf700,	0xf603,	0xf901,	0xf902,	0xf903,	0xf207,	0xf703,	0xf820,
-	0xf701,	0xf702,	0xf210,	0xf600,	0xf211,	0xf900,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-	0xf200,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
-	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf811,
-	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,
-	0xf810,	0xf200,	0xf200,	0xf200,	0xf20c,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf801,	0xf813,	0xf804,	0xf806,
-	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf81a,	0xf818,
-	0xf803,	0xf816,	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf20c,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-	plain_map, shift_map, altgr_map, 0,
-	ctrl_map, shift_ctrl_map, 0, 0,
-	alt_map, 0, 0, 0,
-	ctrl_alt_map,	0
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-	'\033', '[', '[', 'A', 0, 
-	'\033', '[', '[', 'B', 0, 
-	'\033', '[', '[', 'C', 0, 
-	'\033', '[', '[', 'D', 0, 
-	'\033', '[', '[', 'E', 0, 
-	'\033', '[', '1', '7', '~', 0, 
-	'\033', '[', '1', '8', '~', 0, 
-	'\033', '[', '1', '9', '~', 0, 
-	'\033', '[', '2', '0', '~', 0, 
-	'\033', '[', '2', '1', '~', 0, 
-	'\033', '[', '2', '3', '~', 0, 
-	'\033', '[', '2', '4', '~', 0, 
-	'\033', '[', '2', '5', '~', 0, 
-	'\033', '[', '2', '6', '~', 0, 
-	'\033', '[', '2', '8', '~', 0, 
-	'\033', '[', '2', '9', '~', 0, 
-	'\033', '[', '3', '1', '~', 0, 
-	'\033', '[', '3', '2', '~', 0, 
-	'\033', '[', '3', '3', '~', 0, 
-	'\033', '[', '3', '4', '~', 0, 
-	'\033', '[', '1', '~', 0, 
-	'\033', '[', '2', '~', 0, 
-	'\033', '[', '3', '~', 0, 
-	'\033', '[', '4', '~', 0, 
-	'\033', '[', '5', '~', 0, 
-	'\033', '[', '6', '~', 0, 
-	'\033', '[', 'M', 0, 
-	'\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-	func_buf + 0,
-	func_buf + 5,
-	func_buf + 10,
-	func_buf + 15,
-	func_buf + 20,
-	func_buf + 25,
-	func_buf + 31,
-	func_buf + 37,
-	func_buf + 43,
-	func_buf + 49,
-	func_buf + 55,
-	func_buf + 61,
-	func_buf + 67,
-	func_buf + 73,
-	func_buf + 79,
-	func_buf + 85,
-	func_buf + 91,
-	func_buf + 97,
-	func_buf + 103,
-	func_buf + 109,
-	func_buf + 115,
-	func_buf + 120,
-	func_buf + 125,
-	func_buf + 130,
-	func_buf + 135,
-	func_buf + 140,
-	func_buf + 145,
-	0,
-	0,
-	func_buf + 149,
-	0,
-};
-
-struct kbdiacr accent_table[MAX_DIACR] = {
-	{'`', 'A', '\300'},	{'`', 'a', '\340'},
-	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
-	{'^', 'A', '\302'},	{'^', 'a', '\342'},
-	{'~', 'A', '\303'},	{'~', 'a', '\343'},
-	{'"', 'A', '\304'},	{'"', 'a', '\344'},
-	{'O', 'A', '\305'},	{'o', 'a', '\345'},
-	{'0', 'A', '\305'},	{'0', 'a', '\345'},
-	{'A', 'A', '\305'},	{'a', 'a', '\345'},
-	{'A', 'E', '\306'},	{'a', 'e', '\346'},
-	{',', 'C', '\307'},	{',', 'c', '\347'},
-	{'`', 'E', '\310'},	{'`', 'e', '\350'},
-	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
-	{'^', 'E', '\312'},	{'^', 'e', '\352'},
-	{'"', 'E', '\313'},	{'"', 'e', '\353'},
-	{'`', 'I', '\314'},	{'`', 'i', '\354'},
-	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
-	{'^', 'I', '\316'},	{'^', 'i', '\356'},
-	{'"', 'I', '\317'},	{'"', 'i', '\357'},
-	{'-', 'D', '\320'},	{'-', 'd', '\360'},
-	{'~', 'N', '\321'},	{'~', 'n', '\361'},
-	{'`', 'O', '\322'},	{'`', 'o', '\362'},
-	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
-	{'^', 'O', '\324'},	{'^', 'o', '\364'},
-	{'~', 'O', '\325'},	{'~', 'o', '\365'},
-	{'"', 'O', '\326'},	{'"', 'o', '\366'},
-	{'/', 'O', '\330'},	{'/', 'o', '\370'},
-	{'`', 'U', '\331'},	{'`', 'u', '\371'},
-	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
-	{'^', 'U', '\333'},	{'^', 'u', '\373'},
-	{'"', 'U', '\334'},	{'"', 'u', '\374'},
-	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
-	{'T', 'H', '\336'},	{'t', 'h', '\376'},
-	{'s', 's', '\337'},	{'"', 'y', '\377'},
-	{'s', 'z', '\337'},	{'i', 'j', '\377'},
-};
-
-unsigned int accent_table_size = 68;
diff -Nru a/drivers/acorn/char/defkeymap-acorn.c_shipped b/drivers/acorn/char/defkeymap-acorn.c_shipped
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acorn/char/defkeymap-acorn.c_shipped	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf01b,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf209,	0xf205,
+	0xf060,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,	0xf037,
+	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf0a3,	0xf07f,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb71,
+	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
+	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf116,	0xf117,	0xf119,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb61,	0xfb73,	0xfb64,	0xfb66,
+	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,
+	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,
+	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+	0xf01b,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,	0xf10f,	0xf110,
+	0xf111,	0xf112,	0xf113,	0xf10a,	0xf10b,	0xf200,	0xf203,	0xf205,
+	0xf07e,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,
+	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf0a4,	0xf07f,	0xf115,
+	0xf114,	0xf20b,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb51,
+	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,	0xfb4f,
+	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf116,	0xf117,	0xf20a,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb41,	0xfb53,	0xfb44,	0xfb46,
+	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,
+	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb5a,	0xfb58,
+	0xfb43,	0xfb56,	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,
+	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,	0xf511,	0xf512,
+	0xf513,	0xf514,	0xf515,	0xf516,	0xf517,	0xf200,	0xf202,	0xf205,
+	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,
+	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xfb71,
+	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
+	0xfb70,	0xf200,	0xf07e,	0xf200,	0xf116,	0xf117,	0xf119,	0xf911,
+	0xf912,	0xf913,	0xf30b,	0xf702,	0xf914,	0xfb73,	0xf917,	0xf919,
+	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,
+	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
+	0xf916,	0xfb76,	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,
+	0xf700,	0xf603,	0xf90b,	0xf90c,	0xf90d,	0xf207,	0xf703,	0xf200,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf90a,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf204,	0xf205,
+	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,
+	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf008,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
+	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
+	0xf010,	0xf01b,	0xf01d,	0xf01c,	0xf116,	0xf117,	0xf119,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
+	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,
+	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,
+	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf000,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf209,	0xf205,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
+	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
+	0xf010,	0xf200,	0xf200,	0xf200,	0xf116,	0xf117,	0xf119,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
+	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,
+	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,
+	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+	0xf81b,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
+	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
+	0xf860,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,
+	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf8a3,	0xf87f,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf809,	0xf871,
+	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,	0xf86f,
+	0xf870,	0xf85b,	0xf85d,	0xf85c,	0xf116,	0xf117,	0xf119,	0xf907,
+	0xf908,	0xf909,	0xf30b,	0xf702,	0xf861,	0xf873,	0xf864,	0xf866,
+	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf80d,
+	0xf904,	0xf905,	0xf906,	0xf30a,	0xf700,	0xf200,	0xf87a,	0xf878,
+	0xf863,	0xf876,	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,
+	0xf700,	0xf603,	0xf901,	0xf902,	0xf903,	0xf207,	0xf703,	0xf820,
+	0xf701,	0xf702,	0xf210,	0xf600,	0xf211,	0xf900,	0xf310,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
+	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,
+	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf811,
+	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,
+	0xf810,	0xf200,	0xf200,	0xf200,	0xf20c,	0xf117,	0xf119,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf702,	0xf801,	0xf813,	0xf804,	0xf806,
+	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,
+	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf81a,	0xf818,
+	0xf803,	0xf816,	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,
+	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
+	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf20c,	0xf30e,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', '\300'},	{'`', 'a', '\340'},
+	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
+	{'^', 'A', '\302'},	{'^', 'a', '\342'},
+	{'~', 'A', '\303'},	{'~', 'a', '\343'},
+	{'"', 'A', '\304'},	{'"', 'a', '\344'},
+	{'O', 'A', '\305'},	{'o', 'a', '\345'},
+	{'0', 'A', '\305'},	{'0', 'a', '\345'},
+	{'A', 'A', '\305'},	{'a', 'a', '\345'},
+	{'A', 'E', '\306'},	{'a', 'e', '\346'},
+	{',', 'C', '\307'},	{',', 'c', '\347'},
+	{'`', 'E', '\310'},	{'`', 'e', '\350'},
+	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
+	{'^', 'E', '\312'},	{'^', 'e', '\352'},
+	{'"', 'E', '\313'},	{'"', 'e', '\353'},
+	{'`', 'I', '\314'},	{'`', 'i', '\354'},
+	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
+	{'^', 'I', '\316'},	{'^', 'i', '\356'},
+	{'"', 'I', '\317'},	{'"', 'i', '\357'},
+	{'-', 'D', '\320'},	{'-', 'd', '\360'},
+	{'~', 'N', '\321'},	{'~', 'n', '\361'},
+	{'`', 'O', '\322'},	{'`', 'o', '\362'},
+	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
+	{'^', 'O', '\324'},	{'^', 'o', '\364'},
+	{'~', 'O', '\325'},	{'~', 'o', '\365'},
+	{'"', 'O', '\326'},	{'"', 'o', '\366'},
+	{'/', 'O', '\330'},	{'/', 'o', '\370'},
+	{'`', 'U', '\331'},	{'`', 'u', '\371'},
+	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
+	{'^', 'U', '\333'},	{'^', 'u', '\373'},
+	{'"', 'U', '\334'},	{'"', 'u', '\374'},
+	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
+	{'T', 'H', '\336'},	{'t', 'h', '\376'},
+	{'s', 's', '\337'},	{'"', 'y', '\377'},
+	{'s', 'z', '\337'},	{'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/block/ll_rw_blk.c	Fri Jul  5 16:42:56 2002
@@ -964,8 +964,7 @@
 		return;
 	}
 
-	list_splice(&blk_plug_list, &local_plug_list);
-	INIT_LIST_HEAD(&blk_plug_list);
+	list_splice_init(&blk_plug_list, &local_plug_list);
 	spin_unlock_irq(&blk_plug_lock);
 	
 	while (!list_empty(&local_plug_list)) {
@@ -1212,19 +1211,17 @@
 
 static long ro_bits[MAX_BLKDEV][8];
 
-int is_read_only(kdev_t dev)
+int bdev_read_only(struct block_device *bdev)
 {
 	int minor,major;
 
-	major = major(dev);
-	minor = minor(dev);
-	if (major < 0 || major >= MAX_BLKDEV) return 0;
+	if (!bdev)
+		return 0;
+	major = MAJOR(bdev->bd_dev);
+	minor = MINOR(bdev->bd_dev);
+	if (major < 0 || major >= MAX_BLKDEV)
+		return 0;
 	return ro_bits[major][minor >> 5] & (1 << (minor & 31));
-}
-
-int bdev_read_only(struct block_device *bdev)
-{
-	return bdev && is_read_only(to_kdev_t(bdev->bd_dev));
 }
 
 void set_device_ro(kdev_t dev,int flag)
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/cdrom/cdrom.c	Fri Jul  5 16:42:59 2002
@@ -318,8 +318,9 @@
 static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
 		     unsigned long arg);
 
-int cdrom_get_last_written(kdev_t dev, long *last_written);
-int cdrom_get_next_writable(kdev_t dev, long *next_writable);
+int cdrom_get_last_written(struct cdrom_device_info *, long *);
+static int cdrom_get_next_writable(struct cdrom_device_info *, long *);
+static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*);
 
 #ifdef CONFIG_SYSCTL
 static void cdrom_sysctl_register(void);
@@ -431,12 +432,17 @@
 		topCdromPtr = cdi->next;
 	cdi->ops->n_minors--;
 	devfs_unregister (cdi->de);
+	if (atomic_read (&cdi->cdrom_driverfs_dev.refcount)) {
+		device_remove_file (&cdi->cdrom_driverfs_dev, "name");
+		device_remove_file (&cdi->cdrom_driverfs_dev, "kdev");
+		put_device (&cdi->cdrom_driverfs_dev);
+	}
 	devfs_dealloc_unique_number (&cdrom_numspace, cdi->number);
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
 	return 0;
 }
 
-struct cdrom_device_info *cdrom_find_device(kdev_t dev)
+static struct cdrom_device_info *cdrom_find_device(kdev_t dev)
 {
 	struct cdrom_device_info *cdi;
 
@@ -775,7 +781,7 @@
 	return cdi->ops->generic_packet(cdi, &cgc);
 }
 
-int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
+static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
 {
 	struct cdrom_changer_info info;
 	int curslot;
@@ -859,7 +865,7 @@
 }
 
 /* badly broken, I know. Is due for a fixup anytime. */
-void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks)
+static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks)
 {
 	struct cdrom_tochdr header;
 	struct cdrom_tocentry entry;
@@ -1921,7 +1927,6 @@
 {		
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
-	kdev_t dev = cdi->dev;
 	char buffer[32];
 	int ret = 0;
 
@@ -2193,7 +2198,7 @@
 	case CDROM_NEXT_WRITABLE: {
 		long next = 0;
 		cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); 
-		if ((ret = cdrom_get_next_writable(dev, &next)))
+		if ((ret = cdrom_get_next_writable(cdi, &next)))
 			return ret;
 		IOCTL_OUT(arg, long, next);
 		return 0;
@@ -2201,7 +2206,7 @@
 	case CDROM_LAST_WRITTEN: {
 		long last = 0;
 		cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); 
-		if ((ret = cdrom_get_last_written(dev, &last)))
+		if ((ret = cdrom_get_last_written(cdi, &last)))
 			return ret;
 		IOCTL_OUT(arg, long, last);
 		return 0;
@@ -2211,10 +2216,9 @@
 	return -ENOTTY;
 }
 
-int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type,
+static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type,
 			 track_information *ti)
 {
-        struct cdrom_device_info *cdi = cdrom_find_device(dev);
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
 	int ret;
@@ -2241,9 +2245,8 @@
 }
 
 /* requires CD R/RW */
-int cdrom_get_disc_info(kdev_t dev, disc_information *di)
+static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di)
 {
-	struct cdrom_device_info *cdi = cdrom_find_device(dev);
 	struct cdrom_device_ops *cdo = cdi->ops;
 	struct cdrom_generic_command cgc;
 	int ret;
@@ -2273,9 +2276,8 @@
 
 /* return the last written block on the CD-R media. this is for the udf
    file system. */
-int cdrom_get_last_written(kdev_t dev, long *last_written)
-{	
-	struct cdrom_device_info *cdi = cdrom_find_device(dev);
+int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written)
+{
 	struct cdrom_tocentry toc;
 	disc_information di;
 	track_information ti;
@@ -2285,17 +2287,17 @@
 	if (!CDROM_CAN(CDC_GENERIC_PACKET))
 		goto use_toc;
 
-	if ((ret = cdrom_get_disc_info(dev, &di)))
+	if ((ret = cdrom_get_disc_info(cdi, &di)))
 		goto use_toc;
 
 	last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-	if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti)))
+	if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
 		goto use_toc;
 
 	/* if this track is blank, try the previous. */
 	if (ti.blank) {
 		last_track--;
-		if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti)))
+		if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
 			goto use_toc;
 	}
 
@@ -2325,9 +2327,8 @@
 }
 
 /* return the next writable block. also for udf file system. */
-int cdrom_get_next_writable(kdev_t dev, long *next_writable)
+static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable)
 {
-	struct cdrom_device_info *cdi = cdrom_find_device(dev);
 	disc_information di;
 	track_information ti;
 	__u16 last_track;
@@ -2336,17 +2337,17 @@
 	if (!CDROM_CAN(CDC_GENERIC_PACKET))
 		goto use_last_written;
 
-	if ((ret = cdrom_get_disc_info(dev, &di)))
+	if ((ret = cdrom_get_disc_info(cdi, &di)))
 		goto use_last_written;
 
 	last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-	if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti)))
+	if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
 		goto use_last_written;
 
         /* if this track is blank, try the previous. */
 	if (ti.blank) {
 		last_track--;
-		if ((ret = cdrom_get_track_info(dev, last_track, 1, &ti)))
+		if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
 			goto use_last_written;
 	}
 
@@ -2359,7 +2360,7 @@
 	return 0;
 
 use_last_written:
-	if ((ret = cdrom_get_last_written(dev, next_writable))) {
+	if ((ret = cdrom_get_last_written(cdi, next_writable))) {
 		*next_writable = 0;
 		return ret;
 	} else {
@@ -2368,11 +2369,7 @@
 	}
 }
 
-EXPORT_SYMBOL(cdrom_get_disc_info);
-EXPORT_SYMBOL(cdrom_get_track_info);
-EXPORT_SYMBOL(cdrom_get_next_writable);
 EXPORT_SYMBOL(cdrom_get_last_written);
-EXPORT_SYMBOL(cdrom_count_tracks);
 EXPORT_SYMBOL(register_cdrom);
 EXPORT_SYMBOL(unregister_cdrom);
 EXPORT_SYMBOL(cdrom_open);
@@ -2380,11 +2377,9 @@
 EXPORT_SYMBOL(cdrom_ioctl);
 EXPORT_SYMBOL(cdrom_media_changed);
 EXPORT_SYMBOL(cdrom_number_of_slots);
-EXPORT_SYMBOL(cdrom_select_disc);
 EXPORT_SYMBOL(cdrom_mode_select);
 EXPORT_SYMBOL(cdrom_mode_sense);
 EXPORT_SYMBOL(init_cdrom_command);
-EXPORT_SYMBOL(cdrom_find_device);
 
 #ifdef CONFIG_SYSCTL
 
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/Makefile	Fri Jul  5 16:42:59 2002
@@ -219,8 +219,20 @@
 $(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(obj)/conmakehash
 	$(obj)/conmakehash $< > $@
 
-$(obj)/defkeymap.c: $(src)/defkeymap.map
-	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+$(obj)/defkeymap.o:  $(obj)/defkeymap.c
 
-$(obj)/qtronixmap.c: $(src)/qtronixmap.map
-	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+$(obj)/qtronixmap.o: $(obj)/qtronixmap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
+	loadkeys --mktable $< > $@.tmp
+	sed -e 's/^static *//' $@.tmp > $@
+	rm $@.tmp
+
+endif
\ No newline at end of file
diff -Nru a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/defkeymap.c_shipped	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf200,	0xf01b,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,
+	0xf037,	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf07f,	0xf009,
+	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
+	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf201,	0xf702,	0xfb61,	0xfb73,
+	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,
+	0xf027,	0xf060,	0xf700,	0xf05c,	0xfb7a,	0xfb78,	0xfb63,	0xfb76,
+	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf700,	0xf30c,
+	0xf703,	0xf020,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
+	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf209,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
+	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03c,	0xf10a,
+	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+	0xf200,	0xf01b,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,
+	0xf026,	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf07f,	0xf009,
+	0xfb51,	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,
+	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf201,	0xf702,	0xfb41,	0xfb53,
+	0xfb44,	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,
+	0xf022,	0xf07e,	0xf700,	0xf07c,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
+	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf30c,
+	0xf703,	0xf020,	0xf207,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,
+	0xf10f,	0xf110,	0xf111,	0xf112,	0xf113,	0xf213,	0xf203,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
+	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03e,	0xf10a,
+	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf20b,	0xf601,	0xf602,	0xf117,	0xf600,	0xf20a,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
+	0xf07b,	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,
+	0xfb71,	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
+	0xfb6f,	0xfb70,	0xf200,	0xf07e,	0xf201,	0xf702,	0xf914,	0xfb73,
+	0xf917,	0xf919,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,
+	0xf200,	0xf200,	0xf700,	0xf200,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
+	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
+	0xf703,	0xf200,	0xf207,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,
+	0xf511,	0xf512,	0xf513,	0xf514,	0xf515,	0xf208,	0xf202,	0xf911,
+	0xf912,	0xf913,	0xf30b,	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf90b,
+	0xf90c,	0xf90d,	0xf90a,	0xf310,	0xf206,	0xf200,	0xf07c,	0xf516,
+	0xf517,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,
+	0xf01f,	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf008,	0xf200,
+	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
+	0xf00f,	0xf010,	0xf01b,	0xf01d,	0xf201,	0xf702,	0xf001,	0xf013,
+	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
+	0xf007,	0xf000,	0xf700,	0xf01c,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf30c,
+	0xf703,	0xf000,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
+	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf204,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
+	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf10a,
+	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,
+	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
+	0xf00f,	0xf010,	0xf200,	0xf200,	0xf201,	0xf702,	0xf001,	0xf013,
+	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
+	0xf200,	0xf200,	0xf700,	0xf200,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
+	0xf703,	0xf200,	0xf207,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf208,	0xf200,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
+	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+	0xf200,	0xf81b,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,
+	0xf837,	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf87f,	0xf809,
+	0xf871,	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,
+	0xf86f,	0xf870,	0xf85b,	0xf85d,	0xf80d,	0xf702,	0xf861,	0xf873,
+	0xf864,	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,
+	0xf827,	0xf860,	0xf700,	0xf85c,	0xf87a,	0xf878,	0xf863,	0xf876,
+	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf30c,
+	0xf703,	0xf820,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
+	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf209,	0xf907,
+	0xf908,	0xf909,	0xf30b,	0xf904,	0xf905,	0xf906,	0xf30a,	0xf901,
+	0xf902,	0xf903,	0xf900,	0xf310,	0xf206,	0xf200,	0xf83c,	0xf50a,
+	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf210,	0xf211,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf811,	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,
+	0xf80f,	0xf810,	0xf200,	0xf200,	0xf201,	0xf702,	0xf801,	0xf813,
+	0xf804,	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,
+	0xf200,	0xf200,	0xf700,	0xf200,	0xf81a,	0xf818,	0xf803,	0xf816,
+	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
+	0xf703,	0xf200,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
+	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf200,	0xf307,
+	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
+	0xf302,	0xf303,	0xf300,	0xf20c,	0xf206,	0xf200,	0xf200,	0xf50a,
+	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
+	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf20c,
+	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', '\300'},	{'`', 'a', '\340'},
+	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
+	{'^', 'A', '\302'},	{'^', 'a', '\342'},
+	{'~', 'A', '\303'},	{'~', 'a', '\343'},
+	{'"', 'A', '\304'},	{'"', 'a', '\344'},
+	{'O', 'A', '\305'},	{'o', 'a', '\345'},
+	{'0', 'A', '\305'},	{'0', 'a', '\345'},
+	{'A', 'A', '\305'},	{'a', 'a', '\345'},
+	{'A', 'E', '\306'},	{'a', 'e', '\346'},
+	{',', 'C', '\307'},	{',', 'c', '\347'},
+	{'`', 'E', '\310'},	{'`', 'e', '\350'},
+	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
+	{'^', 'E', '\312'},	{'^', 'e', '\352'},
+	{'"', 'E', '\313'},	{'"', 'e', '\353'},
+	{'`', 'I', '\314'},	{'`', 'i', '\354'},
+	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
+	{'^', 'I', '\316'},	{'^', 'i', '\356'},
+	{'"', 'I', '\317'},	{'"', 'i', '\357'},
+	{'-', 'D', '\320'},	{'-', 'd', '\360'},
+	{'~', 'N', '\321'},	{'~', 'n', '\361'},
+	{'`', 'O', '\322'},	{'`', 'o', '\362'},
+	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
+	{'^', 'O', '\324'},	{'^', 'o', '\364'},
+	{'~', 'O', '\325'},	{'~', 'o', '\365'},
+	{'"', 'O', '\326'},	{'"', 'o', '\366'},
+	{'/', 'O', '\330'},	{'/', 'o', '\370'},
+	{'`', 'U', '\331'},	{'`', 'u', '\371'},
+	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
+	{'^', 'U', '\333'},	{'^', 'u', '\373'},
+	{'"', 'U', '\334'},	{'"', 'u', '\374'},
+	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
+	{'T', 'H', '\336'},	{'t', 'h', '\376'},
+	{'s', 's', '\337'},	{'"', 'y', '\377'},
+	{'s', 'z', '\337'},	{'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff -Nru a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
--- a/drivers/char/drm/drm.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/drm.h	Fri Jul  5 16:42:59 2002
@@ -84,6 +84,10 @@
 /* Warning: If you change this structure, make sure you change
  * XF86DRIClipRectRec in the server as well */
 
+/* KW: Actually it's illegal to change either for
+ * backwards-compatibility reasons.
+ */
+
 typedef struct drm_clip_rect {
 	unsigned short	x1;
 	unsigned short	y1;
@@ -99,15 +103,6 @@
 	unsigned int	age;
 } drm_tex_region_t;
 
-/* Seperate include files for the i810/mga/r128 specific structures */
-#include "mga_drm.h"
-#include "i810_drm.h"
-#include "r128_drm.h"
-#include "radeon_drm.h"
-#include "sis_drm.h"
-#include "i830_drm.h"
-#include "gamma_drm.h"
-
 typedef struct drm_version {
 	int    version_major;	  /* Major version			    */
 	int    version_minor;	  /* Minor version			    */
@@ -428,95 +423,8 @@
 #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, drm_scatter_gather_t)
 #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, drm_scatter_gather_t)
 
-/* MGA specific ioctls */
-#define DRM_IOCTL_MGA_INIT		DRM_IOW( 0x40, drm_mga_init_t)
-#define DRM_IOCTL_MGA_FLUSH		DRM_IOW( 0x41, drm_lock_t)
-#define DRM_IOCTL_MGA_RESET		DRM_IO(  0x42)
-#define DRM_IOCTL_MGA_SWAP		DRM_IO(  0x43)
-#define DRM_IOCTL_MGA_CLEAR		DRM_IOW( 0x44, drm_mga_clear_t)
-#define DRM_IOCTL_MGA_VERTEX		DRM_IOW( 0x45, drm_mga_vertex_t)
-#define DRM_IOCTL_MGA_INDICES		DRM_IOW( 0x46, drm_mga_indices_t)
-#define DRM_IOCTL_MGA_ILOAD		DRM_IOW( 0x47, drm_mga_iload_t)
-#define DRM_IOCTL_MGA_BLIT		DRM_IOW( 0x48, drm_mga_blit_t)
-
-/* i810 specific ioctls */
-#define DRM_IOCTL_I810_INIT		DRM_IOW( 0x40, drm_i810_init_t)
-#define DRM_IOCTL_I810_VERTEX		DRM_IOW( 0x41, drm_i810_vertex_t)
-#define DRM_IOCTL_I810_CLEAR		DRM_IOW( 0x42, drm_i810_clear_t)
-#define DRM_IOCTL_I810_FLUSH		DRM_IO(  0x43)
-#define DRM_IOCTL_I810_GETAGE		DRM_IO(  0x44)
-#define DRM_IOCTL_I810_GETBUF		DRM_IOWR(0x45, drm_i810_dma_t)
-#define DRM_IOCTL_I810_SWAP		DRM_IO(  0x46)
-#define DRM_IOCTL_I810_COPY		DRM_IOW( 0x47, drm_i810_copy_t)
-#define DRM_IOCTL_I810_DOCOPY		DRM_IO(  0x48)
-#define DRM_IOCTL_I810_OV0INFO		DRM_IOR( 0x49, drm_i810_overlay_t)
-#define DRM_IOCTL_I810_FSTATUS		DRM_IO ( 0x4a)
-#define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)
-#define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)
-#define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d )
-
-
-/* Rage 128 specific ioctls */
-#define DRM_IOCTL_R128_INIT		DRM_IOW( 0x40, drm_r128_init_t)
-#define DRM_IOCTL_R128_CCE_START	DRM_IO(  0x41)
-#define DRM_IOCTL_R128_CCE_STOP		DRM_IOW( 0x42, drm_r128_cce_stop_t)
-#define DRM_IOCTL_R128_CCE_RESET	DRM_IO(  0x43)
-#define DRM_IOCTL_R128_CCE_IDLE		DRM_IO(  0x44)
-#define DRM_IOCTL_R128_RESET		DRM_IO(  0x46)
-#define DRM_IOCTL_R128_SWAP		DRM_IO(  0x47)
-#define DRM_IOCTL_R128_CLEAR		DRM_IOW( 0x48, drm_r128_clear_t)
-#define DRM_IOCTL_R128_VERTEX		DRM_IOW( 0x49, drm_r128_vertex_t)
-#define DRM_IOCTL_R128_INDICES		DRM_IOW( 0x4a, drm_r128_indices_t)
-#define DRM_IOCTL_R128_BLIT		DRM_IOW( 0x4b, drm_r128_blit_t)
-#define DRM_IOCTL_R128_DEPTH		DRM_IOW( 0x4c, drm_r128_depth_t)
-#define DRM_IOCTL_R128_STIPPLE		DRM_IOW( 0x4d, drm_r128_stipple_t)
-#define DRM_IOCTL_R128_INDIRECT		DRM_IOWR(0x4f, drm_r128_indirect_t)
-#define DRM_IOCTL_R128_FULLSCREEN	DRM_IOW( 0x50, drm_r128_fullscreen_t)
-#define DRM_IOCTL_R128_CLEAR2		DRM_IOW( 0x51, drm_r128_clear2_t)
-
-/* Radeon specific ioctls */
-#define DRM_IOCTL_RADEON_CP_INIT	DRM_IOW( 0x40, drm_radeon_init_t)
-#define DRM_IOCTL_RADEON_CP_START	DRM_IO(  0x41)
-#define DRM_IOCTL_RADEON_CP_STOP	DRM_IOW( 0x42, drm_radeon_cp_stop_t)
-#define DRM_IOCTL_RADEON_CP_RESET	DRM_IO(  0x43)
-#define DRM_IOCTL_RADEON_CP_IDLE	DRM_IO(  0x44)
-#define DRM_IOCTL_RADEON_RESET		DRM_IO(  0x45)
-#define DRM_IOCTL_RADEON_FULLSCREEN	DRM_IOW( 0x46, drm_radeon_fullscreen_t)
-#define DRM_IOCTL_RADEON_SWAP		DRM_IO(  0x47)
-#define DRM_IOCTL_RADEON_CLEAR		DRM_IOW( 0x48, drm_radeon_clear_t)
-#define DRM_IOCTL_RADEON_VERTEX		DRM_IOW( 0x49, drm_radeon_vertex_t)
-#define DRM_IOCTL_RADEON_INDICES	DRM_IOW( 0x4a, drm_radeon_indices_t)
-#define DRM_IOCTL_RADEON_STIPPLE	DRM_IOW( 0x4c, drm_radeon_stipple_t)
-#define DRM_IOCTL_RADEON_INDIRECT	DRM_IOWR(0x4d, drm_radeon_indirect_t)
-#define DRM_IOCTL_RADEON_TEXTURE	DRM_IOWR(0x4e, drm_radeon_texture_t)
-#define DRM_IOCTL_RADEON_VERTEX2	DRM_IOW( 0x4f, drm_radeon_vertex_t)
-#define DRM_IOCTL_RADEON_CMDBUF  	DRM_IOW( 0x50, drm_radeon_cmd_buffer_t)
-#define DRM_IOCTL_RADEON_GETPARAM	DRM_IOWR(0x51, drm_radeon_getparam_t)
-#define DRM_IOCTL_RADEON_FLIP		DRM_IO(  0x52)
-
-/* Gamma specific ioctls */
-#define DRM_IOCTL_GAMMA_INIT		DRM_IOW( 0x40, drm_gamma_init_t)
-#define DRM_IOCTL_GAMMA_COPY		DRM_IOW( 0x41, drm_gamma_copy_t)
-
-/* SiS specific ioctls */
-#define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
-#define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
-#define SIS_IOCTL_AGP_INIT		DRM_IOWR(0x53, drm_sis_agp_t)
-#define SIS_IOCTL_AGP_ALLOC		DRM_IOWR(0x54, drm_sis_mem_t)
-#define SIS_IOCTL_AGP_FREE		DRM_IOW( 0x55, drm_sis_mem_t)
-#define SIS_IOCTL_FLIP			DRM_IOW( 0x48, drm_sis_flip_t)
-#define SIS_IOCTL_FLIP_INIT		DRM_IO(  0x49)
-#define SIS_IOCTL_FLIP_FINAL		DRM_IO(  0x50)
-
-/* I830 specific ioctls */
-#define DRM_IOCTL_I830_INIT		DRM_IOW( 0x40, drm_i830_init_t)
-#define DRM_IOCTL_I830_VERTEX		DRM_IOW( 0x41, drm_i830_vertex_t)
-#define DRM_IOCTL_I830_CLEAR		DRM_IOW( 0x42, drm_i830_clear_t)
-#define DRM_IOCTL_I830_FLUSH		DRM_IO ( 0x43)
-#define DRM_IOCTL_I830_GETAGE		DRM_IO ( 0x44)
-#define DRM_IOCTL_I830_GETBUF		DRM_IOWR(0x45, drm_i830_dma_t)
-#define DRM_IOCTL_I830_SWAP		DRM_IO ( 0x46)
-#define DRM_IOCTL_I830_COPY		DRM_IOW( 0x47, drm_i830_copy_t)
-#define DRM_IOCTL_I830_DOCOPY		DRM_IO ( 0x48)
+/* Device specfic ioctls should only be in their respective headers
+ * The device specific ioctl range is 0x40 to 0x79.                  */
+#define DRM_COMMAND_BASE                0x40
 
 #endif
diff -Nru a/drivers/char/drm/drm_context.h b/drivers/char/drm/drm_context.h
--- a/drivers/char/drm/drm_context.h	Fri Jul  5 16:42:44 2002
+++ b/drivers/char/drm/drm_context.h	Fri Jul  5 16:42:44 2002
@@ -555,7 +555,7 @@
 				/* Allocate a new queue */
 	down(&dev->struct_sem);
 
-	queue = gamma_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+	queue = DRM(alloc)(sizeof(*queue), DRM_MEM_QUEUES);
 	memset(queue, 0, sizeof(*queue));
 	atomic_set(&queue->use_count, 1);
 
diff -Nru a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c
--- a/drivers/char/drm/gamma_dma.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/gamma_dma.c	Fri Jul  5 16:43:00 2002
@@ -32,6 +32,8 @@
 #define __NO_VERSION__
 #include "gamma.h"
 #include "drmP.h"
+#include "drm.h"
+#include "gamma_drm.h"
 #include "gamma_drv.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
diff -Nru a/drivers/char/drm/gamma_drm.h b/drivers/char/drm/gamma_drm.h
--- a/drivers/char/drm/gamma_drm.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/gamma_drm.h	Fri Jul  5 16:43:00 2002
@@ -48,6 +48,16 @@
 	int vertex_prim;
 } drm_gamma_sarea_t;
 
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (xf86drmGamma.h)
+ */
+
+/* Gamma specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_GAMMA_INIT		DRM_IOW( 0x40, drm_gamma_init_t)
+#define DRM_IOCTL_GAMMA_COPY		DRM_IOW( 0x41, drm_gamma_copy_t)
+
 typedef struct drm_gamma_copy {
 	unsigned int	DMAOutputAddress;
 	unsigned int	DMAOutputCount;
diff -Nru a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
--- a/drivers/char/drm/gamma_drv.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/gamma_drv.c	Fri Jul  5 16:43:00 2002
@@ -32,6 +32,8 @@
 #include <linux/config.h>
 #include "gamma.h"
 #include "drmP.h"
+#include "drm.h"
+#include "gamma_drm.h"
 #include "gamma_drv.h"
 
 #define DRIVER_AUTHOR		"VA Linux Systems Inc."
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/i810_dma.c	Fri Jul  5 16:42:59 2002
@@ -33,6 +33,8 @@
 #define __NO_VERSION__
 #include "i810.h"
 #include "drmP.h"
+#include "drm.h"
+#include "i810_drm.h"
 #include "i810_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
 #include <linux/delay.h>
diff -Nru a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h
--- a/drivers/char/drm/i810_drm.h	Fri Jul  5 16:42:44 2002
+++ b/drivers/char/drm/i810_drm.h	Fri Jul  5 16:42:44 2002
@@ -168,13 +168,33 @@
 
 } drm_i810_sarea_t;
 
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (xf86drmMga.h)
+ */
+
+/* i810 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_I810_INIT		DRM_IOW( 0x40, drm_i810_init_t)
+#define DRM_IOCTL_I810_VERTEX		DRM_IOW( 0x41, drm_i810_vertex_t)
+#define DRM_IOCTL_I810_CLEAR		DRM_IOW( 0x42, drm_i810_clear_t)
+#define DRM_IOCTL_I810_FLUSH		DRM_IO(  0x43)
+#define DRM_IOCTL_I810_GETAGE		DRM_IO(  0x44)
+#define DRM_IOCTL_I810_GETBUF		DRM_IOWR(0x45, drm_i810_dma_t)
+#define DRM_IOCTL_I810_SWAP		DRM_IO(  0x46)
+#define DRM_IOCTL_I810_COPY		DRM_IOW( 0x47, drm_i810_copy_t)
+#define DRM_IOCTL_I810_DOCOPY		DRM_IO(  0x48)
+#define DRM_IOCTL_I810_OV0INFO		DRM_IOR( 0x49, drm_i810_overlay_t)
+#define DRM_IOCTL_I810_FSTATUS		DRM_IO ( 0x4a)
+#define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)
+#define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)
+#define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d )
+
 typedef struct _drm_i810_clear {
 	int clear_color;
 	int clear_depth;
 	int flags;
 } drm_i810_clear_t;
-
-
 
 /* These may be placeholders if we have more cliprects than
  * I810_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to
diff -Nru a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
--- a/drivers/char/drm/i810_drv.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/i810_drv.c	Fri Jul  5 16:43:00 2002
@@ -33,6 +33,8 @@
 #include <linux/config.h>
 #include "i810.h"
 #include "drmP.h"
+#include "drm.h"
+#include "i810_drm.h"
 #include "i810_drv.h"
 
 #define DRIVER_AUTHOR		"VA Linux Systems Inc."
diff -Nru a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
--- a/drivers/char/drm/i830_dma.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/char/drm/i830_dma.c	Fri Jul  5 16:42:56 2002
@@ -34,10 +34,11 @@
 #define __NO_VERSION__
 #include "i830.h"
 #include "drmP.h"
+#include "drm.h"
+#include "i830_drm.h"
 #include "i830_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
 #include <linux/delay.h>
-#include <linux/pagemap.h>
 
 /* in case we don't have a 2.3.99-pre6 kernel or later: */
 #ifndef VM_DONTCOPY
@@ -58,7 +59,6 @@
 do {								\
    int _head;							\
    int _tail;							\
-   int _i;							\
    do { 							\
       _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	\
       _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;	\
@@ -369,9 +369,7 @@
 	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 
 	end = jiffies + (HZ*3);
-   	while (ring->space < n) {
-	   	int i;
-	
+   	while (ring->space < n) {	
 	   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 	   	ring->space = ring->head - (ring->tail+8);
 		if (ring->space < 0) ring->space += ring->Size;
@@ -387,7 +385,6 @@
 		   	DRM_ERROR("lockup\n");
 		   	goto out_wait_ring;
 		}
-
 		udelay(1);
 	}
 
diff -Nru a/drivers/char/drm/i830_drm.h b/drivers/char/drm/i830_drm.h
--- a/drivers/char/drm/i830_drm.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/i830_drm.h	Fri Jul  5 16:42:59 2002
@@ -201,6 +201,19 @@
 	int vertex_prim;
 } drm_i830_sarea_t;
 
+/* I830 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_I830_INIT		DRM_IOW( 0x40, drm_i830_init_t)
+#define DRM_IOCTL_I830_VERTEX		DRM_IOW( 0x41, drm_i830_vertex_t)
+#define DRM_IOCTL_I830_CLEAR		DRM_IOW( 0x42, drm_i830_clear_t)
+#define DRM_IOCTL_I830_FLUSH		DRM_IO ( 0x43)
+#define DRM_IOCTL_I830_GETAGE		DRM_IO ( 0x44)
+#define DRM_IOCTL_I830_GETBUF		DRM_IOWR(0x45, drm_i830_dma_t)
+#define DRM_IOCTL_I830_SWAP		DRM_IO ( 0x46)
+#define DRM_IOCTL_I830_COPY		DRM_IOW( 0x47, drm_i830_copy_t)
+#define DRM_IOCTL_I830_DOCOPY		DRM_IO ( 0x48)
+
 typedef struct _drm_i830_clear {
 	int clear_color;
 	int clear_depth;
diff -Nru a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c
--- a/drivers/char/drm/i830_drv.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/i830_drv.c	Fri Jul  5 16:42:59 2002
@@ -34,6 +34,8 @@
 #include <linux/config.h>
 #include "i830.h"
 #include "drmP.h"
+#include "drm.h"
+#include "i830_drm.h"
 #include "i830_drv.h"
 
 #define DRIVER_AUTHOR		"VA Linux Systems Inc."
diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
--- a/drivers/char/drm/mga_dma.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/mga_dma.c	Fri Jul  5 16:42:59 2002
@@ -36,6 +36,8 @@
 #define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
 #include "mga_drv.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
diff -Nru a/drivers/char/drm/mga_drm.h b/drivers/char/drm/mga_drm.h
--- a/drivers/char/drm/mga_drm.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/mga_drm.h	Fri Jul  5 16:42:59 2002
@@ -38,6 +38,7 @@
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the Xserver file (mga_sarea.h)
  */
+
 #ifndef __MGA_SAREA_DEFINES__
 #define __MGA_SAREA_DEFINES__
 
@@ -225,6 +226,20 @@
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the Xserver file (xf86drmMga.h)
  */
+
+/* MGA specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_MGA_INIT		DRM_IOW( 0x40, drm_mga_init_t)
+#define DRM_IOCTL_MGA_FLUSH		DRM_IOW( 0x41, drm_lock_t)
+#define DRM_IOCTL_MGA_RESET		DRM_IO(  0x42)
+#define DRM_IOCTL_MGA_SWAP		DRM_IO(  0x43)
+#define DRM_IOCTL_MGA_CLEAR		DRM_IOW( 0x44, drm_mga_clear_t)
+#define DRM_IOCTL_MGA_VERTEX		DRM_IOW( 0x45, drm_mga_vertex_t)
+#define DRM_IOCTL_MGA_INDICES		DRM_IOW( 0x46, drm_mga_indices_t)
+#define DRM_IOCTL_MGA_ILOAD		DRM_IOW( 0x47, drm_mga_iload_t)
+#define DRM_IOCTL_MGA_BLIT		DRM_IOW( 0x48, drm_mga_blit_t)
+
 typedef struct _drm_mga_warp_index {
    	int installed;
    	unsigned long phys_addr;
diff -Nru a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
--- a/drivers/char/drm/mga_drv.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/mga_drv.c	Fri Jul  5 16:42:59 2002
@@ -32,6 +32,8 @@
 #include <linux/config.h>
 #include "mga.h"
 #include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
 #include "mga_drv.h"
 
 #define DRIVER_AUTHOR		"Gareth Hughes, VA Linux Systems Inc."
diff -Nru a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
--- a/drivers/char/drm/mga_state.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/mga_state.c	Fri Jul  5 16:42:59 2002
@@ -35,6 +35,8 @@
 #define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
 #include "mga_drv.h"
 #include "drm.h"
 
diff -Nru a/drivers/char/drm/mga_warp.c b/drivers/char/drm/mga_warp.c
--- a/drivers/char/drm/mga_warp.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/mga_warp.c	Fri Jul  5 16:42:59 2002
@@ -30,6 +30,8 @@
 #define __NO_VERSION__
 #include "mga.h"
 #include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
 #include "mga_drv.h"
 #include "mga_ucode.h"
 
diff -Nru a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
--- a/drivers/char/drm/r128_cce.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/r128_cce.c	Fri Jul  5 16:42:59 2002
@@ -31,6 +31,8 @@
 #define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
 #include "r128_drv.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
diff -Nru a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
--- a/drivers/char/drm/r128_drm.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/r128_drm.h	Fri Jul  5 16:43:00 2002
@@ -170,6 +170,27 @@
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the Xserver file (xf86drmR128.h)
  */
+
+/* Rage 128 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_R128_INIT		DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_CCE_START	DRM_IO(  0x41)
+#define DRM_IOCTL_R128_CCE_STOP		DRM_IOW( 0x42, drm_r128_cce_stop_t)
+#define DRM_IOCTL_R128_CCE_RESET	DRM_IO(  0x43)
+#define DRM_IOCTL_R128_CCE_IDLE		DRM_IO(  0x44)
+#define DRM_IOCTL_R128_RESET		DRM_IO(  0x46)
+#define DRM_IOCTL_R128_SWAP		DRM_IO(  0x47)
+#define DRM_IOCTL_R128_CLEAR		DRM_IOW( 0x48, drm_r128_clear_t)
+#define DRM_IOCTL_R128_VERTEX		DRM_IOW( 0x49, drm_r128_vertex_t)
+#define DRM_IOCTL_R128_INDICES		DRM_IOW( 0x4a, drm_r128_indices_t)
+#define DRM_IOCTL_R128_BLIT		DRM_IOW( 0x4b, drm_r128_blit_t)
+#define DRM_IOCTL_R128_DEPTH		DRM_IOW( 0x4c, drm_r128_depth_t)
+#define DRM_IOCTL_R128_STIPPLE		DRM_IOW( 0x4d, drm_r128_stipple_t)
+#define DRM_IOCTL_R128_INDIRECT		DRM_IOWR(0x4f, drm_r128_indirect_t)
+#define DRM_IOCTL_R128_FULLSCREEN	DRM_IOW( 0x50, drm_r128_fullscreen_t)
+#define DRM_IOCTL_R128_CLEAR2		DRM_IOW( 0x51, drm_r128_clear2_t)
+
 typedef struct drm_r128_init {
 	enum {
 		R128_INIT_CCE    = 0x01,
diff -Nru a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
--- a/drivers/char/drm/r128_drv.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/r128_drv.c	Fri Jul  5 16:42:59 2002
@@ -32,6 +32,8 @@
 #include <linux/config.h>
 #include "r128.h"
 #include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
 #include "r128_drv.h"
 #include "ati_pcigart.h"
 
diff -Nru a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
--- a/drivers/char/drm/r128_drv.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/r128_drv.h	Fri Jul  5 16:43:00 2002
@@ -34,8 +34,8 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
-#define GET_RING_HEAD( ring )		le32_to_cpu( *(ring)->head )
-#define SET_RING_HEAD( ring, val )	*(ring)->head = cpu_to_le32( val )
+#define GET_RING_HEAD(ring)		readl( (volatile u32 *) (ring)->head )
+#define SET_RING_HEAD(ring,val)		writel( (val), (volatile u32 *) (ring)->head )
 
 typedef struct drm_r128_freelist {
    	unsigned int age;
@@ -384,44 +384,11 @@
 #define R128_BASE(reg)		((unsigned long)(dev_priv->mmio->handle))
 #define R128_ADDR(reg)		(R128_BASE( reg ) + reg)
 
-#define R128_DEREF(reg)		*(volatile u32 *)R128_ADDR( reg )
-#ifdef __alpha__
-#define R128_READ(reg)		(_R128_READ((u32 *)R128_ADDR(reg)))
-static inline u32 _R128_READ(u32 *addr)
-{
-	mb();
-	return *(volatile u32 *)addr;
-}
-#define R128_WRITE(reg,val)						\
-do {									\
-	wmb();								\
-	R128_DEREF(reg) = val;						\
-} while (0)
-#else
-#define R128_READ(reg)		le32_to_cpu( R128_DEREF( reg ) )
-#define R128_WRITE(reg,val)						\
-do {									\
-	R128_DEREF( reg ) = cpu_to_le32( val );				\
-} while (0)
-#endif
+#define R128_READ(reg)		readl( (volatile u32 *) R128_ADDR(reg) )
+#define R128_WRITE(reg,val)	writel( (val), (volatile u32 *) R128_ADDR(reg) )
 
-#define R128_DEREF8(reg)	*(volatile u8 *)R128_ADDR( reg )
-#ifdef __alpha__
-#define R128_READ8(reg)		_R128_READ8((u8 *)R128_ADDR(reg))
-static inline u8 _R128_READ8(u8 *addr)
-{
-	mb();
-	return *(volatile u8 *)addr;
-}
-#define R128_WRITE8(reg,val)						\
-do {									\
-	wmb();								\
-	R128_DEREF8(reg) = val;						\
-} while (0)
-#else
-#define R128_READ8(reg)		R128_DEREF8( reg )
-#define R128_WRITE8(reg,val)	do { R128_DEREF8( reg ) = val; } while (0)
-#endif
+#define R128_READ8(reg)		readb( (volatile u8 *) R128_ADDR(reg) )
+#define R128_WRITE8(reg,val)	writeb( (val), (volatile u8 *) R128_ADDR(reg) )
 
 #define R128_WRITE_PLL(addr,val)					\
 do {									\
@@ -493,7 +460,11 @@
  * Ring control
  */
 
+#if defined(__powerpc__)
+#define r128_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
+#else
 #define r128_flush_write_combine()	mb()
+#endif
 
 
 #define R128_VERBOSE	0
diff -Nru a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
--- a/drivers/char/drm/r128_state.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/r128_state.c	Fri Jul  5 16:42:59 2002
@@ -30,6 +30,8 @@
 #define __NO_VERSION__
 #include "r128.h"
 #include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
 #include "r128_drv.h"
 #include "drm.h"
 #include <linux/delay.h>
diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
--- a/drivers/char/drm/radeon_cp.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/radeon_cp.c	Fri Jul  5 16:42:59 2002
@@ -31,6 +31,8 @@
 #define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
 #include "radeon_drv.h"
 
 #include <linux/interrupt.h>	/* For task queue support */
@@ -38,7 +40,7 @@
 
 #define RADEON_FIFO_DEBUG	0
 
-#if defined(__alpha__)
+#if defined(__alpha__) || defined(__powerpc__)
 # define PCIGART_ENABLED
 #else
 # undef PCIGART_ENABLED
@@ -631,7 +633,11 @@
 	}
 
 	/* Set ring buffer size */
+#ifdef __BIG_ENDIAN
+	RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT );
+#else
 	RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw );
+#endif
 
 	radeon_do_wait_for_idle( dev_priv );
 
diff -Nru a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
--- a/drivers/char/drm/radeon_drm.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/radeon_drm.h	Fri Jul  5 16:43:00 2002
@@ -301,6 +301,29 @@
  *
  * KW: actually it's illegal to change any of this (backwards compatibility).
  */
+
+/* Radeon specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( 0x40, drm_radeon_init_t)
+#define DRM_IOCTL_RADEON_CP_START   DRM_IO(  0x41)
+#define DRM_IOCTL_RADEON_CP_STOP    DRM_IOW( 0x42, drm_radeon_cp_stop_t)
+#define DRM_IOCTL_RADEON_CP_RESET   DRM_IO(  0x43)
+#define DRM_IOCTL_RADEON_CP_IDLE    DRM_IO(  0x44)
+#define DRM_IOCTL_RADEON_RESET      DRM_IO(  0x45)
+#define DRM_IOCTL_RADEON_FULLSCREEN DRM_IOW( 0x46, drm_radeon_fullscreen_t)
+#define DRM_IOCTL_RADEON_SWAP       DRM_IO(  0x47)
+#define DRM_IOCTL_RADEON_CLEAR      DRM_IOW( 0x48, drm_radeon_clear_t)
+#define DRM_IOCTL_RADEON_VERTEX     DRM_IOW( 0x49, drm_radeon_vertex_t)
+#define DRM_IOCTL_RADEON_INDICES    DRM_IOW( 0x4a, drm_radeon_indices_t)
+#define DRM_IOCTL_RADEON_STIPPLE    DRM_IOW( 0x4c, drm_radeon_stipple_t)
+#define DRM_IOCTL_RADEON_INDIRECT   DRM_IOWR(0x4d, drm_radeon_indirect_t)
+#define DRM_IOCTL_RADEON_TEXTURE    DRM_IOWR(0x4e, drm_radeon_texture_t)
+#define DRM_IOCTL_RADEON_VERTEX2    DRM_IOW( 0x4f, drm_radeon_vertex_t)
+#define DRM_IOCTL_RADEON_CMDBUF     DRM_IOW( 0x50, drm_radeon_cmd_buffer_t)
+#define DRM_IOCTL_RADEON_GETPARAM   DRM_IOWR(0x51, drm_radeon_getparam_t)
+#define DRM_IOCTL_RADEON_FLIP	    DRM_IO(  0x52)
+
 typedef struct drm_radeon_init {
 	enum {
 		RADEON_INIT_CP    = 0x01,
diff -Nru a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
--- a/drivers/char/drm/radeon_drv.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/radeon_drv.c	Fri Jul  5 16:42:59 2002
@@ -30,6 +30,8 @@
 #include <linux/config.h>
 #include "radeon.h"
 #include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
 #include "radeon_drv.h"
 #include "ati_pcigart.h"
 
@@ -37,11 +39,11 @@
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20020521"
+#define DRIVER_DATE		"20020611"
 
 #define DRIVER_MAJOR		1
 #define DRIVER_MINOR		3
-#define DRIVER_PATCHLEVEL	0
+#define DRIVER_PATCHLEVEL	1
 
 /* Interface history:
  *
diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
--- a/drivers/char/drm/radeon_drv.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/radeon_drv.h	Fri Jul  5 16:43:00 2002
@@ -31,6 +31,9 @@
 #ifndef __RADEON_DRV_H__
 #define __RADEON_DRV_H__
 
+#define GET_RING_HEAD(ring)		readl( (volatile u32 *) (ring)->head )
+#define SET_RING_HEAD(ring,val)		writel( (val), (volatile u32 *) (ring)->head )
+
 typedef struct drm_radeon_freelist {
    	unsigned int age;
    	drm_buf_t *buf;
@@ -141,7 +144,7 @@
 static inline void
 radeon_update_ring_snapshot( drm_radeon_ring_buffer_t *ring )
 {
-	ring->space = (*(volatile int *)ring->head - ring->tail) * sizeof(u32);
+	ring->space = (GET_RING_HEAD(ring) - ring->tail) * sizeof(u32);
 	if ( ring->space <= 0 )
 		ring->space += ring->size;
 }
@@ -249,6 +252,12 @@
 #	define RADEON_ISYNC_WAIT_IDLEGUI	(1 << 4)
 #	define RADEON_ISYNC_CPSCRATCH_IDLEGUI	(1 << 5)
 
+#define RADEON_RBBM_GUICNTL		0x172c
+#	define RADEON_HOST_DATA_SWAP_NONE	(0 << 0)
+#	define RADEON_HOST_DATA_SWAP_16BIT	(1 << 0)
+#	define RADEON_HOST_DATA_SWAP_32BIT	(2 << 0)
+#	define RADEON_HOST_DATA_SWAP_HDW	(3 << 0)
+
 #define RADEON_MC_AGP_LOCATION		0x014c
 #define RADEON_MC_FB_LOCATION		0x0148
 #define RADEON_MCLK_CNTL		0x0012
@@ -424,6 +433,7 @@
 
 #define RADEON_CP_RB_BASE		0x0700
 #define RADEON_CP_RB_CNTL		0x0704
+#	define RADEON_BUF_SWAP_32BIT		(2 << 16)
 #define RADEON_CP_RB_RPTR_ADDR		0x070c
 #define RADEON_CP_RB_RPTR		0x0710
 #define RADEON_CP_RB_WPTR		0x0714
@@ -467,6 +477,7 @@
 #	define RADEON_CNTL_HOSTDATA_BLT		0x00009400
 #	define RADEON_CNTL_PAINT_MULTI		0x00009A00
 #	define RADEON_CNTL_BITBLT_MULTI		0x00009B00
+#	define RADEON_CNTL_SET_SCISSORS		0xC0001E00
 
 #define RADEON_CP_PACKET_MASK		0xC0000000
 #define RADEON_CP_PACKET_COUNT_MASK	0x3fff0000
@@ -533,41 +544,11 @@
 #define RADEON_BASE(reg)	((unsigned long)(dev_priv->mmio->handle))
 #define RADEON_ADDR(reg)	(RADEON_BASE( reg ) + reg)
 
-#define RADEON_DEREF(reg)	*(volatile u32 *)RADEON_ADDR( reg )
-#ifdef __alpha__
-#define RADEON_READ(reg)	(_RADEON_READ((u32 *)RADEON_ADDR( reg )))
-static inline u32 _RADEON_READ(u32 *addr)
-{
-	mb();
-	return *(volatile u32 *)addr;
-}
-#define RADEON_WRITE(reg,val)						\
-do {									\
-	wmb();								\
-	RADEON_DEREF(reg) = val;					\
-} while (0)
-#else
-#define RADEON_READ(reg)	RADEON_DEREF( reg )
-#define RADEON_WRITE(reg, val)	do { RADEON_DEREF( reg ) = val; } while (0)
-#endif
+#define RADEON_READ(reg)	readl( (volatile u32 *) RADEON_ADDR(reg) )
+#define RADEON_WRITE(reg,val)	writel( (val), (volatile u32 *) RADEON_ADDR(reg) )
 
-#define RADEON_DEREF8(reg)	*(volatile u8 *)RADEON_ADDR( reg )
-#ifdef __alpha__
-#define RADEON_READ8(reg)	_RADEON_READ8((u8 *)RADEON_ADDR( reg ))
-static inline u8 _RADEON_READ8(u8 *addr)
-{
-	mb();
-	return *(volatile u8 *)addr;
-}
-#define RADEON_WRITE8(reg,val)						\
-do {									\
-	wmb();								\
-	RADEON_DEREF8( reg ) = val;					\
-} while (0)
-#else
-#define RADEON_READ8(reg)	RADEON_DEREF8( reg )
-#define RADEON_WRITE8(reg, val)	do { RADEON_DEREF8( reg ) = val; } while (0)
-#endif
+#define RADEON_READ8(reg)	readb( (volatile u8 *) RADEON_ADDR(reg) )
+#define RADEON_WRITE8(reg,val)	writeb( (val), (volatile u8 *) RADEON_ADDR(reg) )
 
 #define RADEON_WRITE_PLL( addr, val )					\
 do {									\
@@ -664,6 +645,15 @@
 				goto __ring_space_done;			\
 			udelay( 1 );					\
 		}							\
+		DRM_ERROR( "ring space check from memory failed, reading register...\n" );	\
+		/* If ring space check fails from RAM, try reading the	\
+		   register directly */					\
+		ring->space = 4 * ( RADEON_READ( RADEON_CP_RB_RPTR ) - ring->tail );	\
+		if ( ring->space <= 0 )					\
+			ring->space += ring->size;			\
+		if ( ring->space >= ring->high_mark )			\
+			goto __ring_space_done;				\
+									\
 		DRM_ERROR( "ring space check failed!\n" );		\
 		return -EBUSY;						\
 	}								\
@@ -701,7 +691,11 @@
  * Ring control
  */
 
+#if defined(__powerpc__)
+#define radeon_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
+#else
 #define radeon_flush_write_combine()	mb()
+#endif
 
 
 #define RADEON_VERBOSE	0
@@ -737,8 +731,9 @@
 		dev_priv->ring.tail = write;				\
 } while (0)
 
-#define COMMIT_RING() do {					    \
-	RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );		    \
+#define COMMIT_RING() do {						\
+	radeon_flush_write_combine();					\
+	RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail );		\
 } while (0)
 
 #define OUT_RING( x ) do {						\
diff -Nru a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
--- a/drivers/char/drm/radeon_state.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/drm/radeon_state.c	Fri Jul  5 16:42:59 2002
@@ -30,8 +30,9 @@
 #define __NO_VERSION__
 #include "radeon.h"
 #include "drmP.h"
-#include "radeon_drv.h"
 #include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
 #include <linux/delay.h>
 
 
@@ -47,12 +48,10 @@
 	DRM_DEBUG( "   box:  x1=%d y1=%d  x2=%d y2=%d\n",
 		   box->x1, box->y1, box->x2, box->y2 );
 
-	BEGIN_RING( 4 );
-	OUT_RING( CP_PACKET0( RADEON_RE_TOP_LEFT, 0 ) );
+	BEGIN_RING( 3 );
+	OUT_RING( CP_PACKET3( RADEON_CNTL_SET_SCISSORS, 1 ));
 	OUT_RING( (box->y1 << 16) | box->x1 );
-	OUT_RING( CP_PACKET0( RADEON_RE_WIDTH_HEIGHT, 0 ) );
-/*	OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );*/
-	OUT_RING( (box->y2 << 16) | box->x2 );
+	OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );
 	ADVANCE_RING();
 }
 
@@ -669,7 +668,6 @@
 	int i = 0;
 	RING_LOCALS;
 
-
 	DRM_DEBUG("%s: hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
 		  __FUNCTION__,
 		  prim->prim,
@@ -684,7 +682,6 @@
 		return;
 	}
 
-
 	do {
 		/* Emit the next cliprect */
 		if ( i < nbox ) {
@@ -906,6 +903,16 @@
 
 	ADVANCE_RING();
 
+#ifdef __BIG_ENDIAN
+	/* The Mesa texture functions provide the data in little endian as the
+	 * chip wants it, but we need to compensate for the fact that the CP
+	 * ring gets byte-swapped
+	 */
+	BEGIN_RING( 2 );
+	OUT_RING_REG( RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT );
+	ADVANCE_RING();
+#endif
+
 	/* Make a copy of the parameters in case we have to update them
 	 * for a multi-pass texture blit.
 	 */
@@ -1081,6 +1088,7 @@
 
 	dev_priv->page_flipping = 1;
 	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
 
 	return 0;
 }
@@ -1095,6 +1103,7 @@
 
 	dev_priv->page_flipping = 0;
 	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
 
 	return 0;
 }
@@ -1585,14 +1594,14 @@
 	drm_radeon_cmd_header_t header,
 	drm_radeon_cmd_buffer_t *cmdbuf )
 {
-	int sz = packet[(int)header.packet.packet_id].len;
-	int reg = packet[(int)header.packet.packet_id].start;
+	int id = (int)header.packet.packet_id;
+	int sz = packet[id].len;
+	int reg = packet[id].start;
 	int *data = (int *)cmdbuf->buf;
 	RING_LOCALS;
    
 	if (sz * sizeof(int) > cmdbuf->bufsz) 
 		return -EINVAL;
-
 
 	BEGIN_RING(sz+1);
 	OUT_RING( CP_PACKET0( reg, (sz-1) ) );
diff -Nru a/drivers/char/drm/sis_drm.h b/drivers/char/drm/sis_drm.h
--- a/drivers/char/drm/sis_drm.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/drm/sis_drm.h	Fri Jul  5 16:43:00 2002
@@ -2,6 +2,16 @@
 #ifndef _sis_drm_public_h_
 #define _sis_drm_public_h_
 
+/* SiS specific ioctls */
+#define SIS_IOCTL_FB_ALLOC		DRM_IOWR(0x44, drm_sis_mem_t)
+#define SIS_IOCTL_FB_FREE		DRM_IOW( 0x45, drm_sis_mem_t)
+#define SIS_IOCTL_AGP_INIT		DRM_IOWR(0x53, drm_sis_agp_t)
+#define SIS_IOCTL_AGP_ALLOC		DRM_IOWR(0x54, drm_sis_mem_t)
+#define SIS_IOCTL_AGP_FREE		DRM_IOW( 0x55, drm_sis_mem_t)
+#define SIS_IOCTL_FLIP			DRM_IOW( 0x48, drm_sis_flip_t)
+#define SIS_IOCTL_FLIP_INIT		DRM_IO(  0x49)
+#define SIS_IOCTL_FLIP_FINAL		DRM_IO(  0x50)
+
 typedef struct {
   int context;
   unsigned int offset;
diff -Nru a/drivers/char/pty.c b/drivers/char/pty.c
--- a/drivers/char/pty.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/char/pty.c	Fri Jul  5 16:42:59 2002
@@ -25,8 +25,6 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
-
-#define BUILDING_PTY_C 1
 #include <linux/devpts_fs.h>
 
 struct pty_struct {
diff -Nru a/drivers/char/qtronixmap.c_shipped b/drivers/char/qtronixmap.c_shipped
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/qtronixmap.c_shipped	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,265 @@
+
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf200,	0xf060,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,
+	0xf037,	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf200,	0xf07f,
+	0xf009,	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,
+	0xfb69,	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf207,	0xfb61,
+	0xfb73,	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,
+	0xf03b,	0xf027,	0xf060,	0xf201,	0xf700,	0xf200,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf020,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf602,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf01b,	0xf200,
+	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,	0xf107,
+	0xf108,	0xf109,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+	0xf200,	0xf07e,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,
+	0xf026,	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf200,	0xf07f,
+	0xf009,	0xfb51,	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,
+	0xfb49,	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf207,	0xfb41,
+	0xfb53,	0xfb44,	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,
+	0xf03a,	0xf022,	0xf07e,	0xf201,	0xf700,	0xf200,	0xfb5a,	0xfb58,
+	0xfb43,	0xfb56,	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf020,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf20b,	0xf20a,	0xf200,
+	0xf200,	0xf602,	0xf213,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf01b,	0xf200,
+	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,	0xf10f,	0xf110,	0xf111,
+	0xf112,	0xf113,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
+	0xf07b,	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,
+	0xfb69,	0xfb6f,	0xfb70,	0xf200,	0xf200,	0xf200,	0xf207,	0xfb61,
+	0xfb73,	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,
+	0xf200,	0xf200,	0xf200,	0xf201,	0xf700,	0xf200,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xfb62,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf200,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf602,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf200,	0xf200,
+	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,	0xf511,	0xf512,	0xf513,
+	0xf514,	0xf515,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,
+	0xf01f,	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf008,
+	0xf200,	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,
+	0xf009,	0xf00f,	0xf010,	0xf01b,	0xf01d,	0xf01c,	0xf207,	0xf001,
+	0xf013,	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,
+	0xf007,	0xf000,	0xf200,	0xf201,	0xf700,	0xf200,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf002,	0xf00e,	0xf20e,	0xf07f,	0xf200,	0xf200,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf000,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf602,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf200,	0xf200,
+	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,	0xf107,
+	0xf108,	0xf109,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,
+	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf200,	0xf207,	0xf001,
+	0xf013,	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,
+	0xf200,	0xf200,	0xf200,	0xf201,	0xf700,	0xf200,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf200,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf602,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+	0xf200,	0xf81b,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,
+	0xf837,	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf200,	0xf87f,
+	0xf809,	0xf871,	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,
+	0xf869,	0xf86f,	0xf870,	0xf85b,	0xf85d,	0xf85c,	0xf207,	0xf861,
+	0xf873,	0xf864,	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf83b,
+	0xf827,	0xf860,	0xf200,	0xf80d,	0xf700,	0xf200,	0xf87a,	0xf878,
+	0xf863,	0xf876,	0xf862,	0xf82c,	0xf82e,	0xf82f,	0xf200,	0xf200,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf820,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf210,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf211,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf200,	0xf200,
+	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,	0xf507,
+	0xf508,	0xf509,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf811,	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,
+	0xf809,	0xf80f,	0xf810,	0xf200,	0xf200,	0xf200,	0xf207,	0xf801,
+	0xf813,	0xf804,	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,
+	0xf200,	0xf200,	0xf200,	0xf201,	0xf700,	0xf200,	0xf81a,	0xf818,
+	0xf803,	0xf816,	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf700,	0xf702,	0xf200,	0xf703,	0xf200,	0xf703,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf115,	0xf07f,	0xf200,	0xf200,	0xf601,
+	0xf200,	0xf200,	0xf200,	0xf603,	0xf600,	0xf118,	0xf119,	0xf200,
+	0xf200,	0xf602,	0xf208,	0xf02d,	0xf02b,	0xf30c,	0xf02e,	0xf30d,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf117,	0xf600,	0xf200,	0xf200,	0xf200,
+	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,	0xf507,
+	0xf508,	0xf509,	0xf200,	0xf200,	0xf200,	0xf200,	0xf11d,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', 'À'},	{'`', 'a', 'à'},
+	{'\'', 'A', 'Á'},	{'\'', 'a', 'á'},
+	{'^', 'A', 'Â'},	{'^', 'a', 'â'},
+	{'~', 'A', 'Ã'},	{'~', 'a', 'ã'},
+	{'"', 'A', 'Ä'},	{'"', 'a', 'ä'},
+	{'O', 'A', 'Å'},	{'o', 'a', 'å'},
+	{'0', 'A', 'Å'},	{'0', 'a', 'å'},
+	{'A', 'A', 'Å'},	{'a', 'a', 'å'},
+	{'A', 'E', 'Æ'},	{'a', 'e', 'æ'},
+	{',', 'C', 'Ç'},	{',', 'c', 'ç'},
+	{'`', 'E', 'È'},	{'`', 'e', 'è'},
+	{'\'', 'E', 'É'},	{'\'', 'e', 'é'},
+	{'^', 'E', 'Ê'},	{'^', 'e', 'ê'},
+	{'"', 'E', 'Ë'},	{'"', 'e', 'ë'},
+	{'`', 'I', 'Ì'},	{'`', 'i', 'ì'},
+	{'\'', 'I', 'Í'},	{'\'', 'i', 'í'},
+	{'^', 'I', 'Î'},	{'^', 'i', 'î'},
+	{'"', 'I', 'Ï'},	{'"', 'i', 'ï'},
+	{'-', 'D', 'Ð'},	{'-', 'd', 'ð'},
+	{'~', 'N', 'Ñ'},	{'~', 'n', 'ñ'},
+	{'`', 'O', 'Ò'},	{'`', 'o', 'ò'},
+	{'\'', 'O', 'Ó'},	{'\'', 'o', 'ó'},
+	{'^', 'O', 'Ô'},	{'^', 'o', 'ô'},
+	{'~', 'O', 'Õ'},	{'~', 'o', 'õ'},
+	{'"', 'O', 'Ö'},	{'"', 'o', 'ö'},
+	{'/', 'O', 'Ø'},	{'/', 'o', 'ø'},
+	{'`', 'U', 'Ù'},	{'`', 'u', 'ù'},
+	{'\'', 'U', 'Ú'},	{'\'', 'u', 'ú'},
+	{'^', 'U', 'Û'},	{'^', 'u', 'û'},
+	{'"', 'U', 'Ü'},	{'"', 'u', 'ü'},
+	{'\'', 'Y', 'Ý'},	{'\'', 'y', 'ý'},
+	{'T', 'H', 'Þ'},	{'t', 'h', 'þ'},
+	{'s', 's', 'ß'},	{'"', 'y', 'ÿ'},
+	{'s', 'z', 'ß'},	{'i', 'j', 'ÿ'},
+};
+
+unsigned int accent_table_size = 68;
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/char/tty_io.c	Fri Jul  5 16:43:00 2002
@@ -1336,7 +1336,7 @@
 	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		minor -= driver->minor_start;
-		devpts_pty_new(driver->other->name_base + minor, mk_kdev(driver->other->major, minor + driver->other->minor_start));
+		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
 		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/ide/ide-cd.c	Fri Jul  5 16:42:59 2002
@@ -1937,9 +1937,9 @@
 /* Try to read the entire TOC for the disk into our internal buffer. */
 static int cdrom_read_toc(struct ata_device *drive, struct request_sense *sense)
 {
-	int minor, stat, ntracks, i;
-	kdev_t dev;
+	int stat, ntracks, i;
 	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *cdi = &info->devinfo;
 	struct atapi_toc *toc = info->toc;
 	struct {
 		struct atapi_toc_header hdr;
@@ -2071,10 +2071,8 @@
 	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
 	/* Now try to get the total cdrom capacity. */
-	minor = (drive->select.b.unit) << PARTN_BITS;
-	dev = mk_kdev(drive->channel->major, minor);
 	/* FIXME: This is making worng assumptions about register layout. */
-	stat = cdrom_get_last_written(dev, (unsigned long *) &toc->capacity);
+	stat = cdrom_get_last_written(cdi, (unsigned long *) &toc->capacity);
 	if (stat)
 		stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat)
diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c
--- a/drivers/ide/probe.c	Fri Jul  5 16:42:44 2002
+++ b/drivers/ide/probe.c	Fri Jul  5 16:42:44 2002
@@ -1143,6 +1143,7 @@
 	if (!gd)
 		goto err_kmalloc_gd;
 
+	memset(gd, 0, sizeof(struct gendisk));
 	gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
@@ -1171,18 +1172,6 @@
 	gd->nr_real	= MAX_DRIVES;		/* current num real drives */
 	gd->next	= NULL;			/* linked list of major devs */
 	gd->fops        = ide_fops;             /* file operations */
-
-	gd->de_arr	= kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
-	if (gd->de_arr)
-		memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
-	else
-	    goto err_kmalloc_gd_de_arr;
-
-	gd->flags	= kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
-	if (gd->flags)
-		memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
-	else
-	    goto err_kmalloc_gd_flags;
 
 	ch->gd = gd;
 	add_gendisk(gd);
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/ieee1394/ieee1394_core.c	Fri Jul  5 16:42:59 2002
@@ -740,8 +740,7 @@
         host->ops->devctl(host, CANCEL_REQUESTS, 0);
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
-        list_splice(&host->pending_packets, &llist);
-        INIT_LIST_HEAD(&host->pending_packets);
+        list_splice_init(&host->pending_packets, &llist);
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         list_for_each(lh, &llist) {
diff -Nru a/drivers/input/Config.help b/drivers/input/Config.help
--- a/drivers/input/Config.help	Fri Jul  5 16:42:59 2002
+++ b/drivers/input/Config.help	Fri Jul  5 16:42:59 2002
@@ -64,6 +64,18 @@
   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_TSDEV
+  Say Y here if you have an application that only can understand the
+  Compaq touchscreen protocol for absolute pointer data. This is
+  useful namely for embedded configurations.
+
+  If unsure, say N.
+
+  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 tsdev.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 input device events be accessible
   under char device 13:64+ - /dev/input/eventX in a generic way.
@@ -71,4 +83,18 @@
   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>.
+
+CONFIG_INPUT_EVBUG
+  Say Y here if you have a problem with the input subsystem and
+  want all events (keypresses, mouse movements), to be output to
+  the system log. While this is useful for debugging, it's also
+  a security threat - your keypresses include your passwords, of
+  course.
+
+  If unsure, say N.
+
+  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>.
diff -Nru a/drivers/input/Config.in b/drivers/input/Config.in
--- a/drivers/input/Config.in	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/Config.in	Fri Jul  5 16:43:00 2002
@@ -6,20 +6,34 @@
 comment 'Input device support'
 
 tristate 'Input core support' CONFIG_INPUT
+
+comment 'Userland interfaces'
 dep_tristate '  Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
 dep_tristate '  Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+dep_mbool '    Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $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 interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate '  Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT
+if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then
+   int '   Horizontal screen resolution' CONFIG_INPUT_TSDEV_SCREEN_X 240
+   int '   Vertical screen resolution' CONFIG_INPUT_TSDEV_SCREEN_Y 320 
+fi
 dep_tristate '  Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate '  Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
 
+comment 'Input I/O drivers'
 source drivers/input/gameport/Config.in
 source drivers/input/serio/Config.in
 
+comment 'Input Device Drivers'
 if [ "$CONFIG_INPUT" != "n" ]; then
+   source drivers/input/keyboard/Config.in
+   source drivers/input/mouse/Config.in
    source drivers/input/joystick/Config.in
+   source drivers/input/touchscreen/Config.in
 fi
 
 endmenu
diff -Nru a/drivers/input/Makefile b/drivers/input/Makefile
--- a/drivers/input/Makefile	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/Makefile	Fri Jul  5 16:43:00 2002
@@ -13,8 +13,14 @@
 obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
 obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
+obj-$(CONFIG_INPUT_TSDEV)	+= tsdev.o
+obj-$(CONFIG_INPUT_POWER)	+= power.o
+obj-$(CONFIG_INPUT_EVBUG)	+= evbug.o
 
+obj-$(CONFIG_INPUT_KEYBOARD)	+= keyboard/
+obj-$(CONFIG_INPUT_MOUSE)	+= mouse/
 obj-$(CONFIG_INPUT_JOYSTICK)	+= joystick/
+obj-$(CONFIG_INPUT_TOUCHSCREEN)	+= touchscreen/
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/evbug.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,99 @@
+/*
+ * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  Input driver event debug module - dumps all events into syslog
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input driver event debug module"); 
+MODULE_LICENSE("GPL");
+
+static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+	printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
+}
+
+static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+{
+	struct input_handle *handle;
+
+	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+		return NULL;
+	memset(handle, 0, sizeof(struct input_handle));
+
+	handle->dev = dev;
+	handle->handler = handler;
+
+	input_open_device(handle);
+
+	printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
+
+	return handle;
+}
+
+static void evbug_disconnect(struct input_handle *handle)
+{
+	printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
+	
+	input_close_device(handle);
+
+	kfree(handle);
+}
+
+static struct input_device_id evbug_ids[] = {
+	{ driver_info: 1 },	/* Matches all devices */
+	{ },			/* Terminating zero entry */
+};
+
+MODULE_DEVICE_TABLE(input, evbug_ids);
+	
+static struct input_handler evbug_handler = {
+	event:		evbug_event,
+	connect:	evbug_connect,
+	disconnect:	evbug_disconnect,
+	name:		"evbug",
+	id_table:	evbug_ids,
+};
+
+int __init evbug_init(void)
+{
+	input_register_handler(&evbug_handler);
+	return 0;
+}
+
+void __exit evbug_exit(void)
+{
+	input_unregister_handler(&evbug_handler);
+}
+
+module_init(evbug_init);
+module_exit(evbug_exit);
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/evdev.c	Fri Jul  5 16:43:00 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: evdev.c,v 1.42 2002/01/02 11:59:56 vojtech Exp $
+ * $Id: evdev.c,v 1.48 2002/05/26 14:28:26 jdeneux Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
@@ -40,7 +40,6 @@
 struct evdev {
 	int exist;
 	int open;
-	int open_for_write;
 	int minor;
 	char name[16];
 	struct input_handle handle;
@@ -91,7 +90,9 @@
 
 static int evdev_flush(struct file * file)
 {
-	return input_flush_device(&((struct evdev_list*)file->private_data)->evdev->handle, file);
+	struct evdev_list *list = (struct evdev_list*)file->private_data;
+	if (!list->evdev->exist) return -ENODEV;
+	return input_flush_device(&list->evdev->handle, file);
 }
 
 static int evdev_release(struct inode * inode, struct file * file)
@@ -158,6 +159,8 @@
 	struct input_event event;
 	int retval = 0;
 
+	if (!list->evdev->exist) return -ENODEV;
+
 	while (retval < count) {
 
 		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -232,6 +235,8 @@
 	struct input_dev *dev = evdev->handle.dev;
 	int retval, t, u;
 
+	if (!evdev->exist) return -ENODEV;
+
 	switch (cmd) {
 
 		case EVIOCGVERSION:
@@ -284,11 +289,11 @@
 				int err;
 
 				if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) {
-					return -EINVAL;
+					return -EFAULT;
 				}
 				err = dev->upload_effect(dev, &effect);
 				if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) {
-					return -EINVAL;
+					return -EFAULT;
 				}
 				return err;
 			}
@@ -301,7 +306,8 @@
 			else return -ENOSYS;
 
 		case EVIOCGEFFECTS:
-			put_user(dev->ff_effects_max, (int*) arg);
+			if ((retval = put_user(dev->ff_effects_max, (int*) arg)))
+				return retval;
 			return 0;
 
 		default:
diff -Nru a/drivers/input/gameport/Config.help b/drivers/input/gameport/Config.help
--- a/drivers/input/gameport/Config.help	Fri Jul  5 16:42:59 2002
+++ b/drivers/input/gameport/Config.help	Fri Jul  5 16:42:59 2002
@@ -43,13 +43,13 @@
   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.
+CONFIG_GAMEPORT_VORTEX
+  Say Y here if you have an Aureal Vortex 1 or 2  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
+  The module will be called vortex.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_GAMEPORT_CS461X
diff -Nru a/drivers/input/gameport/Config.in b/drivers/input/gameport/Config.in
--- a/drivers/input/gameport/Config.in	Fri Jul  5 16:42:48 2002
+++ b/drivers/input/gameport/Config.in	Fri Jul  5 16:42:48 2002
@@ -14,6 +14,6 @@
 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 '  Aureal Vortex, Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $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
--- a/drivers/input/gameport/Makefile	Fri Jul  5 16:42:48 2002
+++ b/drivers/input/gameport/Makefile	Fri Jul  5 16:42:48 2002
@@ -11,9 +11,10 @@
 obj-$(CONFIG_GAMEPORT)		+= gameport.o
 obj-$(CONFIG_GAMEPORT_CS461X)	+= cs461x.o
 obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
+obj-$(CONFIG_GAMEPORT_FM801)	+= fm801-gp.o
 obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
 obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
-obj-$(CONFIG_GAMEPORT_PCIGAME)	+= pcigame.o
+obj-$(CONFIG_GAMEPORT_VORTEX)	+= vortex.o
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/fm801-gp.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,162 @@
+/*
+ *  FM801 gameport driver for Linux
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#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_FORTEMEDIA	0x1319
+#define PCI_DEVICE_ID_FM801_GP	0x0802
+
+#define HAVE_COOKED
+
+struct fm801_gp {
+	struct gameport gameport;
+	struct resource *res_port;
+	char phys[32];
+	char name[32];
+};
+
+#ifdef HAVE_COOKED
+static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	unsigned short w;
+
+	w = inw(gameport->io + 2);
+	*buttons = (~w >> 14) & 0x03;
+	axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
+	w = inw(gameport->io + 4);
+	axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
+	w = inw(gameport->io + 6);
+	*buttons |= ((~w >> 14) & 0x03) << 2;
+	axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
+	w = inw(gameport->io + 8);
+	axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
+	outw(0xff, gameport->io); /* reset */
+
+        return 0;
+}
+#endif
+
+static int fm801_gp_open(struct gameport *gameport, int mode)
+{
+	switch (mode) {
+#ifdef HAVE_COOKED
+	case GAMEPORT_MODE_COOKED:
+		return 0;
+#endif
+	case GAMEPORT_MODE_RAW:
+		return 0;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+	struct fm801_gp *gp;
+
+	if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
+		printk("cannot malloc for fm801-gp\n");
+		return -1;
+	}
+	memset(gp, 0, sizeof(*gp));
+
+	gp->gameport.open = fm801_gp_open;
+#ifdef HAVE_COOKED
+	gp->gameport.cooked_read = fm801_gp_cooked_read;
+#endif
+
+	pci_enable_device(pci);
+	gp->gameport.io = pci_resource_start(pci, 0);
+	if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
+		kfree(gp);
+		printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
+		return -1;
+	}
+
+	gp->gameport.phys = gp->phys;
+	gp->gameport.name = gp->name;
+	gp->gameport.idbus = BUS_PCI;
+	gp->gameport.idvendor = pci->vendor;
+	gp->gameport.idproduct = pci->device;
+
+	pci_set_drvdata(pci, gp);
+
+	outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ 
+
+	gameport_register_port(&gp->gameport);
+
+	printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
+		pci->name, pci->slot_name, gp->gameport.speed);
+
+	return 0;
+}
+
+static void __devexit fm801_gp_remove(struct pci_dev *pci)
+{
+	struct fm801_gp *gp = pci_get_drvdata(pci);
+	if (gp) {
+		gameport_unregister_port(&gp->gameport);
+		release_resource(gp->res_port);
+		kfree(gp);
+	}
+}
+
+static struct pci_device_id fm801_gp_id_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0  },
+	{ 0 }
+};
+
+static struct pci_driver fm801_gp_driver = {
+	name:		"FM801 GP",
+	id_table:	fm801_gp_id_table,
+	probe:		fm801_gp_probe,
+	remove:		fm801_gp_remove,
+};
+
+int __init fm801_gp_init(void)
+{
+	return pci_module_init(&fm801_gp_driver);
+}
+
+void __exit fm801_gp_exit(void)
+{
+	pci_unregister_driver(&fm801_gp_driver);
+}
+
+module_init(fm801_gp_init);
+module_exit(fm801_gp_exit);
+
+MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
--- a/drivers/input/gameport/gameport.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/gameport/gameport.c	Fri Jul  5 16:43:00 2002
@@ -54,16 +54,36 @@
 static struct gameport *gameport_list;
 static struct gameport_dev *gameport_dev;
 
+
+#ifdef __i386__
+
+#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193180/HZ:0))
+#define GET_TIME(x)     do { x = get_time_pit(); } while (0)
+
+static unsigned int get_time_pit(void)
+{
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+	unsigned int count;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x00, 0x43);
+	count = inb_p(0x40);
+	count |= inb_p(0x40) << 8;
+	spin_unlock_irqrestore(&i8253_lock, flags);
+
+	return count;
+}
+
+#endif
+
 /*
  * 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))
+#ifdef __i386__
 
 	unsigned int i, t, t1, t2, t3, tx;
 	unsigned long flags;
diff -Nru a/drivers/input/gameport/pcigame.c b/drivers/input/gameport/pcigame.c
--- a/drivers/input/gameport/pcigame.c	Fri Jul  5 16:42:59 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:		__devexit_p(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/gameport/vortex.c b/drivers/input/gameport/vortex.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/gameport/vortex.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,185 @@
+/*
+ * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Raymond Ingles
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, 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>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
+MODULE_LICENSE("GPL");
+
+#define VORTEX_GCR		0x0c	/* Gameport control register */
+#define VORTEX_LEG		0x08	/* Legacy port location */
+#define VORTEX_AXD		0x10	/* Axes start */
+#define VORTEX_DATA_WAIT	20	/* 20 ms */
+
+struct vortex {
+	struct gameport gameport;
+	struct pci_dev *dev;
+        unsigned char *base;
+        unsigned char *io;
+	char phys[32];
+};
+
+static unsigned char vortex_read(struct gameport *gameport)
+{
+	struct vortex *vortex = gameport->driver;
+	return readb(vortex->io + VORTEX_LEG);
+}
+
+static void vortex_trigger(struct gameport *gameport)
+{
+	struct vortex *vortex = gameport->driver;
+	writeb(0xff, vortex->io + VORTEX_LEG);
+}
+
+static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+	struct vortex *vortex = gameport->driver;
+	int i;
+
+	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
+
+	for (i = 0; i < 4; i++) {
+		axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
+		if (axes[i] == 0x1fff) axes[i] = -1;
+	}
+        
+        return 0;
+}
+
+static int vortex_open(struct gameport *gameport, int mode)
+{
+	struct vortex *vortex = gameport->driver;
+
+	switch (mode) {
+		case GAMEPORT_MODE_COOKED:
+			writeb(0x40, vortex->io + VORTEX_GCR);
+			wait_ms(VORTEX_DATA_WAIT);
+			return 0;
+		case GAMEPORT_MODE_RAW:
+			writeb(0x00, vortex->io + VORTEX_GCR);
+			return 0;
+		default:
+			return -1;
+	}
+
+	return 0;
+}
+
+static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct vortex *vortex;
+	int i;
+
+	if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
+		return -1;
+        memset(vortex, 0, sizeof(struct vortex));
+
+	vortex->dev = dev;
+	sprintf(vortex->phys, "pci%s/gameport0", dev->slot_name);
+
+	pci_set_drvdata(dev, vortex);
+
+	vortex->gameport.driver = vortex;
+	vortex->gameport.fuzz = 64;
+	
+	vortex->gameport.read = vortex_read;
+	vortex->gameport.trigger = vortex_trigger;
+	vortex->gameport.cooked_read = vortex_cooked_read;
+	vortex->gameport.open = vortex_open;
+
+	vortex->gameport.name = dev->name;
+	vortex->gameport.phys = vortex->phys;
+	vortex->gameport.idbus = BUS_PCI;
+	vortex->gameport.idvendor = dev->vendor;
+	vortex->gameport.idproduct = dev->device;
+
+	for (i = 0; i < 6; i++)
+		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
+			break;
+
+	pci_enable_device(dev);
+
+	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
+				pci_resource_len(vortex->dev, i));
+	vortex->io = vortex->base + id->driver_data;
+
+	gameport_register_port(&vortex->gameport);
+	
+	printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
+		dev->name, dev->slot_name, vortex->gameport.speed);
+
+	return 0;
+}
+
+static void __devexit vortex_remove(struct pci_dev *dev)
+{
+	struct vortex *vortex = pci_get_drvdata(dev);
+	gameport_unregister_port(&vortex->gameport);
+	iounmap(vortex->base);
+	kfree(vortex);
+}
+
+static struct pci_device_id vortex_id_table[] __devinitdata =
+{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
+ { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
+ { 0 }};
+
+static struct pci_driver vortex_driver = {
+	name:		"vortex",
+	id_table:	vortex_id_table,
+	probe:		vortex_probe,
+	remove:		vortex_remove,
+};
+
+int __init vortex_init(void)
+{
+	return pci_module_init(&vortex_driver);
+}
+
+void __exit vortex_exit(void)
+{
+	pci_unregister_driver(&vortex_driver);
+}
+
+module_init(vortex_init);
+module_exit(vortex_exit);
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/input.c	Fri Jul  5 16:43:00 2002
@@ -61,8 +61,6 @@
 static struct input_handler *input_handler;
 static struct input_handler *input_table[8];
 static devfs_handle_t input_devfs_handle;
-static int input_number;
-static long input_devices[NBITS(INPUT_DEVICES)];
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_bus_input_dir;
@@ -454,17 +452,8 @@
  * Add the device.
  */
 
-	if (input_number >= INPUT_DEVICES) {
-		printk(KERN_WARNING "input: ran out of input device numbers!\n");
-		dev->number = input_number;
-	} else {
-		dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
-		set_bit(dev->number, input_devices);
-	}
-		
 	dev->next = input_dev;	
 	input_dev = dev;
-	input_number++;
 
 /*
  * Notify handlers.
@@ -493,7 +482,6 @@
 	input_devices_state++;
 	wake_up(&input_devices_poll_wait);
 #endif
-
 }
 
 void input_unregister_device(struct input_dev *dev)
@@ -509,7 +497,6 @@
 	if (dev->pm_dev)
 		pm_unregister(dev->pm_dev);
 
-
 /*
  * Kill any pending repeat timers.
  */
@@ -540,7 +527,6 @@
  */
 	input_find_and_remove(struct input_dev, input_dev, dev, next);
 
-	input_number--;
 /*
  * Notify /proc.
  */
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/joydev.c	Fri Jul  5 16:43:00 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: joydev.c,v 1.38 2001/12/27 10:37:41 vojtech Exp $
+ * $Id: joydev.c,v 1.43 2002/04/09 23:59:01 jsimmons Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik 
  *  Copyright (c) 1999 Colin Van Dyke 
@@ -49,7 +49,7 @@
 MODULE_LICENSE("GPL");
 
 #define JOYDEV_MINOR_BASE	0
-#define JOYDEV_MINORS		32
+#define JOYDEV_MINORS		16	
 #define JOYDEV_BUFFER_SIZE	64
 
 #define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
@@ -254,6 +254,10 @@
 
 		while (list->head == list->tail) {
 
+			if (!joydev->exist) {
+				retval = -ENODEV;
+				break;
+			}
 			if (file->f_flags & O_NONBLOCK) {
 				retval = -EAGAIN;
 				break;
@@ -324,6 +328,8 @@
 	struct joydev *joydev = list->joydev;
 	struct input_dev *dev = joydev->handle.dev;
 	int i;
+
+	if (!joydev->exist) return -ENODEV;
 
 	switch (cmd) {
 
diff -Nru a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
--- a/drivers/input/joystick/Config.help	Fri Jul  5 16:42:56 2002
+++ b/drivers/input/joystick/Config.help	Fri Jul  5 16:42:56 2002
@@ -67,6 +67,15 @@
   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_GUILLEMOT
+  Say Y here if you have a Guillemot joystick using a digital
+  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 guillemot.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.
@@ -156,6 +165,15 @@
   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_TWIDDLER
+  Say Y here if you have a Handykey Twiddler connected to your
+  computer's serial port and want to use it as 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 twidjoy.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_JOYSTICK_DB9
diff -Nru a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
--- a/drivers/input/joystick/Config.in	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/joystick/Config.in	Fri Jul  5 16:43:00 2002
@@ -10,6 +10,7 @@
 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 '  Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $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
@@ -21,6 +22,7 @@
 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 '  Twiddler as as joystick' CONFIG_JOYSTICK_TWIDDLER $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
diff -Nru a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
--- a/drivers/input/joystick/Makefile	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/joystick/Makefile	Fri Jul  5 16:43:00 2002
@@ -31,8 +31,9 @@
 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_GUILLEMOT)	+= guillemot.o
 obj-$(CONFIG_JOYSTICK_INTERACT)		+= interact.o
+obj-$(CONFIG_JOYSTICK_JOYDUMP)		+= joydump.o
 obj-$(CONFIG_JOYSTICK_MAGELLAN)		+= magellan.o
 obj-$(CONFIG_JOYSTICK_SIDEWINDER)	+= sidewinder.o
 obj-$(CONFIG_JOYSTICK_SPACEBALL)	+= spaceball.o
@@ -40,7 +41,10 @@
 obj-$(CONFIG_JOYSTICK_STINGER)		+= stinger.o
 obj-$(CONFIG_JOYSTICK_TMDC)		+= tmdc.o
 obj-$(CONFIG_JOYSTICK_TURBOGRAFX)	+= turbografx.o
+obj-$(CONFIG_JOYSTICK_TWIDJOY)		+= twidjoy.o
 obj-$(CONFIG_JOYSTICK_WARRIOR)		+= warrior.o
+
+obj-$(CONFIG_JOYSTICK_IFORCE)		+= iforce/
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
--- a/drivers/input/joystick/adi.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/input/joystick/adi.c	Fri Jul  5 16:42:59 2002
@@ -426,10 +426,10 @@
 	adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
-		set_bit(adi->abs[i], &adi->dev.absbit);
+		set_bit(adi->abs[i], adi->dev.absbit);
 
 	for (i = 0; i < adi->buttons; i++)
-		set_bit(adi->key[i], &adi->dev.keybit);
+		set_bit(adi->key[i], adi->dev.keybit);
 }
 
 static void adi_init_center(struct adi *adi)
diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- a/drivers/input/joystick/db9.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/input/joystick/db9.c	Fri Jul  5 16:42:59 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $
+ * $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
@@ -199,7 +199,7 @@
 			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_START, ~data & DB9_FIRE2);
 
 			parport_write_control(port, DB9_NOSELECT); /* 2 */
 			udelay(DB9_GENESIS6_DELAY);
@@ -209,10 +209,10 @@
 			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);
+			input_report_key(dev, BTN_X,    ~data & DB9_LEFT);
+			input_report_key(dev, BTN_Y,    ~data & DB9_DOWN);
+			input_report_key(dev, BTN_Z,    ~data & DB9_UP);
+			input_report_key(dev, BTN_MODE, ~data & DB9_RIGHT);
 
 			parport_write_control(port, DB9_NORMAL);
 			udelay(DB9_GENESIS6_DELAY);
diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/joystick/gamecon.c	Fri Jul  5 16:43:00 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $
+ * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
@@ -398,8 +398,8 @@
 
 			case GC_PSX_RUMBLE:
 
-				input_report_key(dev + i, BTN_THUMB,  ~data[0] & 0x04);
-				input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+				input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04);
+				input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02);
 
 			case GC_PSX_NEGCON:
 			case GC_PSX_ANALOG:
diff -Nru a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/guillemot.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,285 @@
+/*
+ * $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $
+ *
+ *  Copyright (c) 2001 Vojtech Pavlik
+ */
+
+/*
+ * Guillemot Digital Interface Protocol 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, Simunkova 1594, 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>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Guillemot Digital joystick driver");
+MODULE_LICENSE("GPL");
+
+#define GUILLEMOT_MAX_START	600	/* 600 us */
+#define GUILLEMOT_MAX_STROBE	60	/* 60 us */
+#define GUILLEMOT_MAX_LENGTH	17	/* 17 bytes */
+#define GUILLEMOT_REFRESH_TIME	HZ/50	/* 20 ms */
+
+static short guillemot_abs_pad[] = 
+	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
+
+static short guillemot_btn_pad[] =
+	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
+
+static struct {
+        int x;
+        int y;
+} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+struct guillemot_type {
+	unsigned char id;
+	short *abs;
+	short *btn;
+	int hat;
+	char *name;
+};
+
+struct guillemot {
+	struct gameport *gameport;
+	struct input_dev dev;
+	struct timer_list timer;
+	int used;
+	int bads;
+	int reads;
+	struct guillemot_type *type;
+	unsigned char length;
+	char phys[32];
+};
+
+static struct guillemot_type guillemot_type[] = {
+	{ 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
+	{ 0 }};
+
+/*
+ * guillemot_read_packet() reads Guillemot joystick data.
+ */
+
+static int guillemot_read_packet(struct gameport *gameport, u8 *data)
+{
+	unsigned long flags;
+	unsigned char u, v;
+	unsigned int t, s;
+	int i;
+
+	for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
+		data[i] = 0;
+
+	i = 0;
+	t = gameport_time(gameport, GUILLEMOT_MAX_START);
+	s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
+
+	__save_flags(flags);
+	__cli();
+	gameport_trigger(gameport);
+	v = gameport_read(gameport);
+
+	while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
+		t--;
+		u = v; v = gameport_read(gameport);
+		if (v & ~u & 0x10) {
+			data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
+			i++;
+			t = s;
+		}
+	}
+
+	__restore_flags(flags);
+
+	return i;
+}
+
+/*
+ * guillemot_timer() reads and analyzes Guillemot joystick data.
+ */
+
+static void guillemot_timer(unsigned long private)
+{
+	struct guillemot *guillemot = (struct guillemot *) private;
+	struct input_dev *dev = &guillemot->dev;
+	u8 data[GUILLEMOT_MAX_LENGTH];
+	int i;
+
+	guillemot->reads++;
+
+	if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
+		data[0] != 0x55 || data[16] != 0xaa) {
+		guillemot->bads++;
+	} else {
+
+		for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
+			input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
+
+		if (guillemot->type->hat) {
+			input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
+			input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
+		}
+
+		for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
+			input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
+	}
+
+	mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
+}
+
+/*
+ * guillemot_open() is a callback from the input open routine.
+ */
+
+static int guillemot_open(struct input_dev *dev)
+{
+	struct guillemot *guillemot = dev->private;
+	if (!guillemot->used++)
+		mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);	
+	return 0;
+}
+
+/*
+ * guillemot_close() is a callback from the input close routine.
+ */
+
+static void guillemot_close(struct input_dev *dev)
+{
+	struct guillemot *guillemot = dev->private;
+	if (!--guillemot->used)
+		del_timer(&guillemot->timer);
+}
+
+/*
+ * guillemot_connect() probes for Guillemot joysticks.
+ */
+
+static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+	struct guillemot *guillemot;
+	u8 data[GUILLEMOT_MAX_LENGTH];
+	int i, t;
+
+	if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
+		return;
+	memset(guillemot, 0, sizeof(struct guillemot));
+
+	gameport->private = guillemot;
+
+	guillemot->gameport = gameport;
+	init_timer(&guillemot->timer);
+	guillemot->timer.data = (long) guillemot;
+	guillemot->timer.function = guillemot_timer;
+
+	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+		goto fail1;
+
+	i = guillemot_read_packet(gameport, data);
+
+	if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
+		goto fail2;
+
+	for (i = 0; guillemot_type[i].name; i++)
+		if (guillemot_type[i].id == data[11])
+			break;
+
+	if (!guillemot_type[i].name) {
+		printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
+			gameport->phys, data[12], data[13], data[11], data[14], data[15]);
+		goto fail2;	
+	}
+
+	sprintf(guillemot->phys, "%s/input0", gameport->phys);
+
+	guillemot->type = guillemot_type + i;
+
+	guillemot->dev.private = guillemot;
+	guillemot->dev.open = guillemot_open;
+	guillemot->dev.close = guillemot_close;
+
+	guillemot->dev.name = guillemot_type[i].name;
+	guillemot->dev.phys = guillemot->phys;
+	guillemot->dev.idbus = BUS_GAMEPORT;
+	guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
+	guillemot->dev.idproduct = guillemot_type[i].id;
+	guillemot->dev.idversion = (int)data[14] << 8 | data[15];
+
+	guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+	for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
+		set_bit(t, guillemot->dev.absbit);
+		guillemot->dev.absmin[t] = 0;
+		guillemot->dev.absmax[t] = 255;
+	}
+
+	if (guillemot->type->hat) 
+		for (i = 0; i < 2; i++) {
+			t = ABS_HAT0X + i;
+			set_bit(t, guillemot->dev.absbit);
+			guillemot->dev.absmin[t] = -1;
+			guillemot->dev.absmax[t] = 1;
+		}
+
+	for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
+		set_bit(t, guillemot->dev.keybit);
+
+	input_register_device(&guillemot->dev);
+	printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
+		guillemot->type->name, data[14], data[15], gameport->phys);
+
+	return;
+fail2:	gameport_close(gameport);
+fail1:  kfree(guillemot);
+}
+
+static void guillemot_disconnect(struct gameport *gameport)
+{
+	struct guillemot *guillemot = gameport->private;
+	printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
+	input_unregister_device(&guillemot->dev);
+	gameport_close(gameport);
+	kfree(guillemot);
+}
+
+static struct gameport_dev guillemot_dev = {
+	connect:	guillemot_connect,
+	disconnect:	guillemot_disconnect,
+};
+
+int __init guillemot_init(void)
+{
+	gameport_register_device(&guillemot_dev);
+	return 0;
+}
+
+void __exit guillemot_exit(void)
+{
+	gameport_unregister_device(&guillemot_dev);
+}
+
+module_init(guillemot_init);
+module_exit(guillemot_exit);
diff -Nru a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/Makefile	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,42 @@
+#
+# Makefile for the I-Force driver
+#
+
+# 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
+
+obj-$(CONFIG_JOYSTICK_IFORCE)	+= iforce.o 
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+
+# iforce.o is a multipart module.
+
+IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o
+
+ifneq ($(CONFIG_JOYSTICK_IFORCE_232),)
+	IFORCEOBJS += iforce-serio.o 
+endif
+
+ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),)
+	IFORCEOBJS += iforce-usb.o 
+endif
+
+iforce.o: $(IFORCEOBJS) 
+	$(LD) -i $(IFORCEOBJS) -o $@
diff -Nru a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce-ff.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,543 @@
+/*
+ * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include "iforce.h"
+
+/*
+ * 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, int no_alloc, __s16 level)
+{
+	unsigned char data[3];
+
+	if (!no_alloc) {
+		down(&iforce->mem_mutex);
+		if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
+			iforce->device_memory.start, iforce->device_memory.end, 2L,
+			NULL, NULL)) {
+			up(&iforce->mem_mutex);
+			return -ENOMEM;
+		}
+		up(&iforce->mem_mutex);
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+	data[2] = HIFIX80(level);
+
+	iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data);
+
+	iforce_dump_packet("magnitude: ", 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, int no_alloc,
+	__s16 magnitude, __s16 offset, u16 period, u16 phase)
+{
+	unsigned char data[7];
+
+	period = TIME_SCALE(period);
+
+	if (!no_alloc) {
+		down(&iforce->mem_mutex);
+		if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
+			iforce->device_memory.start, iforce->device_memory.end, 2L,
+			NULL, NULL)) {
+			up(&iforce->mem_mutex);
+			return -ENOMEM;
+		}
+		up(&iforce->mem_mutex);
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = HIFIX80(magnitude);
+	data[3] = HIFIX80(offset);
+	data[4] = HI(phase);
+
+	data[5] = LO(period);
+	data[6] = HI(period);
+
+	iforce_send_packet(iforce, FF_CMD_PERIOD, data);
+
+	return 0;
+}
+
+/*
+ * Uploads the part of an effect setting the envelope of the force
+ */
+
+static int make_envelope_modifier(struct iforce* iforce,
+	struct resource* mod_chunk, int no_alloc,
+	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 (!no_alloc) {
+		down(&iforce->mem_mutex);
+		if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
+			iforce->device_memory.start, iforce->device_memory.end, 2L,
+			NULL, NULL)) {
+			up(&iforce->mem_mutex);
+			return -ENOMEM;
+		}
+		up(&iforce->mem_mutex);
+	}
+
+	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);
+
+	iforce_send_packet(iforce, FF_CMD_ENVELOPE, data);
+
+	return 0;
+}
+
+/*
+ * Component of spring, friction, inertia... effects
+ */
+
+static int make_condition_modifier(struct iforce* iforce,
+	struct resource* mod_chunk, int no_alloc,
+	__u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
+{
+	unsigned char data[10];
+
+	if (!no_alloc) {
+		down(&iforce->mem_mutex);
+		if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
+			iforce->device_memory.start, iforce->device_memory.end, 2L,
+			NULL, NULL)) {
+			up(&iforce->mem_mutex);
+			return -ENOMEM;
+		}
+		up(&iforce->mem_mutex);
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = (100*rk)>>15;	/* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
+	data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */
+
+	center = (500*center)>>15;
+	data[4] = LO(center);
+	data[5] = HI(center);
+
+	db = (1000*db)>>16;
+	data[6] = LO(db);
+	data[7] = HI(db);
+
+	data[8] = (100*rsat)>>16;
+	data[9] = (100*lsat)>>16;
+
+	iforce_send_packet(iforce, FF_CMD_CONDITION, data);
+	iforce_dump_packet("condition", FF_CMD_CONDITION, 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;
+}
+
+/*
+ * Analyse the changes in an effect, and tell if we need to send an condition 
+ * parameter packet
+ */
+static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
+{
+	int id = new->id;
+	struct ff_effect* old = &iforce->core_effects[id].effect;
+	int ret=0;
+	int i;
+
+	if (new->type != FF_SPRING && new->type != FF_FRICTION) {
+		printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
+		return FALSE;
+	}
+
+	for(i=0; i<2; i++) {
+		ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation
+			|| old->u.condition[i].left_saturation != new->u.condition[i].left_saturation
+			|| old->u.condition[i].right_coeff != new->u.condition[i].right_coeff
+			|| old->u.condition[i].left_coeff != new->u.condition[i].left_coeff
+			|| old->u.condition[i].deadband != new->u.condition[i].deadband
+			|| old->u.condition[i].center != new->u.condition[i].center;
+	}
+	return ret;
+}
+
+/*
+ * Analyse the changes in an effect, and tell if we need to send a magnitude
+ * parameter packet
+ */
+static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect)
+{
+	int id = effect->id;
+	struct ff_effect* old = &iforce->core_effects[id].effect;
+
+	if (effect->type != FF_CONSTANT) {
+		printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+		return FALSE;
+	}
+
+	return (old->u.constant.level != effect->u.constant.level);
+}
+
+/*
+ * Analyse the changes in an effect, and tell if we need to send an envelope
+ * parameter packet
+ */
+static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect)
+{
+	int id = effect->id;
+	struct ff_effect* old = &iforce->core_effects[id].effect;
+
+	switch (effect->type) {
+	case FF_CONSTANT:
+		if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length
+		|| old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level
+		|| old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length
+		|| old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level)
+			return TRUE;
+		break;
+
+	case FF_PERIODIC:
+		if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length
+		|| old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level
+		|| old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length
+		|| old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level)
+			return TRUE;
+		break;
+
+	default:
+		printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+	}
+
+	return FALSE;
+}
+
+/*
+ * Analyse the changes in an effect, and tell if we need to send a periodic
+ * parameter effect
+ */
+static int need_period_modifier(struct iforce* iforce, struct ff_effect* new)
+{
+	int id = new->id;
+	struct ff_effect* old = &iforce->core_effects[id].effect;
+
+	if (new->type != FF_PERIODIC) {
+		printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n");
+		return FALSE;
+	}
+
+	return (old->u.periodic.period != new->u.periodic.period
+		|| old->u.periodic.magnitude != new->u.periodic.magnitude
+		|| old->u.periodic.offset != new->u.periodic.offset
+		|| old->u.periodic.phase != new->u.periodic.phase);
+}
+
+/*
+ * Analyse the changes in an effect, and tell if we need to send an effect
+ * packet
+ */
+static int need_core(struct iforce* iforce, struct ff_effect* new)
+{
+	int id = new->id;
+	struct ff_effect* old = &iforce->core_effects[id].effect;
+
+	if (old->direction != new->direction
+		|| old->trigger.button != new->trigger.button
+		|| old->trigger.interval != new->trigger.interval
+		|| old->replay.length != new->replay.length
+		|| old->replay.delay != new->replay.delay)
+		return TRUE;
+
+	return FALSE;
+}
+/*
+ * 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);
+
+	/* Stop effect */
+/*	iforce_control_playback(iforce, id, 0);*/
+
+	iforce_send_packet(iforce, FF_CMD_EFFECT, data);
+
+	/* If needed, restart effect */
+	if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) {
+		/* BUG: perhaps we should replay n times, instead of 1. But we do not know n */
+		iforce_control_playback(iforce, id, 1);
+	}
+
+	return 0;
+}
+
+/*
+ * Upload a periodic effect to the device
+ * See also iforce_upload_constant.
+ */
+int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update)
+{
+	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 param1_err = 1;
+	int param2_err = 1;
+	int core_err = 0;
+
+	if (!is_update || need_period_modifier(iforce, effect)) {
+		param1_err = make_period_modifier(iforce, mod1_chunk, 
+			is_update,
+			effect->u.periodic.magnitude, effect->u.periodic.offset,
+			effect->u.periodic.period, effect->u.periodic.phase);
+		if (param1_err) return param1_err;
+		set_bit(FF_MOD1_IS_USED, core_effect->flags);
+	}
+
+	if (!is_update || need_envelope_modifier(iforce, effect)) {
+		param2_err = make_envelope_modifier(iforce, mod2_chunk,
+			is_update,
+			effect->u.periodic.envelope.attack_length,
+			effect->u.periodic.envelope.attack_level,
+			effect->u.periodic.envelope.fade_length,
+			effect->u.periodic.envelope.fade_level);
+		if (param2_err) return param2_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;
+	}
+
+	if (!is_update || need_core(iforce, effect)) {
+		core_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->direction);
+	}
+
+	/* If one of the parameter creation failed, we already returned an
+	 * error code.
+	 * If the core creation failed, we return its error code.
+	 * Else: if one parameter at least was created, we return 0
+	 *       else we return 1;
+	 */
+	return core_err < 0 ? core_err : (param1_err && param2_err);
+}
+
+/*
+ * Upload a constant force effect
+ * Return value:
+ *  <0 Error code
+ *  0 Ok, effect created or updated
+ *  1 effect did not change since last upload, and no packet was therefore sent
+ */
+int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update)
+{
+	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 param1_err = 1;
+	int param2_err = 1;
+	int core_err = 0;
+
+	if (!is_update || need_magnitude_modifier(iforce, effect)) {
+		param1_err = make_magnitude_modifier(iforce, mod1_chunk,
+			is_update,
+			effect->u.constant.level);
+		if (param1_err) return param1_err;
+		set_bit(FF_MOD1_IS_USED, core_effect->flags);
+	}
+
+	if (!is_update || need_envelope_modifier(iforce, effect)) {
+		param2_err = make_envelope_modifier(iforce, mod2_chunk,
+			is_update,
+			effect->u.constant.envelope.attack_length,
+			effect->u.constant.envelope.attack_level,
+			effect->u.constant.envelope.fade_length,
+			effect->u.constant.envelope.fade_level);
+		if (param2_err) return param2_err;
+		set_bit(FF_MOD2_IS_USED, core_effect->flags);
+	}
+
+	if (!is_update || need_core(iforce, effect)) {
+		core_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->direction);
+	}
+
+	/* If one of the parameter creation failed, we already returned an
+	 * error code.
+	 * If the core creation failed, we return its error code.
+	 * Else: if one parameter at least was created, we return 0
+	 *       else we return 1;
+	 */
+	return core_err < 0 ? core_err : (param1_err && param2_err);
+}
+
+/*
+ * Upload an condition effect. Those are for example friction, inertia, springs...
+ */
+int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update)
+{
+	int core_id = effect->id;
+	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+	struct resource* mod1_chunk = &(core_effect->mod1_chunk);
+	struct resource* mod2_chunk = &(core_effect->mod2_chunk);
+	u8 type;
+	int param_err = 1;
+	int core_err = 0;
+
+	switch (effect->type) {
+		case FF_SPRING:		type = 0x40; break;
+		case FF_DAMPER:		type = 0x41; break;
+		default: return -1;
+	}
+
+	if (!is_update || need_condition_modifier(iforce, effect)) {
+		param_err = make_condition_modifier(iforce, mod1_chunk,
+			is_update,
+			effect->u.condition[0].right_saturation,
+			effect->u.condition[0].left_saturation,
+			effect->u.condition[0].right_coeff,
+			effect->u.condition[0].left_coeff,
+			effect->u.condition[0].deadband,
+			effect->u.condition[0].center);
+		if (param_err) return param_err;
+		set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+		param_err = make_condition_modifier(iforce, mod2_chunk,
+			is_update,
+			effect->u.condition[1].right_saturation,
+			effect->u.condition[1].left_saturation,
+			effect->u.condition[1].right_coeff,
+			effect->u.condition[1].left_coeff,
+			effect->u.condition[1].deadband,
+			effect->u.condition[1].center);
+		if (param_err) return param_err;
+		set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+	}
+
+	if (!is_update || need_core(iforce, effect)) {
+		core_err = make_core(iforce, effect->id,
+			mod1_chunk->start, mod2_chunk->start,
+			type, 0xc0,
+			effect->replay.length, effect->replay.delay,
+			effect->trigger.button, effect->trigger.interval,
+			effect->direction);
+	}
+
+	/* If the parameter creation failed, we already returned an
+	 * error code.
+	 * If the core creation failed, we return its error code.
+	 * Else: if a parameter  was created, we return 0
+	 *       else we return 1;
+	 */
+	return core_err < 0 ? core_err : param_err;
+}
diff -Nru a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce-main.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,543 @@
+/*
+ * $Id: iforce-main.c,v 1.18 2002/06/09 11:03:03 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include "iforce.h"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
+
+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, -1 };
+
+static signed short btn_avb_pegasus[] =
+{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
+  BTN_BASE2, BTN_BASE3, BTN_BASE4, -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 btn_avb_tw[] =
+{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE,
+  BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
+
+static signed short btn_avb_wheel[] =
+{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3,
+  BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 };
+
+static signed short abs_joystick[] =
+{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+
+static signed short abs_avb_pegasus[] =
+{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y,
+  ABS_HAT1X, ABS_HAT1Y, -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_DAMPER,
+  FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN,
+  FF_AUTOCENTER, -1 };
+
+static struct iforce_device iforce_device[] = {
+	{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT",		btn_wheel, abs_wheel, ff_iforce },
+	{ 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_avb_pegasus, abs_avb_pegasus, ff_iforce },
+	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_avb_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_avb_tw, abs_wheel, ff_iforce }, //?
+	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
+	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
+	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
+	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
+};
+
+
+
+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];
+
+	if (type != EV_FF)
+		return -1;
+
+	switch (code) {
+
+		case FF_GAIN:
+
+			data[0] = value >> 9;
+			iforce_send_packet(iforce, FF_CMD_GAIN, data);
+
+			return 0;
+
+		case FF_AUTOCENTER:
+
+			data[0] = 0x03;
+			data[1] = value >> 9;
+			iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			data[0] = 0x04;
+			data[1] = 0x01;
+			iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			return 0;
+
+		default: /* Play or stop an effect */
+
+			if (!CHECK_OWNERSHIP(code, iforce)) {
+				return -1;
+			}
+			if (value > 0) {
+				set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
+			}
+			else {
+				clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
+			}
+
+			iforce_control_playback(iforce, code, value);
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * 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;
+	int ret;
+	int is_update;
+
+/* Check this effect type is supported by this device */
+	if (!test_bit(effect->type, iforce->dev.ffbit))
+		return -EINVAL;
+
+/*
+ * If we want to create a new effect, get a free id
+ */
+	if (effect->id == -1) {
+
+		for (id=0; id < FF_EFFECTS_MAX; ++id)
+			if (!test_and_set_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;
+		iforce->core_effects[id].owner = current->pid;
+		iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED);	/* Only IS_USED bit must be set */
+
+		is_update = FALSE;
+	}
+	else {
+		/* We want to update an effect */
+		if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES;
+		
+		/* Parameter type cannot be updated */
+		if (effect->type != iforce->core_effects[effect->id].effect.type)
+			return -EINVAL;
+
+		/* Check the effect is not already being updated */
+		if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) {
+			return -EAGAIN;
+		}
+
+		is_update = TRUE;
+	}
+
+/*
+ * Upload the effect
+ */
+	switch (effect->type) {
+
+		case FF_PERIODIC:
+			ret = iforce_upload_periodic(iforce, effect, is_update);
+			break;
+
+		case FF_CONSTANT:
+			ret = iforce_upload_constant(iforce, effect, is_update);
+			break;
+
+		case FF_SPRING:
+		case FF_DAMPER:
+			ret = iforce_upload_condition(iforce, effect, is_update);
+			break;
+
+		default:
+			return -EINVAL;
+	}
+	if (ret == 0) {
+		/* A packet was sent, forbid new updates until we are notified
+		 * that the packet was updated
+		 */
+		set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags);
+	}
+	iforce->core_effects[effect->id].effect = *effect;
+	return ret;
+}
+
+/*
+ * 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;
+
+	/* Check who is trying to erase this effect */
+	if (iforce->core_effects[effect_id].owner != current->pid) {
+		printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner);
+		return -EACCES;
+	}
+
+	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_open(struct input_dev *dev)
+{
+	struct iforce *iforce = dev->private;
+
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			iforce->irq->dev = iforce->usbdev;
+			if (usb_submit_urb(iforce->irq, GFP_KERNEL))
+				return -EIO;
+			break;
+#endif
+	}
+
+	/* Enable force feedback */
+	iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
+
+	return 0;
+}
+
+static int iforce_flush(struct input_dev *dev, struct file *file)
+{
+	struct iforce *iforce = dev->private;
+	int i;
+
+	/* Erase all effects this process owns */
+	for (i=0; i<dev->ff_effects_max; ++i) {
+
+		if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
+			current->pid == iforce->core_effects[i].owner) {
+			
+			/* Stop effect */
+			input_report_ff(dev, i, 0);
+
+			/* Free ressources assigned to effect */
+			if (iforce_erase_effect(dev, i)) {
+				printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i);
+			}
+		}
+
+	}
+	return 0;
+}
+
+static void iforce_release(struct input_dev *dev)
+{
+	struct iforce *iforce = dev->private;
+	int i;
+
+	/* Check: no effect should be present in memory */
+	for (i=0; i<dev->ff_effects_max; ++i) {
+		if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags))
+			break;
+	}
+	if (i<dev->ff_effects_max) {
+		printk(KERN_WARNING "iforce_release: Device still owns effects\n");
+	}
+
+	/* Disable force feedback playback */
+	iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
+
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			usb_unlink_urb(iforce->irq);
+
+			/* The device was unplugged before the file
+			 * was released */
+			if (iforce->usbdev == NULL) {
+				iforce_delete_device(iforce);
+				kfree(iforce);
+			}
+		break;
+#endif
+	}
+}
+
+void iforce_delete_device(struct iforce *iforce)
+{
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+	case IFORCE_USB:
+		iforce_usb_delete(iforce);
+		break;
+#endif
+#ifdef IFORCE_232
+	case IFORCE_232:
+		//TODO: Wait for the last packets to be sent
+		break;
+#endif
+	}
+}
+
+int iforce_init_device(struct iforce *iforce)
+{
+	unsigned char c[] = "CEOV";
+	int i;
+
+	init_waitqueue_head(&iforce->wait);
+	spin_lock_init(&iforce->xmit_lock);
+	init_MUTEX(&iforce->mem_mutex);
+	iforce->xmit.buf = iforce->xmit_data;
+
+	iforce->dev.ff_effects_max = 10;
+
+/*
+ * Input device fields.
+ */
+
+	iforce->dev.idbus = BUS_USB;
+	iforce->dev.private = iforce;
+	iforce->dev.name = "Unknown I-Force device";
+	iforce->dev.open = iforce_open;
+	iforce->dev.close = iforce_release;
+	iforce->dev.flush = iforce_flush;
+	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 (!iforce_get_id_packet(iforce, "O"))
+			break;
+
+	if (i == 20) { /* 5 seconds */
+		printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
+		return -1;
+	}
+
+/*
+ * Get device info.
+ */
+
+	if (!iforce_get_id_packet(iforce, "M"))
+		iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
+	else
+		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n");
+
+	if (!iforce_get_id_packet(iforce, "P"))
+		iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
+	else
+		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n");
+
+	if (!iforce_get_id_packet(iforce, "B"))
+		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+	else
+		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
+
+	if (!iforce_get_id_packet(iforce, "N"))
+		iforce->dev.ff_effects_max = iforce->edata[1];
+	else
+		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
+
+	/* Check if the device can store more effects than the driver can really handle */
+	if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) {
+		printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n",
+			iforce->dev.ff_effects_max, FF_EFFECTS_MAX);
+		iforce->dev.ff_effects_max = FF_EFFECTS_MAX;
+	}
+
+/*
+ * Display additional info.
+ */
+
+	for (i = 0; c[i]; i++)
+		if (!iforce_get_id_packet(iforce, c + i))
+			iforce_dump_packet("info", iforce->ecmd, iforce->edata);
+
+/*
+ * Disable spring, enable force feedback.
+ * FIXME: We should use iforce_set_autocenter() et al here.
+ */
+
+	iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
+
+/*
+ * 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;
+	iforce->dev.name = iforce->type->name;
+
+/*
+ * Set input device bitfields and ranges.
+ */
+
+	iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS);
+
+	for (i = 0; iforce->type->btn[i] >= 0; i++) {
+		signed short t = iforce->type->btn[i];
+		set_bit(t, iforce->dev.keybit);
+	}
+	set_bit(BTN_DEAD, iforce->dev.keybit);
+
+	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(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_RUDDER:
+
+				iforce->dev.absmax[t] = 127;
+				iforce->dev.absmin[t] = -128;
+				break;
+
+			case ABS_HAT0X:
+			case ABS_HAT0Y:
+		        case ABS_HAT1X:
+		        case ABS_HAT1Y:
+				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);
+
+	printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open);
+
+	printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n",
+		iforce->dev.name, iforce->dev.ff_effects_max,
+		iforce->device_memory.end);
+
+	return 0;
+}
+
+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/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce-packets.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,314 @@
+/*
+ * $Id: iforce-packets.c,v 1.15 2002/06/09 11:08:04 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include "iforce.h"
+
+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}};
+
+
+void iforce_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
+ */
+int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
+{
+	/* Copy data to buffer */
+	int n = LO(cmd);
+	int c;
+	int empty;
+	int head, tail;
+	unsigned long flags;
+			
+/*
+ * Update head and tail of xmit buffer
+ */
+	spin_lock_irqsave(&iforce->xmit_lock, flags);
+
+	head = iforce->xmit.head;
+	tail = iforce->xmit.tail;
+
+	if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
+		printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
+		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+		return -1;
+	}
+
+	empty = head == tail;
+	XMIT_INC(iforce->xmit.head, n+2);
+
+/*
+ * Store packet in xmit buffer
+ */
+	iforce->xmit.buf[head] = HI(cmd);
+	XMIT_INC(head, 1);
+	iforce->xmit.buf[head] = LO(cmd);
+	XMIT_INC(head, 1);
+
+	c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
+	if (n < c) c=n;
+
+	memcpy(&iforce->xmit.buf[head],
+	       data,
+	       c);
+	if (n != c) {
+		memcpy(&iforce->xmit.buf[0],
+		       data + c,
+		       n - c);
+	}
+	XMIT_INC(head, n);
+
+	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+/*
+ * If necessary, start the transmission
+ */
+	switch (iforce->bus) {
+
+#ifdef IFORCE_232
+		case IFORCE_232:
+		if (empty)
+			iforce_serial_xmit(iforce);
+		break;
+#endif
+#ifdef IFORCE_USB
+		case IFORCE_USB: 
+
+		if (iforce->usbdev && empty &&
+			!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
+
+			iforce_usb_xmit(iforce);
+		}
+		break;
+#endif
+	}
+	return 0;
+}
+
+/* Start or stop an effect */
+int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
+{
+	unsigned char data[3];
+
+printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
+
+	data[0] = LO(id);
+	data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
+	data[2] = LO(value);
+	return iforce_send_packet(iforce, FF_CMD_PLAY, data);
+}
+
+/* Mark an effect that was being updated as ready. That means it can be updated
+ * again */
+static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
+{
+	int i;
+	for (i=0; i<iforce->dev.ff_effects_max; ++i) {
+		if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
+		    (iforce->core_effects[i].mod1_chunk.start == addr ||
+		     iforce->core_effects[i].mod2_chunk.start == addr)) {
+			clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags);
+			return 0;
+		}
+	}
+	printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
+	return -1;
+}
+
+void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+{
+	struct input_dev *dev = &iforce->dev;
+	int i;
+	static int being_used = 0;
+
+	if (being_used)
+		printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
+	being_used++;
+
+#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) {
+		being_used--;
+		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]);
+				if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
+					input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
+			} 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)));
+
+			/* If there are untouched bits left, interpret them as the second hat */
+			if (i <= 8) {
+				int btns = data[6];
+				if (test_bit(ABS_HAT1X, dev->absbit)) {
+					if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
+					else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
+					else input_report_abs(dev, ABS_HAT1X, 0);
+				}
+				if (test_bit(ABS_HAT1Y, dev->absbit)) {
+					if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
+					else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
+					else input_report_abs(dev, ABS_HAT1Y, 0);
+				}
+			}
+
+			break;
+
+		case 0x02:	/* status report */
+			input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+
+			/* Check if an effect was just started or stopped */
+			i = data[1] & 0x7f;
+			if (data[1] & 0x80) {
+				if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+				/* Report play event */
+				input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+				}
+			}
+			else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+				/* Report stop event */
+				input_report_ff_status(dev, i, FF_STATUS_STOPPED);
+			}
+			if (LO(cmd) > 3) {
+				int j;
+				for (j=3; j<LO(cmd); j+=2) {
+					mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
+				}
+			}
+			break;
+	}
+	being_used--;
+}
+
+int iforce_get_id_packet(struct iforce *iforce, char *packet)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = HZ; /* 1 second */
+
+	switch (iforce->bus) {
+
+	case IFORCE_USB:
+
+#ifdef IFORCE_USB
+		iforce->cr.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_KERNEL)) {
+			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;
+		}
+#else
+		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
+#endif
+		break;
+
+	case IFORCE_232:
+
+#ifdef IFORCE_232
+		iforce->expect_packet = FF_CMD_QUERY;
+		iforce_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;
+		}
+#else
+		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
+#endif
+		break;
+
+	default:
+		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
+		       iforce->bus);
+		break;
+	}
+
+	return -(iforce->edata[0] != packet[0]);
+}
+
diff -Nru a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce-serio.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,166 @@
+/*
+ * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include "iforce.h"
+
+void iforce_serial_xmit(struct iforce *iforce)
+{
+	unsigned char cs;
+	int i;
+	unsigned long flags;
+
+	if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
+		set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
+		return;
+	}
+
+	spin_lock_irqsave(&iforce->xmit_lock, flags);
+
+again:
+	if (iforce->xmit.head == iforce->xmit.tail) {
+		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+		return;
+	}
+
+	cs = 0x2b;
+
+	serio_write(iforce->serio, 0x2b);
+
+	serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+	cs ^= iforce->xmit.buf[iforce->xmit.tail];
+	XMIT_INC(iforce->xmit.tail, 1);
+
+	for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
+		serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+		cs ^= iforce->xmit.buf[iforce->xmit.tail];
+		XMIT_INC(iforce->xmit.tail, 1);
+	}
+	
+	serio_write(iforce->serio, cs);
+
+	if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
+		goto again;
+
+	clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+
+	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+}
+
+static void iforce_serio_write_wakeup(struct serio *serio)
+{
+	iforce_serial_xmit((struct iforce *)serio->private);
+}
+
+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;
+	}
+}
+
+static void iforce_serio_disconnect(struct serio *serio)
+{
+	struct iforce* iforce = serio->private;
+
+	input_unregister_device(&iforce->dev);
+	serio_close(serio);
+	kfree(iforce);
+}
+
+struct serio_dev iforce_serio_dev = {
+	write_wakeup:	iforce_serio_write_wakeup,
+	interrupt:	iforce_serio_irq,
+	connect:	iforce_serio_connect,
+	disconnect:	iforce_serio_disconnect,
+};
diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce-usb.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,214 @@
+ /*
+ * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include "iforce.h"
+
+void iforce_usb_xmit(struct iforce *iforce)
+{
+	int n, c;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iforce->xmit_lock, flags);
+
+	if (iforce->xmit.head == iforce->xmit.tail) {
+		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
+		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+		return;
+	}
+
+	((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
+	XMIT_INC(iforce->xmit.tail, 1);
+	n = iforce->xmit.buf[iforce->xmit.tail];
+	XMIT_INC(iforce->xmit.tail, 1);
+
+	iforce->out->transfer_buffer_length = n + 1;
+	iforce->out->dev = iforce->usbdev;
+
+	/* Copy rest of data then */
+	c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
+	if (n < c) c=n;
+
+	memcpy(iforce->out->transfer_buffer + 1,
+	       &iforce->xmit.buf[iforce->xmit.tail],
+	       c);
+	if (n != c) {
+		memcpy(iforce->out->transfer_buffer + 1 + c,
+		       &iforce->xmit.buf[0],
+		       n-c);
+	}
+	XMIT_INC(iforce->xmit.tail, n);
+
+	if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
+		printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
+	}
+
+	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
+	 * As long as the urb completion handler is not called, the transmiting
+	 * is considered to be running */
+	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+}
+
+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) {
+		printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
+		return;
+	}
+
+	iforce_usb_xmit(iforce);
+
+	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)))
+		goto fail;
+
+	memset(iforce, 0, sizeof(struct iforce));
+
+	if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) {
+		goto fail;
+	}
+
+	if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) {
+		goto fail;
+	}
+
+	if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) {
+		goto fail;
+	}
+
+	iforce->bus = IFORCE_USB;
+	iforce->usbdev = dev;
+
+	iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+	iforce->cr.wIndex = 0;
+	iforce->cr.wLength = 16;
+
+	usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+
+	usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+			iforce + 1, 32, iforce_usb_out, iforce);
+
+	usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+			(void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
+
+	if (iforce_init_device(iforce)) goto fail;
+
+	return iforce;
+
+fail:
+	if (iforce) {
+		if (iforce->irq) usb_free_urb(iforce->irq);
+		if (iforce->out) usb_free_urb(iforce->out);
+		if (iforce->ctrl) usb_free_urb(iforce->ctrl);
+		kfree(iforce);
+	}
+
+	return NULL;
+}
+
+/* Called by iforce_delete() */
+void iforce_usb_delete(struct iforce* iforce)
+{
+	usb_unlink_urb(iforce->irq);
+/* Is it ok to unlink those ? */
+	usb_unlink_urb(iforce->out);
+	usb_unlink_urb(iforce->ctrl);
+
+	usb_free_urb(iforce->irq);
+	usb_free_urb(iforce->out);
+	usb_free_urb(iforce->ctrl);
+}
+
+static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct iforce *iforce = ptr;
+	int open = iforce->dev.handle->open;
+
+	iforce->usbdev = NULL;
+	input_unregister_device(&iforce->dev);
+
+	if (!open) {
+		iforce_delete_device(iforce);
+		kfree(iforce);
+	}
+}
+
+static struct usb_device_id iforce_usb_ids [] = {
+	{ USB_DEVICE(0x044f, 0xa01c) },		/* Thrustmaster Motor Sport GT */
+	{ 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(0x05ef, 0x8888) },		/* AVB Top Shot FFB Racing Wheel */
+	{ USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
+	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
+
+struct usb_driver iforce_usb_driver = {
+	owner:		THIS_MODULE,
+	name:		"iforce",
+	probe:		iforce_usb_probe,
+	disconnect:	iforce_usb_disconnect,
+	id_table:	iforce_usb_ids,
+};
diff -Nru a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/iforce/iforce.h	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,194 @@
+/*
+ * $Id: iforce.h,v 1.12 2002/06/09 11:08:04 jdeneux Exp $
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
+ *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *
+ *  USB/RS232 I-Force joysticks and wheels.
+ */
+
+/*
+ * 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, Simunkova 1594, 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>
+#include <linux/circ_buf.h>
+#include <asm/semaphore.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>
+
+#define IFORCE_MAX_LENGTH	16
+
+#if defined(CONFIG_JOYSTICK_IFORCE_232)
+#define IFORCE_232	1
+#endif
+#if defined(CONFIG_JOYSTICK_IFORCE_USB)
+#define IFORCE_USB	2
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+#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	/* Effect is currently being played */
+#define FF_CORE_SHOULD_PLAY	4	/* User wants the effect to be played */
+#define FF_CORE_UPDATE		5	/* Effect is being updated */
+#define FF_MODCORE_MAX		5
+
+#define CHECK_OWNERSHIP(i, iforce)	\
+	((i) < FF_EFFECTS_MAX && i >= 0 && \
+	test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
+	(current->pid == 0 || \
+	(iforce)->core_effects[(i)].owner == current->pid))
+
+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)];
+	pid_t owner;
+	/* Used to keep track of parameters of an effect. They are needed
+	 * to know what parts of an effect changed in an update operation.
+	 * We try to send only parameter packets if possible, as sending
+	 * effect parameter requires the effect to be stoped and restarted
+	 */
+	struct ff_effect effect;
+};
+
+#define FF_CMD_EFFECT		0x010e
+#define FF_CMD_ENVELOPE		0x0208
+#define FF_CMD_MAGNITUDE	0x0303
+#define FF_CMD_PERIOD		0x0407
+#define FF_CMD_CONDITION	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
+
+/* Buffer for async write */
+#define XMIT_SIZE		256
+#define XMIT_INC(var, n)	(var)+=n; (var)&= XMIT_SIZE -1
+/* iforce::xmit_flags */
+#define IFORCE_XMIT_RUNNING	0
+#define IFORCE_XMIT_AGAIN	1
+
+struct iforce_device {
+	u16 idvendor;
+	u16 idproduct;
+	char *name;
+	signed short *btn;
+	signed short *abs;
+	signed short *ff;
+};
+
+struct iforce {
+	struct input_dev dev;		/* Input device interface */
+	struct iforce_device *type;
+	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 cr;
+#endif
+	spinlock_t xmit_lock;
+	/* Buffer used for asynchronous sending of bytes to the device */
+	struct circ_buf xmit;
+	unsigned char xmit_data[XMIT_SIZE];
+	long xmit_flags[1];
+	
+					/* Force Feedback */
+	wait_queue_head_t wait;
+	struct resource device_memory;
+	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
+	struct semaphore mem_mutex;
+};
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+/* For many parameters, it seems that 0x80 is a special value that should
+ * be avoided. Instead, we replace this value by 0x7f
+ */
+#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8))
+
+/* Encode a time value */
+#define TIME_SCALE(a)	(a)
+
+
+/* Public functions */
+/* iforce-serio.c */
+void iforce_serial_xmit(struct iforce *iforce);
+
+/* iforce-usb.c */
+void iforce_usb_xmit(struct iforce *iforce);
+void iforce_usb_delete(struct iforce *iforce);
+
+/* iforce-main.c */
+int iforce_init_device(struct iforce *iforce);
+void iforce_delete_device(struct iforce *iforce);
+
+/* iforce-packets.c */
+int iforce_control_playback(struct iforce*, u16 id, unsigned int);
+void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
+int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
+void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
+int iforce_get_id_packet(struct iforce *iforce, char *packet);
+
+/* iforce-ff.c */
+int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
+int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
+int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
+
+/* Public variables */
+extern struct serio_dev iforce_serio_dev;
+extern struct usb_driver iforce_usb_driver;
diff -Nru a/drivers/input/joystick/iforce.c b/drivers/input/joystick/iforce.c
--- a/drivers/input/joystick/iforce.c	Fri Jul  5 16:43:00 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_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->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->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->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, GFP_KERNEL);
-	if (!iforce->irq) {
-		kfree(iforce);
-		return NULL;
-	}
-	iforce->out = usb_alloc_urb(0, GFP_KERNEL);
-	if (!iforce->out) {
-		usb_free_urb(iforce->irq);
-		kfree(iforce);
-		return NULL;
-	}
-	iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL);
-	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/magellan.c b/drivers/input/joystick/magellan.c
--- a/drivers/input/joystick/magellan.c	Fri Jul  5 16:42:50 2002
+++ b/drivers/input/joystick/magellan.c	Fri Jul  5 16:42:50 2002
@@ -156,7 +156,7 @@
 	magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
 
 	for (i = 0; i < 9; i++)
-		set_bit(magellan_buttons[i], &magellan->dev.keybit);
+		set_bit(magellan_buttons[i], magellan->dev.keybit);
 
 	for (i = 0; i < 6; i++) {
 		t = magellan_axes[i];
diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/joystick/twidjoy.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,264 @@
+/*
+ * $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $
+ *
+ *  derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp"
+ *
+ *  Copyright (c) 2001 Arndt Schoenewald
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2000 Mark Fletcher
+ *
+ *  Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany
+ */
+
+/*
+ * Driver to use Handykey's Twiddler (the first edition, i.e. the one with
+ * the RS232 interface) as a joystick under Linux
+ *
+ * The Twiddler is a one-handed chording keyboard featuring twelve buttons on
+ * the front, six buttons on the top, and a built-in tilt sensor. The buttons
+ * on the front, which are grouped as four rows of three buttons, are pressed
+ * by the four fingers (this implies only one button per row can be held down
+ * at the same time) and the buttons on the top are for the thumb. The tilt
+ * sensor delivers X and Y axis data depending on how the Twiddler is held.
+ * Additional information can be found at http://www.handykey.com.
+ *
+ * This driver does not use the Twiddler for its intended purpose, i.e. as
+ * a chording keyboard, but as a joystick: pressing and releasing a button
+ * immediately sends a corresponding button event, and tilting it generates
+ * corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game
+ * controller with amazing 18 buttons :-)
+ *
+ * Note: The Twiddler2 (the successor of the Twiddler that connects directly
+ * to the PS/2 keyboard and mouse ports) is NOT supported by this driver!
+ *
+ * For questions or feedback regarding this driver module please contact:
+ * Arndt Schoenewald <arndt@quelltext.com>
+ */
+
+/*
+ * 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
+ */
+
+#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 TWIDJOY_MAX_LENGTH 5
+
+static char *twidjoy_name = "Handykey Twiddler";
+
+static struct twidjoy_button_spec {
+	int bitshift;
+	int bitmask;
+	int buttons[3];
+}
+twidjoy_buttons[] = {
+	{  0, 3, { BTN_A,      BTN_B,     BTN_C    } },
+	{  2, 3, { BTN_X,      BTN_Y,     BTN_Z    } },
+	{  4, 3, { BTN_TL,     BTN_TR,    BTN_TR2  } },
+	{  6, 3, { BTN_SELECT, BTN_START, BTN_MODE } },
+	{  8, 1, { BTN_BASE5                       } },
+	{  9, 1, { BTN_BASE                        } },
+	{ 10, 1, { BTN_BASE3                       } },
+	{ 11, 1, { BTN_BASE4                       } },
+	{ 12, 1, { BTN_BASE2                       } },
+	{ 13, 1, { BTN_BASE6                       } },
+	{ 0,  0, { 0                               } }
+};
+
+/*
+ * Per-Twiddler data.
+ */
+
+struct twidjoy {
+	struct input_dev dev;
+	int idx;
+	unsigned char data[TWIDJOY_MAX_LENGTH];
+	char phys[32];
+};
+
+/*
+ * twidjoy_process_packet() decodes packets the driver receives from the
+ * Twiddler. It updates the data accordingly.
+ */
+
+static void twidjoy_process_packet(struct twidjoy *twidjoy)
+{
+	if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
+		struct input_dev *dev = &twidjoy->dev;
+		unsigned char *data = twidjoy->data;
+		struct twidjoy_button_spec *bp;
+		int button_bits, abs_x, abs_y;
+
+		button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f);
+
+		for (bp = twidjoy_buttons; bp->bitmask; bp++) {
+			int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift;
+			int i;
+
+			for (i = 0; i < bp->bitmask; i++)
+				input_report_key(dev, bp->buttons[i], i+1 == value);
+		}
+
+		abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2);
+		if (data[4] & 0x08) abs_x -= 256;
+
+		abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0);
+		if (data[3] & 0x02) abs_y -= 256;
+
+		input_report_abs(dev, ABS_X, -abs_x);
+		input_report_abs(dev, ABS_Y, +abs_y);
+	}
+
+	return;
+}
+
+/*
+ * twidjoy_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 twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct twidjoy *twidjoy = serio->private;
+
+	/* All Twiddler packets are 5 bytes. The fact that the first byte
+	 * has a MSB of 0 and all other bytes have a MSB of 1 can be used
+	 * to check and regain sync. */
+
+	if ((data & 0x80) == 0)
+		twidjoy->idx = 0;	/* this byte starts a new packet */
+	else if (twidjoy->idx == 0)
+		return;			/* wrong MSB -- ignore this byte */
+
+	if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
+		twidjoy->data[twidjoy->idx++] = data;
+
+	if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
+		twidjoy_process_packet(twidjoy);
+		twidjoy->idx = 0;
+	}
+
+	return;
+}
+
+/*
+ * twidjoy_disconnect() is the opposite of twidjoy_connect()
+ */
+
+static void twidjoy_disconnect(struct serio *serio)
+{
+	struct twidjoy *twidjoy = serio->private;
+	input_unregister_device(&twidjoy->dev);
+	serio_close(serio);
+	kfree(twidjoy);
+}
+
+/*
+ * twidjoy_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Twiddler, and if found, registers
+ * it as an input device.
+ */
+
+static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct twidjoy_button_spec *bp;
+	struct twidjoy *twidjoy;
+	int i;
+
+	if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY))
+		return;
+
+	if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL)))
+		return;
+
+	memset(twidjoy, 0, sizeof(struct twidjoy));
+
+	sprintf(twidjoy->phys, "%s/input0", serio->phys);
+
+	twidjoy->dev.name = twidjoy_name;
+	twidjoy->dev.phys = twidjoy->phys;
+	twidjoy->dev.idbus = BUS_RS232;
+	twidjoy->dev.idvendor = SERIO_TWIDJOY;
+	twidjoy->dev.idproduct = 0x0001;
+	twidjoy->dev.idversion = 0x0100;
+
+	twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+
+	for (bp = twidjoy_buttons; bp->bitmask; bp++) {
+		for (i = 0; i < bp->bitmask; i++)
+			set_bit(bp->buttons[i], twidjoy->dev.keybit);
+	}
+
+	twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+	for (i = 0; i < 2; i++) {
+		twidjoy->dev.absmax[ABS_X+i] =  50;	
+		twidjoy->dev.absmin[ABS_X+i] = -50;	
+
+		/* TODO: arndt 20010708: Are these values appropriate? */
+		twidjoy->dev.absfuzz[ABS_X+i] = 4;
+		twidjoy->dev.absflat[ABS_X+i] = 4;
+	}
+
+	twidjoy->dev.private = twidjoy;
+	
+	serio->private = twidjoy;
+
+	if (serio_open(serio, dev)) {
+		kfree(twidjoy);
+		return;
+	}
+
+	input_register_device(&twidjoy->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev twidjoy_dev = {
+	interrupt:	twidjoy_interrupt,
+	connect:	twidjoy_connect,
+	disconnect:	twidjoy_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init twidjoy_init(void)
+{
+	serio_register_device(&twidjoy_dev);
+	return 0;
+}
+
+void __exit twidjoy_exit(void)
+{
+	serio_unregister_device(&twidjoy_dev);
+}
+
+module_init(twidjoy_init);
+module_exit(twidjoy_exit);
diff -Nru a/drivers/input/keybdev.c b/drivers/input/keybdev.c
--- a/drivers/input/keybdev.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/keybdev.c	Fri Jul  5 16:43:00 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: keybdev.c,v 1.16 2002/01/09 04:21:41 lethal Exp $
+ * $Id: keybdev.c,v 1.19 2002/03/13 10:09:20 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
@@ -179,7 +179,7 @@
 	static unsigned long last_jiffie;
 	static char led;
 	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
-	if (jiffies - last_jiffie > HZ/2) {
+	if (time_after(jiffies, last_jiffie + HZ/2)) {
 		led ^= 0x01 | 0x04;
 		keybdev_ledfunc(led);
 		last_jiffie = jiffies;
diff -Nru a/drivers/input/keyboard/Config.help b/drivers/input/keyboard/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/Config.help	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,66 @@
+CONFIG_INPUT_KEYBOARD
+  Say Y here, and a list of supported keyboards will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_KEYBOARD_ATKBD
+  Say Y here if you want to use the standard AT keyboard. Usually
+  you'll need this, unless you have a different type keyboard (USB,
+  ADB or other).
+
+  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 atkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_SUNKBD
+  Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
+  connected either to the Sun keyboard connector or to an serial
+  (RS-232) port via a simple adapter.
+
+  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 sunkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_PS2SERKBD
+  Say Y here if you want to use a PS/2 to Serial converter with a
+  keyboard attached 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 ps2serkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_XTKBD
+  Say Y here if you want to use the old IBM PC/XT keyboard (or
+  compatible) on your system. This is only possible with a
+  parallel port keyboard adapter, you cannot connect it to the
+  keyboard port on a PC that runs Linux. 
+
+  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 xtkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_MAPLE  
+  Say Y here if you have a DreamCast console running Linux and have
+  a keyboard attached to its Maple bus.
+
+  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 maple_keyb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_AMIGA
+  Say Y here if you are running Linux on any AMIGA and have a keyboard
+  attached.	
+
+  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 amikbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff -Nru a/drivers/input/keyboard/Config.in b/drivers/input/keyboard/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/Config.in	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,18 @@
+#
+# Input core configuration
+#
+
+bool 'Keyboards' CONFIG_INPUT_KEYBOARD
+
+dep_tristate '  AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+   dep_tristate '  Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
+fi
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate '  Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD
+fi
diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/Makefile	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,16 @@
+#
+# Makefile for the input core drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
+obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
+obj-$(CONFIG_KEYBOARD_PS2SERKBD)	+= ps2serkbd.o
+obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
+obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
+obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/amikbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,144 @@
+/*
+ * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Hamish Macdonald
+ */
+
+/*
+ * Amiga keyboard driver 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Amiga keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char amikbd_keycode[0x78] = {
+	 41,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 43,  0, 82,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,  0, 79, 80, 81,
+	 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  0,  0, 75, 76, 77,
+	  0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,  0, 83, 71, 72, 73,
+	 57, 14, 15, 96, 28,  1,111,  0,  0,  0, 74,  0,103,108,106,105,
+	 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87,
+	 42, 54, 58, 29, 56,100
+}
+
+static char *amikbd_messages[] = {
+	KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
+	KERN_WARNING "amikbd: keyboard lost sync\n",
+	KERN_WARNING "amikbd: keyboard buffer overflow\n",
+	KERN_WARNING "amikbd: keyboard controller failure\n",
+	KERN_ERR "amikbd: keyboard selftest failure\n",
+	KERN_INFO "amikbd: initiate power-up key stream\n",
+	KERN_INFO "amikbd: terminate power-up key stream\n",
+	KERN_WARNING "amikbd: keyboard interrupt\n"
+};
+
+static struct input_dev amikbd_dev;
+
+static char *amikbd_name = "Amiga keyboard";
+static char *amikbd_phys = "amikbd/input0";
+
+static void amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned char scancode, down;
+
+	scancode = ~ciaa.sdr;		/* get and invert scancode (keyboard is active low) */
+	ciaa.cra |= 0x40;		/* switch SP pin to output for handshake */
+	udelay(85);			/* wait until 85 us have expired */
+	ciaa.cra &= ~0x40;		/* switch CIA serial port to input mode */
+
+	down = scancode & 1;		/* lowest bit is release bit */
+	scancode = scancode >> 1;
+
+	if (scancode < 0x78) {		/* scancodes < 0x78 are keys */
+
+		scancode = amikbd_keycode[scancode];
+	
+		if (scancode == KEY_CAPS) {	/* CapsLock is a toggle switch key on Amiga */
+			input_report_key(&amikbd_dev, scancode, 1);
+			input_report_key(&amikbd_dev, scancode, 0);
+			return;
+		}
+		
+		input_report_key(&amikbd_dev, scancode, down);
+
+		return;
+	}
+
+	printk(amikbd_messages[scancode - 0x78]);	/* scancodes >= 0x78 are error codes */
+}
+
+static int __init amikbd_init(void)
+{
+	int i;
+
+	if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
+	 	return -EIO;
+
+	if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))   
+		return -EBUSY;
+
+	amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);	
+	amikbd_dev.keycode = amikbd_keycode;
+	
+ 	for (i = 0; i < 0x78; i++)
+		if (amikbd_keycode[i])
+			set_bit(amikbd_keycode[i], amikbd_dev.keybit);
+
+	ciaa.cra &= ~0x41;	 /* serial data in, turn off TA */
+	request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL);
+
+	amikbd_dev.name = amikbd_name;
+	amikbd_dev.phys = amikbd_phys;
+	amikbd_dev.idbus = BUS_AMIGA;
+	amikbd_dev.idvendor = 0x0001;
+	amikbd_dev.idproduct = 0x0001;
+	amikbd_dev.idversion = 0x0100;
+
+	input_register_device(&amikbd_dev);
+
+	printk(KERN_INFO "input: %s\n", amikbd_name);
+
+	return 0;
+}
+
+static void __exit amikbd_exit(void)
+{
+	input_unregister_device(&amikbd_dev);
+	free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
+	release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100);
+}
+
+module_init(amikbd_init);
+module_exit(amikbd_exit);
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/atkbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,565 @@
+/*
+ * $Id: atkbd.c,v 1.33 2002/02/12 09:34:34 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
+MODULE_PARM(atkbd_set, "1i");
+MODULE_LICENSE("GPL");
+
+static int atkbd_set = 2;
+
+/*
+ * Scancode to keycode tables. These are just the default setting, and
+ * are loadable via an userland utility.
+ */
+
+static unsigned char atkbd_set2_keycode[512] = {
+	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41, 85,
+	  0, 56, 42,  0, 29, 16,  2, 89,  0,  0, 44, 31, 30, 17,  3, 90,
+	  0, 46, 45, 32, 18,  5,  4, 91,  0, 57, 47, 33, 20, 19,  6,  0,
+	  0, 49, 48, 35, 34, 21,  7,  0,  0,  0, 50, 36, 22,  8,  9,  0,
+	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
+	122, 89, 40,120, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0,  0,
+	 85, 86, 90, 91, 92, 93, 14, 94, 95, 79,  0, 75, 71,121,  0,123,
+	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+	252,  0,  0, 65, 99,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,251,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	252,253,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	254,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255,
+	  0,  0, 92, 90, 85,  0,137,  0,  0,  0,  0, 91, 89,144,115,  0,
+	136,100,255,  0, 97,149,164,  0,156,  0,  0,140,115,  0,  0,125,
+	  0,150,  0,154,152,163,151,126,112,166,  0,140,  0,147,  0,127,
+	159,167,139,160,163,  0,  0,116,158,  0,150,165,  0,  0,  0,142,
+	157,  0,114,166,168,  0,  0,  0,155,  0, 98,113,  0,148,  0,138,
+	  0,  0,  0,  0,  0,  0,153,140,  0,255, 96,  0,  0,  0,143,  0,
+	133,  0,116,  0,143,  0,174,133,  0,107,  0,105,102,  0,  0,112,
+	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119
+};
+
+static unsigned char atkbd_set3_keycode[512] = {
+	  0,  0,  0,  0,  0,  0,  0, 59,  1,138,128,129,130, 15, 41, 60,
+	131, 29, 42, 86, 58, 16,  2, 61,133, 56, 44, 31, 30, 17,  3, 62,
+	134, 46, 45, 32, 18,  5,  4, 63,135, 57, 47, 33, 20, 19,  6, 64,
+	136, 49, 48, 35, 34, 21,  7, 65,137,100, 50, 36, 22,  8,  9, 66,
+	125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
+	113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70,
+	108,105,119,103,111,107, 14,110,  0, 79,106, 75, 71,109,102,104,
+	 82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55, 85,
+	 89, 90, 91, 92, 74,  0,  0,  0,  0,  0,  0,125,126,127,112,  0,
+	  0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
+	148,149,147,140,  0,  0,  0,  0,  0,  0,251,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	252,253,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	254,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255
+};
+
+#define ATKBD_CMD_SETLEDS	0x10ed
+#define ATKBD_CMD_GSCANSET	0x11f0
+#define ATKBD_CMD_SSCANSET	0x10f0
+#define ATKBD_CMD_GETID		0x02f2
+#define ATKBD_CMD_ENABLE	0x00f4
+#define ATKBD_CMD_RESET_DIS	0x00f5
+#define ATKBD_CMD_SETALL_MB	0x00f8
+#define ATKBD_CMD_EX_ENABLE	0x10ea
+#define ATKBD_CMD_EX_SETLEDS	0x20eb
+
+#define ATKBD_RET_ACK		0xfa
+#define ATKBD_RET_NAK		0xfe
+
+#define ATKBD_KEY_UNKNOWN	  0
+#define ATKBD_KEY_BAT		251
+#define ATKBD_KEY_EMUL0		252
+#define ATKBD_KEY_EMUL1		253
+#define ATKBD_KEY_RELEASE	254
+#define ATKBD_KEY_NULL		255
+
+/*
+ * The atkbd control structure
+ */
+
+struct atkbd {
+	unsigned char keycode[512];
+	struct input_dev dev;
+	struct serio *serio;
+	char name[64];
+	char phys[32];
+	struct tq_struct tq;
+	unsigned char cmdbuf[4];
+	unsigned char cmdcnt;
+	unsigned char set;
+	char release;
+	char ack;
+	char emul;
+	char error;
+	unsigned short id;
+};
+
+/*
+ * atkbd_interrupt(). Here takes place processing of data received from
+ * the keyboard into events.
+ */
+
+static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct atkbd *atkbd = serio->private;
+	int code = data;
+
+#ifdef ATKBD_DEBUG
+	printk(KERN_DEBUG "atkbd.c: Received %02x\n", data);
+#endif
+
+	switch (code) {
+		case ATKBD_RET_ACK:
+			atkbd->ack = 1;
+			return;
+		case ATKBD_RET_NAK:
+			atkbd->ack = -1;
+			return;
+	}
+
+	if (atkbd->cmdcnt) {
+		atkbd->cmdbuf[--atkbd->cmdcnt] = code;
+		return;
+	}
+
+	switch (atkbd->keycode[code]) {
+		case ATKBD_KEY_BAT:
+			queue_task(&atkbd->tq, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			return;
+		case ATKBD_KEY_EMUL0:
+			atkbd->emul = 1;
+			return;
+		case ATKBD_KEY_EMUL1:
+			atkbd->emul = 2;
+			return;
+		case ATKBD_KEY_RELEASE:
+			atkbd->release = 1;
+			return;
+	}
+
+	if (atkbd->emul) {
+		if (--atkbd->emul) return;
+		code |= 0x100;
+	}
+
+	switch (atkbd->keycode[code]) {
+		case ATKBD_KEY_NULL:
+			break;
+		case ATKBD_KEY_UNKNOWN:
+			printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n",
+				atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
+			break;
+		default:
+			input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
+	}
+		
+	atkbd->release = 0;
+}
+
+/*
+ * atkbd_sendbyte() sends a byte to the keyboard, and waits for
+ * acknowledge. It doesn't handle resends according to the keyboard
+ * protocol specs, because if these are needed, the keyboard needs
+ * replacement anyway, and they only make a mess in the protocol.
+ */
+
+static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
+{
+	int timeout = 10000; /* 100 msec */
+	atkbd->ack = 0;
+
+#ifdef ATKBD_DEBUG
+	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
+#endif
+	serio_write(atkbd->serio, byte);
+	while (!atkbd->ack && timeout--) udelay(10);
+
+	return -(atkbd->ack <= 0);
+}
+
+/*
+ * atkbd_command() sends a command, and its parameters to the keyboard,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
+{
+	int timeout = 50000; /* 500 msec */
+	int send = (command >> 12) & 0xf;
+	int receive = (command >> 8) & 0xf;
+	int i;
+
+	atkbd->cmdcnt = receive;
+	
+	if (command & 0xff)
+		if (atkbd_sendbyte(atkbd, command & 0xff))
+			return (atkbd->cmdcnt = 0) - 1;
+
+	for (i = 0; i < send; i++)
+		if (atkbd_sendbyte(atkbd, param[i]))
+			return (atkbd->cmdcnt = 0) - 1;
+
+	while (atkbd->cmdcnt && timeout--) udelay(10);
+
+	for (i = 0; i < receive; i++)
+		param[i] = atkbd->cmdbuf[(receive - 1) - i];
+
+	if (atkbd->cmdcnt) 
+		return (atkbd->cmdcnt = 0) - 1;
+
+	return 0;
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+
+static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct atkbd *atkbd = dev->private;
+	char param[2];
+
+	if (!atkbd->serio->write)
+		return -1;
+
+	switch (type) {
+
+		case EV_LED:
+
+			*param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+			       | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
+			       | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
+		        atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
+
+			if (atkbd->set == 4) {
+				param[0] = 0;
+				param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+					 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
+					 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+				         | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
+				atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+			}
+
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * atkbd_set_3 checks if a keyboard has a working Set 3 support, and
+ * sets it into that. Unfortunately there are keyboards that can be switched
+ * to Set 3, but don't work well in that (BTC Multimedia ...)
+ */
+
+static int atkbd_set_3(struct atkbd *atkbd)
+{
+	unsigned char param;
+
+/*
+ * For known special keyboards we can go ahead and set the correct set.
+ */
+
+	if (atkbd->id == 0xaca1) {
+		param = 3;
+		atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
+		return 3;
+	}
+
+/*
+ * We check for the extra keys on an some keyboards that need extra
+ * command to get enabled. This shouldn't harm any keyboards not
+ * knowing the command.
+ */
+
+	param = 0x71;
+	if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
+		return 4;
+
+/*
+ * Try to set the set we want.
+ */
+
+	param = atkbd_set;
+	if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
+		return 2;
+
+/*
+ * Read set number. Beware here. Some keyboards always send '2'
+ * or some other number regardless into what mode they have been
+ * attempted to be set. Other keyboards treat the '0' command as
+ * 'set to set 0', and not 'report current set' as they should.
+ * In that case we time out, and return 2.
+ */
+
+	param = 0;
+	if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
+		return 2;
+
+/*
+ * Here we return the set number the keyboard reports about
+ * itself.
+ */
+
+	return (param == 3) ? 3 : 2;
+}
+
+/*
+ * atkbd_probe() probes for an AT keyboard on a serio port.
+ */
+
+static int atkbd_probe(struct atkbd *atkbd)
+{
+	unsigned char param[2];
+
+/*
+ * Full reset with selftest can on some keyboards be annoyingly slow,
+ * so we just do a reset-and-disable on the keyboard, which
+ * is considerably faster, but doesn't have to reset everything.
+ */
+
+	if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS))
+		return -1;
+
+/*
+ * Next, we check if it's a keyboard. It should send 0xab83
+ * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard,
+ * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f
+ * on Fujitsu Lifebook).
+ * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse),
+ * and we'll time out here, and report an error.
+ */
+
+	param[0] = param[1] = 0;
+
+	if (atkbd_command(atkbd, param, ATKBD_CMD_GETID))
+		return -1;
+
+	atkbd->id = (param[0] << 8) | param[1];
+
+	if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 &&
+	    atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03)
+		printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n",
+			atkbd->id, atkbd->serio->phys);
+
+	return 0;
+}
+
+/*
+ * atkbd_initialize() sets the keyboard into a sane state.
+ */
+
+static void atkbd_initialize(struct atkbd *atkbd)
+{
+	unsigned char param;	
+
+/*
+ * Disable autorepeat. We don't need it, as we do it in software anyway,
+ * because that way can get faster repeat, and have less system load
+ * (less accesses to the slow ISA hardware). If this fails, we don't care,
+ * and will just ignore the repeated keys.
+ */
+
+	atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
+
+/*
+ * We also shut off all the leds. The console code will turn them back on,
+ * if needed.
+ */
+
+	param = 0;
+	atkbd_command(atkbd, &param, ATKBD_CMD_SETLEDS);
+
+/*
+ * Last, we enable the keyboard so that we get keypresses from it.
+ */
+
+	if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
+		printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+			atkbd->serio->phys);
+}
+
+/*
+ * atkbd_disconnect() cleans up behind us ...
+ */
+
+static void atkbd_disconnect(struct serio *serio)
+{
+	struct atkbd *atkbd = serio->private;
+	input_unregister_device(&atkbd->dev);
+	serio_close(serio);
+	kfree(atkbd);
+}
+
+/*
+ * atkbd_powerup() is called when the keyboard sends the 0xaa character,
+ * meaning that it was disconnected and reconnected. We close the port
+ * in that case and let the upper layer find an appropriate driver for
+ * the device that was connected. It may be a mouse, or a keyboard, we
+ * don't know yet.
+ */
+
+static void atkbd_powerup(void *data)
+{
+	struct atkbd *atkbd = data;
+	mdelay(40); /* FIXME!!! Wait some nicer way */
+	serio_rescan(atkbd->serio);
+}
+
+/*
+ * atkbd_connect() is called when the serio module finds and interface
+ * that isn't handled yet by an appropriate device driver. We check if
+ * there is an AT keyboard out there and if yes, we register ourselves
+ * to the input module.
+ */
+
+static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct atkbd *atkbd;
+	int i;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+		return;
+
+	if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
+		return;
+
+	memset(atkbd, 0, sizeof(struct atkbd));
+
+	if (serio->write) {
+		atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+		atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	} else  atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	atkbd->serio = serio;
+
+	atkbd->dev.keycode = atkbd->keycode;
+	atkbd->dev.event = atkbd_event;
+	atkbd->dev.private = atkbd;
+
+	atkbd->tq.routine = atkbd_powerup;
+	atkbd->tq.data = atkbd;
+
+	serio->private = atkbd;
+
+	if (serio_open(serio, dev)) {
+		kfree(atkbd);
+		return;
+	}
+
+	if (serio->write) {
+
+		if (atkbd_probe(atkbd)) {
+			serio_close(serio);
+			kfree(atkbd);
+			return;
+		}
+		
+		atkbd->set = atkbd_set_3(atkbd);
+
+	} else {
+		atkbd->set = 2;
+		atkbd->id = 0xab00;
+	}
+
+	if (atkbd->set == 4) {
+		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
+		sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
+	} else
+		sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
+
+	sprintf(atkbd->phys, "%s/input0", serio->phys);
+
+	if (atkbd->set == 3)
+		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+	else
+		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
+
+	atkbd->dev.name = atkbd->name;
+	atkbd->dev.phys = atkbd->phys;
+	atkbd->dev.idbus = BUS_I8042;
+	atkbd->dev.idvendor = 0x0001;
+	atkbd->dev.idproduct = atkbd->set;
+	atkbd->dev.idversion = atkbd->id;
+
+	for (i = 0; i < 512; i++)
+		if (atkbd->keycode[i] && atkbd->keycode[i] <= 250)
+			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+
+	input_register_device(&atkbd->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+
+	if (serio->write)
+		atkbd_initialize(atkbd);
+}
+
+
+static struct serio_dev atkbd_dev = {
+	interrupt:	atkbd_interrupt,
+	connect:	atkbd_connect,
+	disconnect:	atkbd_disconnect
+};
+
+/*
+ * Module init and exit.
+ */
+
+void __init atkbd_setup(char *str, int *ints)
+{
+	if (!ints[0]) atkbd_set = ints[1];
+}
+
+int __init atkbd_init(void)
+{
+	serio_register_device(&atkbd_dev);
+	return 0;
+}
+
+void __exit atkbd_exit(void)
+{
+	serio_unregister_device(&atkbd_dev);
+}
+
+module_init(atkbd_init);
+module_exit(atkbd_exit);
diff -Nru a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/maple_keyb.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,190 @@
+/*
+ *	$Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ * 	SEGA Dreamcast keyboard driver
+ *	Based on drivers/usb/usbkbd.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+
+MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
+MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
+
+static unsigned char dc_kbd_keycode[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
+	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,  0,  0,  0,124,  0,181,182,183,184,185,186,187,188,189,
+	190,191,192,193,194,195,196,197,198,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+
+struct dc_kbd {
+	struct input_dev dev;
+	unsigned char new[8];
+	unsigned char old[8];
+	int open;
+};
+
+
+static void dc_scan_kbd(struct dc_kbd *kbd)
+{
+	int i;
+	struct input_dev *dev = &kbd->dev;
+
+	for(i=0; i<8; i++)
+		input_report_key(dev,
+				 dc_kbd_keycode[i+224],
+				 (kbd->new[0]>>i)&1);
+
+	for(i=2; i<8; i++) {
+
+		if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) {
+			if(dc_kbd_keycode[kbd->old[i]])
+				input_report_key(dev,
+						 dc_kbd_keycode[kbd->old[i]],
+						 0);
+			else
+				printk("Unknown key (scancode %#x) released.",
+				       kbd->old[i]);
+		}
+
+		if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) {
+			if(dc_kbd_keycode[kbd->new[i]])
+				input_report_key(dev,
+						 dc_kbd_keycode[kbd->new[i]],
+						 1);
+			else
+				printk("Unknown key (scancode %#x) pressed.",
+				       kbd->new[i]);
+		}
+	}
+
+	memcpy(kbd->old, kbd->new, 8);
+}
+
+
+static void dc_kbd_callback(struct mapleq *mq)
+{
+	struct maple_device *mapledev = mq->dev;
+	struct dc_kbd *kbd = mapledev->private_data;
+	unsigned long *buf = mq->recvbuf;
+
+	if (buf[1] == mapledev->function) {
+		memcpy(kbd->new, buf+2, 8);
+		dc_scan_kbd(kbd);
+	}
+}
+
+
+static int dc_kbd_open(struct input_dev *dev)
+{
+	struct dc_kbd *kbd = dev->private;
+	kbd->open++;
+	return 0;
+}
+
+
+static void dc_kbd_close(struct input_dev *dev)
+{
+	struct dc_kbd *kbd = dev->private;
+	kbd->open--;
+}
+
+
+static int dc_kbd_connect(struct maple_device *dev)
+{
+	int i;
+	unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
+	struct dc_kbd *kbd;
+
+	if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL)))
+		return -1;
+	memset(kbd, 0, sizeof(struct dc_kbd));
+
+	dev->private_data = kbd;
+
+	kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	for (i=0; i<255; i++)
+		set_bit(dc_kbd_keycode[i], kbd->dev.keybit);
+	clear_bit(0, kbd->dev.keybit);
+
+	kbd->dev.private = kbd;
+	kbd->dev.open = dc_kbd_open;
+	kbd->dev.close = dc_kbd_close;
+	kbd->dev.event = NULL;
+
+	kbd->dev.name = dev->product_name;
+	kbd->dev.idbus = BUS_MAPLE;
+	
+	input_register_device(&kbd->dev);
+
+	maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
+
+	printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n",
+	       kbd->dev.number, data, kbd->dev.name);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+
+static void dc_kbd_disconnect(struct maple_device *dev)
+{
+	struct dc_kbd *kbd = dev->private_data;
+
+	input_unregister_device(&kbd->dev);
+
+	kfree(kbd);
+
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct maple_driver dc_kbd_driver = {
+	function:	MAPLE_FUNC_KEYBOARD,
+	name:		"Dreamcast keyboard",
+	connect:	dc_kbd_connect,
+	disconnect:	dc_kbd_disconnect,
+};
+
+
+static int __init dc_kbd_init(void)
+{
+	maple_register_driver(&dc_kbd_driver);
+	return 0;
+}
+
+
+static void __exit dc_kbd_exit(void)
+{
+	maple_unregister_driver(&dc_kbd_driver);
+}
+
+
+module_init(dc_kbd_init);
+module_exit(dc_kbd_exit);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -Nru a/drivers/input/keyboard/ps2serkbd.c b/drivers/input/keyboard/ps2serkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/ps2serkbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,298 @@
+/*
+ * based on: sunkbd.c and ps2serkbd.c
+ *
+ * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $
+ */
+
+/*
+ * PS/2 keyboard via adapter at serial 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
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+#define ATKBD_CMD_SETLEDS	0x10ed
+#define ATKBD_CMD_GSCANSET	0x11f0
+#define ATKBD_CMD_SSCANSET	0x10f0
+#define ATKBD_CMD_GETID		0x02f2
+#define ATKBD_CMD_ENABLE	0x00f4
+#define ATKBD_CMD_RESET_DIS	0x00f5
+#define ATKBD_CMD_SETALL_MB	0x00f8
+#define ATKBD_CMD_EX_ENABLE	0x10ea
+#define ATKBD_CMD_EX_SETLEDS	0x20eb
+
+#define ATKBD_RET_ACK		0xfa
+#define ATKBD_RET_NAK		0xfe
+
+#define ATKBD_KEY_UNKNOWN	  0
+#define ATKBD_KEY_BAT		251
+#define ATKBD_KEY_EMUL0		252
+#define ATKBD_KEY_EMUL1		253
+#define ATKBD_KEY_RELEASE	254
+#define ATKBD_KEY_NULL		255
+
+static unsigned char ps2serkbd_set2_keycode[512] = {
+    0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
+    0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
+    0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
+    0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+    0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
+    122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
+    85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123,
+    82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+    252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
+    0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0,
+    136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125,
+    0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127,
+    159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142,
+    157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138,
+    0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0,
+    133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
+    110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119
+};
+
+/*
+ * Per-keyboard data.
+ */
+
+struct ps2serkbd {
+    unsigned char keycode[512];
+    struct input_dev dev;
+    struct serio *serio;
+    char name[64];
+    char phys[32];
+    struct tq_struct tq;
+    unsigned char cmdbuf[4];
+    unsigned char cmdcnt;
+    unsigned char set;
+    char release;
+    char ack;
+    char emul;
+    char error;
+    unsigned short id;
+};
+
+/*
+ * ps2serkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+    static int event_count=0;
+    struct ps2serkbd* ps2serkbd = serio->private;
+    int code=data;
+
+#if 0
+    printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data);
+#endif
+    event_count++;
+
+    switch (code) {
+    case ATKBD_RET_ACK:
+        ps2serkbd->ack = 1;
+        return;
+    case ATKBD_RET_NAK:
+        ps2serkbd->ack = -1;
+        return;
+    }
+
+    if (ps2serkbd->cmdcnt) {
+        ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code;
+        return;
+    }
+
+    switch (ps2serkbd->keycode[code]) {
+    case ATKBD_KEY_BAT:
+        queue_task(&ps2serkbd->tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+        return;
+    case ATKBD_KEY_EMUL0:
+        ps2serkbd->emul = 1;
+        return;
+    case ATKBD_KEY_EMUL1:
+        ps2serkbd->emul = 2;
+        return;
+    case ATKBD_KEY_RELEASE:
+        ps2serkbd->release = 1;
+        return;
+    }
+
+    if (ps2serkbd->emul) {
+        if (--ps2serkbd->emul) return;
+        code |= 0x100;
+    }
+
+    switch (ps2serkbd->keycode[code]) {
+    case ATKBD_KEY_NULL:
+        break;
+    case ATKBD_KEY_UNKNOWN:
+        printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n",
+        ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed");
+        break;
+    default:
+        input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release);
+    }
+
+    ps2serkbd->release = 0;
+}
+
+/*
+ * ps2serkbd_event() handles events from the input module.
+ */
+
+static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+    switch (type) {
+
+    case EV_LED:
+
+        return 0;
+    }
+
+    return -1;
+}
+
+static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd) 
+{
+    return 0;
+}
+
+static void ps2serkbd_reinit(void *data) 
+{
+}
+
+
+static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+    struct ps2serkbd *ps2serkbd;
+    int i;
+
+    if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+        return;
+
+    if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER)
+        return;
+
+
+    if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL)))
+        return;
+
+    memset(ps2serkbd, 0, sizeof(struct ps2serkbd));
+
+    ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+    ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+
+    ps2serkbd->serio = serio;
+
+    ps2serkbd->dev.keycode = ps2serkbd->keycode;
+    ps2serkbd->dev.event = ps2serkbd_event;
+    ps2serkbd->dev.private = ps2serkbd;
+
+    ps2serkbd->tq.routine = ps2serkbd_reinit;
+    ps2serkbd->tq.data = ps2serkbd;
+
+    serio->private = ps2serkbd;
+
+    if (serio_open(serio, dev)) {
+        kfree(ps2serkbd);
+        return;
+    }
+
+    if (ps2serkbd_initialize(ps2serkbd) < 0) {
+        serio_close(serio);
+        kfree(ps2serkbd);
+        return;
+    }
+
+    ps2serkbd->set = 4;
+
+    if (ps2serkbd->set == 4) {
+        ps2serkbd->dev.ledbit[0] |= 0;
+        sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n");
+    }
+    memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode));
+
+    sprintf(ps2serkbd->phys, "%s/input0", serio->phys);
+
+    ps2serkbd->dev.name = ps2serkbd->name;
+    ps2serkbd->dev.phys = ps2serkbd->phys;
+    ps2serkbd->dev.idbus = BUS_RS232; 
+    ps2serkbd->dev.idvendor = SERIO_PS2SER;
+    ps2serkbd->dev.idproduct = ps2serkbd->set;
+    ps2serkbd->dev.idversion = ps2serkbd->id;
+
+    for (i = 0; i < 512; i++)
+        if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250)
+            set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit);
+
+    input_register_device(&ps2serkbd->dev);
+}
+
+/*
+ * ps2serkbd_disconnect() unregisters and closes behind us.
+ */
+
+static void ps2serkbd_disconnect(struct serio *serio)
+{
+    struct ps2serkbd *ps2serkbd = serio->private;
+    input_unregister_device(&ps2serkbd->dev);
+    serio_close(serio);
+    kfree(ps2serkbd);
+}
+
+static struct serio_dev ps2serkbd_dev = {
+interrupt:
+    ps2serkbd_interrupt,
+connect:
+    ps2serkbd_connect,
+disconnect:
+    ps2serkbd_disconnect
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init ps2serkbd_init(void)
+{
+    serio_register_device(&ps2serkbd_dev);
+    return 0;
+}
+
+void __exit ps2serkbd_exit(void)
+{
+    serio_unregister_device(&ps2serkbd_dev);
+}
+
+module_init(ps2serkbd_init);
+module_exit(ps2serkbd_exit);
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/sunkbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,318 @@
+/*
+ * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * Sun keyboard 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Sun keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char sunkbd_keycode[128] = {
+	  0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,  0,
+	 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106,  1,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
+	116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+	 26, 27,111,127, 71, 72, 73, 74,134,135,107,  0, 29, 30, 31, 32,
+	 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
+	104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
+	 79, 80, 81,  0,  0,  0,138, 58,125, 57,126,109, 86, 78
+};
+
+#define SUNKBD_CMD_RESET	0x1
+#define SUNKBD_CMD_BELLON	0x2
+#define SUNKBD_CMD_BELLOFF	0x3
+#define SUNKBD_CMD_CLICK	0xa
+#define SUNKBD_CMD_NOCLICK	0xb
+#define SUNKBD_CMD_SETLED	0xe
+#define SUNKBD_CMD_LAYOUT	0xf
+
+#define SUNKBD_RET_RESET	0xff
+#define SUNKBD_RET_ALLUP	0x7f
+#define SUNKBD_RET_LAYOUT	0xfe
+
+#define SUNKBD_LAYOUT_5_MASK	0x20
+#define SUNKBD_RELEASE		0x80
+#define SUNKBD_KEY		0x7f
+
+/*
+ * Per-keyboard data.
+ */
+
+struct sunkbd {
+	unsigned char keycode[128];
+	struct input_dev dev;
+	struct serio *serio;
+	struct tq_struct tq;
+	char name[64];
+	char phys[32];
+	char type;
+	char reset;
+	char layout;
+};
+
+/*
+ * sunkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct sunkbd* sunkbd = serio->private;
+
+	if (sunkbd->reset <= -1) {		/* If cp[i] is 0xff, sunkbd->reset will stay -1. */
+		sunkbd->reset = data;		/* The keyboard sends 0xff 0xff 0xID on powerup */
+		return;
+	}
+
+	if (sunkbd->layout == -1) {
+		sunkbd->layout = data;
+		return;
+	}
+
+	switch (data) {
+
+		case SUNKBD_RET_RESET:
+			queue_task(&sunkbd->tq, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			sunkbd->reset = -1;
+			return;
+
+		case SUNKBD_RET_LAYOUT:
+			sunkbd->layout = -1;
+			return;
+
+		case SUNKBD_RET_ALLUP: /* All keys released */
+			return;
+
+		default:
+			if (sunkbd->keycode[data & SUNKBD_KEY]) {
+                                input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
+                        } else {
+                                printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
+                                        data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
+                        }
+	}
+}
+
+/*
+ * sunkbd_event() handles events from the input module.
+ */
+
+static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct sunkbd *sunkbd = dev->private;
+
+	switch (type) {
+
+		case EV_LED:
+
+			sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
+			sunkbd->serio->write(sunkbd->serio, 
+				(!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
+				(!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
+			return 0;
+
+		case EV_SND:
+
+			switch (code) {
+
+				case SND_CLICK:
+					sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
+					return 0;
+	
+				case SND_BELL:
+					sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
+					return 0;
+			}
+
+			break;
+	}
+
+	return -1;
+}
+
+/*
+ * sunkbd_initialize() checks for a Sun keyboard attached, and determines
+ * its type.
+ */
+
+static int sunkbd_initialize(struct sunkbd *sunkbd)
+{
+	int t;
+
+	t = 1000;
+	sunkbd->reset = -2;
+	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
+	while (sunkbd->reset < 0 && --t) mdelay(1);
+	if (!t) return -1;
+
+	sunkbd->type = sunkbd->reset;
+
+	if (sunkbd->type == 4) {	/* Type 4 keyboard */
+		t = 250;
+		sunkbd->layout = -2;
+		sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
+		while (sunkbd->layout < 0 && --t) mdelay(1);
+		if (!t) return -1;
+		if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
+	}
+
+	return 0;
+}
+
+/*
+ * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
+ * were in.
+ */
+
+static void sunkbd_reinit(void *data)
+{
+	struct sunkbd *sunkbd = data;
+	int t = 1000;
+
+	while (sunkbd->reset < 0 && --t) mdelay(1);
+
+	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
+	sunkbd->serio->write(sunkbd->serio, 
+		(!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) |
+		(!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led));
+	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd));
+	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd));
+}
+
+/*
+ * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
+ */
+
+static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct sunkbd *sunkbd;
+	int i;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+		return;
+
+	if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
+		return;
+	
+	if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
+		return;
+
+	memset(sunkbd, 0, sizeof(struct sunkbd));
+
+	sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
+	sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
+	sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL);
+
+	sunkbd->serio = serio;
+
+	sunkbd->tq.routine = sunkbd_reinit;
+	sunkbd->tq.data = sunkbd;
+
+	sunkbd->dev.keycode = sunkbd->keycode;
+	sunkbd->dev.event = sunkbd_event;
+	sunkbd->dev.private = sunkbd;
+
+	serio->private = sunkbd;
+
+	if (serio_open(serio, dev)) {
+		kfree(sunkbd);
+		return;
+	}
+
+	if (sunkbd_initialize(sunkbd) < 0) {
+		serio_close(serio);
+		kfree(sunkbd);
+		return;
+	}
+
+	sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
+
+	memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
+	for (i = 0; i < 255; i++)
+		set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
+	clear_bit(0, sunkbd->dev.keybit);
+
+	sprintf(sunkbd->name, "%s/input", serio->phys);
+
+	sunkbd->dev.name = sunkbd->name;
+	sunkbd->dev.phys = sunkbd->phys;
+	sunkbd->dev.idbus = BUS_RS232;
+	sunkbd->dev.idvendor = SERIO_SUNKBD;
+	sunkbd->dev.idproduct = sunkbd->type;
+	sunkbd->dev.idversion = 0x0100;
+
+	input_register_device(&sunkbd->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys);
+}
+
+/*
+ * sunkbd_disconnect() unregisters and closes behind us.
+ */
+
+static void sunkbd_disconnect(struct serio *serio)
+{
+	struct sunkbd *sunkbd = serio->private;
+	input_unregister_device(&sunkbd->dev);
+	serio_close(serio);
+	kfree(sunkbd);
+}
+
+static struct serio_dev sunkbd_dev = {
+	interrupt:	sunkbd_interrupt,
+	connect:	sunkbd_connect,
+	disconnect:	sunkbd_disconnect
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init sunkbd_init(void)
+{
+	serio_register_device(&sunkbd_dev);
+	return 0;
+}
+
+void __exit sunkbd_exit(void)
+{
+	serio_unregister_device(&sunkbd_dev);
+}
+
+module_init(sunkbd_init);
+module_exit(sunkbd_exit);
diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/xtkbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,157 @@
+/*
+ * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * XT keyboard 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("XT keyboard driver");
+MODULE_LICENSE("GPL");
+
+#define XTKBD_EMUL0	0xe0
+#define XTKBD_EMUL1	0xe1
+#define XTKBD_KEY	0x7f
+#define XTKBD_RELEASE	0x80
+
+static unsigned char xtkbd_keycode[256] = {	 
+	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+	 80, 81, 82, 83,  0,  0,  0, 87, 88,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0, 87, 88,  0,  0,  0,  0,110,111,103,108,105,
+	106
+};
+
+static char *xtkbd_name = "XT Keyboard";
+
+struct xtkbd {
+	unsigned char keycode[256];
+	struct input_dev dev;
+	struct serio *serio;
+	char phys[32];
+};
+
+void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct xtkbd *xtkbd = serio->private;
+
+	switch (data) {
+		case XTKBD_EMUL0:
+		case XTKBD_EMUL1:
+			return;
+		default:
+
+			if (xtkbd->keycode[data & XTKBD_KEY]) {
+				input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
+			} else {
+				printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n",
+					data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed");
+			}
+		}
+}
+
+void xtkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct xtkbd *xtkbd;
+	int i;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_XT)
+		return;
+
+	if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL)))
+		return;
+
+	memset(xtkbd, 0, sizeof(struct xtkbd));
+	
+	xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+	xtkbd->serio = serio;
+
+	xtkbd->dev.keycode = xtkbd->keycode;
+	xtkbd->dev.private = xtkbd;
+
+	serio->private = xtkbd;
+
+	if (serio_open(serio, dev)) {
+		kfree(xtkbd);
+		return;
+	}
+
+	memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
+	for (i = 0; i < 255; i++)
+		set_bit(xtkbd->keycode[i], xtkbd->dev.keybit);
+	clear_bit(0, xtkbd->dev.keybit);
+
+	sprintf(xtkbd->phys, "%s/input0", serio->phys);
+
+	xtkbd->dev.name = xtkbd_name;
+	xtkbd->dev.phys = xtkbd->phys;
+	xtkbd->dev.idbus = BUS_XTKBD;
+	xtkbd->dev.idvendor = 0x0001;
+	xtkbd->dev.idproduct = 0x0001;
+	xtkbd->dev.idversion = 0x0100;
+
+	input_register_device(&xtkbd->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys);
+}
+
+void xtkbd_disconnect(struct serio *serio)
+{
+	struct xtkbd *xtkbd = serio->private;
+	input_unregister_device(&xtkbd->dev);
+	serio_close(serio);
+	kfree(xtkbd);
+}
+
+struct serio_dev xtkbd_dev = {
+	interrupt:	xtkbd_interrupt,
+	connect:	xtkbd_connect,
+	disconnect:	xtkbd_disconnect
+};
+
+int __init xtkbd_init(void)
+{
+	serio_register_device(&xtkbd_dev);
+	return 0;
+}
+
+void __exit xtkbd_exit(void)
+{
+	serio_unregister_device(&xtkbd_dev);
+}
+
+module_init(xtkbd_init);
+module_exit(xtkbd_exit);
diff -Nru a/drivers/input/mouse/Config.help b/drivers/input/mouse/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/Config.help	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,87 @@
+CONFIG_INPUT_MOUSE
+  Say Y here, and a list of supported mice will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_MOUSE_PS2
+  Say Y here if you have a PS/2 mouse connected to your system. This
+  includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
+  mice with wheels and extra buttons, Microsoft, Logitech or Genius
+  compatible.
+
+  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 psmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_SERIAL
+  Say Y here if you have a serial (RS-232, COM port) mouse connected
+  to your system. This includes Sun, MouseSystems, Microsoft,
+  Logitech and all other compatible serial mice.
+
+  If unsure, say N.
+
+  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 sermouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_INPORT
+  Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
+  They are rather rare these days.
+
+  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 inport.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ATIXL
+  Say Y here if your mouse is of the ATI XL variety.
+
+CONFIG_MOUSE_LOGIBM
+  Say Y here if you have a Logitech busmouse.
+  They are rather rare these days.
+
+  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 logibm.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_PC110PAD
+  Say Y if you have the IBM PC-110 micro-notebook and want its
+  touchscreen supported.
+
+  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 pc110pad.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_MAPLE
+  Say Y if you have a DreamCast console and a mouse attached to
+  its Maple bus.
+
+  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 maplemouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_AMIGA
+  Say Y here if you have an Amiga and want its native mouse
+  supported by the kernel.
+
+  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 amimouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ACORN
+  Say Y here if you have the Acorn RiscPC computer and want its
+  native mouse supported.
+
+  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 rpcmouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
diff -Nru a/drivers/input/mouse/Config.in b/drivers/input/mouse/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/Config.in	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,24 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Mice' CONFIG_INPUT_MOUSE
+
+dep_tristate '  PS/2 mouse' CONFIG_MOUSE_PS2 $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+dep_tristate '  Serial mouse' CONFIG_MOUSE_SERIAL $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+
+dep_tristate '  InPort/MS/ATIXL busmouse' CONFIG_MOUSE_INPORT $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_MOUSE_INPORT" != "n" ]; then
+   bool '  ATI XL variant' CONFIG_MOUSE_ATIXL
+fi
+dep_tristate '  Logitech busmouse' CONFIG_MOUSE_LOGIBM $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+dep_tristate '  IBM PC110 touchpad' CONFIG_MOUSE_PC110PAD $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+  dep_tristate '  Maple bus mouse' CONFIG_MOUSE_MAPLE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_MAPLE
+fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate '  Amiga mouse' CONFIG_MOUSE_AMIGA $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+   dep_tristate '  Acorn RiscPC mouse' CONFIG_MOUSE_ACORN $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/Makefile	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,18 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_MOUSE_AMIGA)	+= amimouse.o
+obj-$(CONFIG_MOUSE_ACORN)	+= rpcmouse.o
+obj-$(CONFIG_MOUSE_INPORT)	+= inport.o
+obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
+obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.o
+obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
+obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
+obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/amimouse.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,147 @@
+/*
+ * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Michael Rausch		James Banks
+ *	Matther Dillon		David Giller
+ *	Nathan Laredo		Linus Torvalds
+ *	Johan Myreen		Jes Sorensen
+ *	Russel King
+ */
+
+/*
+ * Amiga mouse driver 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Amiga mouse driver");
+MODULE_LICENSE("GPL");
+
+static int amimouse_used = 0;
+static int amimouse_lastx, amimouse_lasty;
+static struct input_dev amimouse_dev;
+
+static char *amimouse_name = "Amiga mouse";
+static char *amimouse_phys = "amimouse/input0";
+
+static void amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned short joy0dat, potgor;
+	int nx, ny, dx, dy;
+
+	joy0dat = custom.joy0dat;
+
+	nx = joy0dat & 0xff;
+	ny = joy0dat >> 8;
+
+	dx = nx - amimouse_lastx;
+	dy = ny - amimouse_lasty;
+
+	if (dx < -127) dx = (256 + nx) - lastx;
+	if (dx >  127) dx = (nx - 256) - lastx;
+	if (dy < -127) dy = (256 + ny) - lasty;
+	if (dy >  127) dy = (ny - 256) - lasty;
+
+	amimouse_lastx = nx;
+	amimouse_lasty = ny;
+
+	potgor = custom.potgor;
+
+	input_report_rel(&amimouse_dev, REL_X, dx);
+	input_report_rel(&amimouse_dev, REL_Y, dy);
+	
+	input_report_key(&amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
+	input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
+	input_report_key(&amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
+}
+
+static int amimouse_open(struct input_dev *dev)
+{
+	unsigned short joy0dat;
+
+        if (amimouse_used++)
+                return 0;
+
+	joy0dat = custom.joy0dat;
+
+	amimouse_lastx = joy0dat & 0xff;
+	amimouse_lasty = joy0dat >> 8;
+
+	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", NULL)) {
+                amimouse_used--;
+                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq);
+                return -EBUSY;
+        }
+
+        return 0;
+}
+
+static void amimouse_close(struct input_dev *dev)
+{
+        if (!--amimouse_used)
+		free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+}
+
+static int __init amimouse_init(void)
+{
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
+		return -ENODEV;
+
+	amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	amimouse_dev.open = amimouse_open;
+	amimouse_dev.close = amimouse_close;
+
+	amimouse_dev.name = amimouse_name;
+	amimouse_dev.phys = amimouse_phys;
+	amimouse_dev.idbus = BUS_AMIGA;
+	amimouse_dev.idvendor = 0x0001;
+	amimouse_dev.idproduct = 0x0002;
+	amimouse_dev.idversion = 0x0100;
+        
+	input_register_device(&amimouse_dev);
+
+        printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
+}
+
+static void __exit amimouse_exit(void)
+{
+        input_unregister_device(&amimouse_dev);
+}
+
+module_init(amimouse_init);
+module_exit(amimouse_exit);
diff -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/inport.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,193 @@
+/*
+ * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Teemu Rantanen		Derrick Cole
+ *	Peter Cervasio		Christoph Niemann
+ *	Philip Blundell		Russell King
+ *	Bob Harris
+ */
+
+/*
+ * Inport (ATI XL and Microsoft) busmouse 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
+MODULE_LICENSE("GPL");
+
+#define INPORT_BASE		0x23c
+#define INPORT_EXTENT		4
+
+#define INPORT_CONTROL_PORT	INPORT_BASE + 0
+#define INPORT_DATA_PORT	INPORT_BASE + 1
+#define INPORT_SIGNATURE_PORT	INPORT_BASE + 2
+
+#define INPORT_REG_BTNS	0x00
+#define INPORT_REG_X		0x01
+#define INPORT_REG_Y		0x02
+#define INPORT_REG_MODE		0x07
+#define INPORT_RESET		0x80
+
+#ifdef CONFIG_INPUT_ATIXL
+#define INPORT_NAME		"ATI XL Mouse"
+#define INPORT_VENDOR		0x0002
+#define INPORT_SPEED_30HZ	0x01
+#define INPORT_SPEED_50HZ	0x02
+#define INPORT_SPEED_100HZ	0x03
+#define INPORT_SPEED_200HZ	0x04
+#define INPORT_MODE_BASE	INPORT_SPEED_100HZ
+#define INPORT_MODE_IRQ		0x08
+#else
+#define INPORT_NAME		"Microsoft InPort Mouse"
+#define INPORT_VENDOR		0x0001
+#define INPORT_MODE_BASE	0x10
+#define INPORT_MODE_IRQ		0x01
+#endif
+#define INPORT_MODE_HOLD	0x20
+
+#define INPORT_IRQ		5
+
+MODULE_PARM(inport_irq, "i");
+
+static int inport_irq = INPORT_IRQ;
+static int inport_used = 0;
+
+static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int inport_open(struct input_dev *dev)
+{
+	if (!inport_used++) {
+		if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+			return -EBUSY;
+		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+		outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+	}
+
+	return 0;
+}
+
+static void inport_close(struct input_dev *dev)
+{
+	if (!--inport_used) {
+		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+		outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+		free_irq(inport_irq, NULL);
+	}
+}
+
+static struct input_dev inport_dev = {
+	evbit:		{ BIT(EV_KEY) | BIT(EV_REL) },
+	keybit: 	{ [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+	relbit:		{ BIT(REL_X) | BIT(REL_Y) },
+	open:		inport_open,
+	close:		inport_close,
+	name:		INPORT_NAME,
+	phys:		"isa023c/input0",
+	idbus:		BUS_ISA,
+	idvendor:	INPORT_VENDOR,
+	idproduct:	0x0001,
+	idversion:	0x0100,
+};
+
+static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned char buttons;
+
+	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+	outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+	outb(INPORT_REG_X, INPORT_CONTROL_PORT);
+	input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT));
+
+	outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
+	input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT));
+
+	outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
+	buttons = inb(INPORT_DATA_PORT);
+
+	input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1);
+	input_report_key(&inport_dev, BTN_LEFT,   buttons & 2);
+	input_report_key(&inport_dev, BTN_RIGHT,  buttons & 4);
+
+	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+}
+
+#ifndef MODULE
+static int __init inport_setup(char *str)
+{
+        int ints[4];
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+        if (ints[0] > 0) inport_irq = ints[1];
+        return 1;
+}
+__setup("inport_irq=", inport_setup);
+#endif
+
+static int __init inport_init(void)
+{
+	unsigned char a,b,c;
+
+	if (check_region(INPORT_BASE, INPORT_EXTENT))
+		return -EBUSY;
+
+	a = inb(INPORT_SIGNATURE_PORT);
+	b = inb(INPORT_SIGNATURE_PORT);
+	c = inb(INPORT_SIGNATURE_PORT);
+	if (( a == b ) || ( a != c ))
+		return -ENODEV;
+
+	outb(INPORT_RESET, INPORT_CONTROL_PORT);
+	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+	request_region(INPORT_BASE, INPORT_EXTENT, "inport");
+
+	input_register_device(&inport_dev);
+
+	printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n",
+		INPORT_BASE, inport_irq);
+
+	return 0;
+}
+
+static void __exit inport_exit(void)
+{
+	input_unregister_device(&inport_dev);
+	release_region(INPORT_BASE, INPORT_EXTENT);
+}
+
+module_init(inport_init);
+module_exit(inport_exit);
diff -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/logibm.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,182 @@
+/*
+ * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	James Banks		Matthew Dillon
+ *	David Giller		Nathan Laredo
+ *	Linus Torvalds		Johan Myreen
+ *	Cliff Matthews		Philip Blundell
+ *	Russell King
+ */
+
+/*
+ * Logitech Bus Mouse 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Logitech busmouse driver");
+MODULE_LICENSE("GPL");
+
+#define	LOGIBM_BASE		0x23c
+#define	LOGIBM_EXTENT		4
+
+#define	LOGIBM_DATA_PORT	LOGIBM_BASE + 0
+#define	LOGIBM_SIGNATURE_PORT	LOGIBM_BASE + 1
+#define	LOGIBM_CONTROL_PORT	LOGIBM_BASE + 2
+#define	LOGIBM_CONFIG_PORT	LOGIBM_BASE + 3
+
+#define	LOGIBM_ENABLE_IRQ	0x00
+#define	LOGIBM_DISABLE_IRQ	0x10
+#define	LOGIBM_READ_X_LOW	0x80
+#define	LOGIBM_READ_X_HIGH	0xa0
+#define	LOGIBM_READ_Y_LOW	0xc0
+#define	LOGIBM_READ_Y_HIGH	0xe0
+
+#define LOGIBM_DEFAULT_MODE	0x90
+#define LOGIBM_CONFIG_BYTE	0x91
+#define LOGIBM_SIGNATURE_BYTE	0xa5
+
+#define LOGIBM_IRQ		5
+
+MODULE_PARM(logibm_irq, "i");
+
+static int logibm_irq = LOGIBM_IRQ;
+static int logibm_used = 0;
+
+static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int logibm_open(struct input_dev *dev)
+{
+	if (logibm_used++)
+		return 0;
+	if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
+		logibm_used--;
+		printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
+		return -EBUSY;
+	}
+	outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
+	return 0;
+}
+
+static void logibm_close(struct input_dev *dev)
+{
+	if (--logibm_used)
+		return;
+	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
+	free_irq(logibm_irq, NULL);
+}
+
+static struct input_dev logibm_dev = {
+	evbit:		{ BIT(EV_KEY) | BIT(EV_REL) },
+	keybit: 	{ [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+	relbit:		{ BIT(REL_X) | BIT(REL_Y) },
+	open:		logibm_open,
+	close:		logibm_close,
+	name:		"Logitech bus mouse",
+	phys:		"isa023c/input0",
+	idbus:		BUS_ISA,
+	idvendor:	0x0003,
+	idproduct:	0x0001,
+	idversion:	0x0100,
+};
+
+static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	char dx, dy;
+	unsigned char buttons;
+
+	outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
+	dx = (inb(LOGIBM_DATA_PORT) & 0xf);
+	outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
+	dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
+	outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
+	dy = (inb(LOGIBM_DATA_PORT) & 0xf);
+	outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
+	buttons = inb(LOGIBM_DATA_PORT);
+	dy |= (buttons & 0xf) << 4;
+	buttons = ~buttons;
+
+	input_report_rel(&logibm_dev, REL_X, dx);
+	input_report_rel(&logibm_dev, REL_Y, 255 - dy);
+	input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1);
+	input_report_key(&logibm_dev, BTN_LEFT,   buttons & 2);
+	input_report_key(&logibm_dev, BTN_RIGHT,  buttons & 4);
+}
+
+#ifndef MODULE
+static int __init logibm_setup(char *str)
+{
+        int ints[4];
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+        if (ints[0] > 0) logibm_irq = ints[1];
+        return 1;
+}
+__setup("logibm_irq=", logibm_setup);
+#endif
+
+static int __init logibm_init(void)
+{
+	if (request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
+		printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
+		return -EBUSY;
+	}
+
+	outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT);
+	outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT);
+	udelay(100);
+
+	if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
+		release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+		printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
+		return -ENODEV;
+	}
+
+	outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
+	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
+
+	input_register_device(&logibm_dev);
+
+	printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
+
+	return 0;
+}
+
+static void __exit logibm_exit(void)
+{
+	input_unregister_device(&logibm_dev);
+	release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+}
+
+module_init(logibm_init);
+module_exit(logibm_exit);
diff -Nru a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/maplemouse.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,137 @@
+/*
+ *	$Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ * 	SEGA Dreamcast mouse driver
+ *	Based on drivers/usb/usbmouse.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+
+MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
+MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
+
+struct dc_mouse {
+	struct input_dev dev;
+	int open;
+};
+
+
+static void dc_mouse_callback(struct mapleq *mq)
+{
+	int buttons, relx, rely, relz;
+	struct maple_device *mapledev = mq->dev;
+	struct dc_mouse *mouse = mapledev->private_data;
+	struct input_dev *dev = &mouse->dev;
+	unsigned char *res = mq->recvbuf;
+
+	buttons = ~res[8];
+	relx=*(unsigned short *)(res+12)-512;
+	rely=*(unsigned short *)(res+14)-512;
+	relz=*(unsigned short *)(res+16)-512;
+
+	input_report_key(dev, BTN_LEFT,   buttons&4);
+	input_report_key(dev, BTN_MIDDLE, buttons&9);
+	input_report_key(dev, BTN_RIGHT,  buttons&2);
+	input_report_rel(dev, REL_X,      relx);
+	input_report_rel(dev, REL_Y,      rely);
+	input_report_rel(dev, REL_WHEEL,  relz);
+}
+
+
+static int dc_mouse_open(struct input_dev *dev)
+{
+	struct dc_mouse *mouse = dev->private;
+	mouse->open++;
+	return 0;
+}
+
+
+static void dc_mouse_close(struct input_dev *dev)
+{
+	struct dc_mouse *mouse = dev->private;
+	mouse->open--;
+}
+
+
+static int dc_mouse_connect(struct maple_device *dev)
+{
+	unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
+	struct dc_mouse *mouse;
+
+	if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+		return -1;
+	memset(mouse, 0, sizeof(struct dc_mouse));
+
+	dev->private_data = mouse;
+
+	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+
+	mouse->dev.private = mouse;
+	mouse->dev.open = dc_mouse_open;
+	mouse->dev.close = dc_mouse_close;
+	mouse->dev.event = NULL;
+
+	mouse->dev.name = dev->product_name;
+	mouse->dev.idbus = BUS_MAPLE;
+	
+	input_register_device(&mouse->dev);
+
+	maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
+
+	printk(KERN_INFO "input%d: mouse(0x%lx): %s\n",
+	       mouse->dev.number, data, mouse->dev.name);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+
+static void dc_mouse_disconnect(struct maple_device *dev)
+{
+	struct dc_mouse *mouse = dev->private_data;
+
+	input_unregister_device(&mouse->dev);
+
+	kfree(mouse);
+
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct maple_driver dc_mouse_driver = {
+	function:	MAPLE_FUNC_MOUSE,
+	name:		"Dreamcast mouse",
+	connect:	dc_mouse_connect,
+	disconnect:	dc_mouse_disconnect,
+};
+
+
+static int __init dc_mouse_init(void)
+{
+	maple_register_driver(&dc_mouse_driver);
+	return 0;
+}
+
+
+static void __exit dc_mouse_exit(void)
+{
+	maple_unregister_driver(&dc_mouse_driver);
+}
+
+
+module_init(dc_mouse_init);
+module_exit(dc_mouse_exit);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -Nru a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/pc110pad.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,163 @@
+/*
+ * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Alan Cox	Robin O'Leary	
+ */
+
+/*
+ * IBM PC110 touchpad 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/input.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("IBM PC110 touchpad driver");
+MODULE_LICENSE("GPL");
+
+#define PC110PAD_OFF	0x30
+#define PC110PAD_ON	0x38
+
+static int pc110pad_irq = 10;
+static int pc110pad_io = 0x15e0;
+
+static struct input_dev pc110pad_dev;
+static int pc110pad_data[3];
+static int pc110pad_count;
+static int pc110pad_used;
+
+static char *pc110pad_name = "IBM PC110 TouchPad";
+static char *pc110pad_phys = "isa15e0/input0";
+
+static void pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	int value     = inb_p(pc110pad_io);
+	int handshake = inb_p(pc110pad_io + 2);
+
+	outb_p(handshake |  1, pc110pad_io + 2);
+	outb_p(handshake & ~1, pc110pad_io + 2);
+	inb_p(0x64);
+
+	pc110pad_data[pc110pad_count++] = value;
+
+	if (pc110pad_count < 3) return;
+	
+	input_report_key(&pc110pad_dev, BTN_TOUCH,
+		pc110pad_data[0] & 0x01);
+	input_report_abs(&pc110pad_dev, ABS_X,
+		pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
+	input_report_abs(&pc110pad_dev, ABS_Y,
+		pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
+
+	pc110pad_count = 0;
+}
+
+static void pc110pad_close(struct input_dev *dev)
+{
+	if (!--pc110pad_used)
+		outb(PC110PAD_OFF, pc110pad_io + 2);
+}
+
+static int pc110pad_open(struct input_dev *dev)
+{
+	unsigned long flags;
+	
+	if (pc110pad_used++)
+		return 0;
+
+	save_flags(flags);
+	cli();
+	pc110pad_interrupt(0,0,0);
+	pc110pad_interrupt(0,0,0);
+	pc110pad_interrupt(0,0,0);
+	outb(PC110PAD_ON, pc110pad_io + 2);
+	pc110pad_count = 0;
+	restore_flags(flags);
+
+	return 0;
+}
+
+static int __init pc110pad_init(void)
+{
+	if (request_region(pc110pad_io, 4, "pc110pad"))
+	{
+		printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4);
+		return -EBUSY;
+	}
+
+	outb(PC110PAD_OFF, pc110pad_io + 2);
+
+	if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", 0))
+	{
+		release_region(pc110pad_io, 4);
+		printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
+		return -EBUSY;
+	}
+
+        pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+        pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+        pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	pc110pad_dev.absmax[ABS_X] = 0x1ff;
+	pc110pad_dev.absmax[ABS_Y] = 0x0ff;
+        
+	pc110pad_dev.open = pc110pad_open;
+        pc110pad_dev.close = pc110pad_close;
+
+	pc110pad_dev.name = pc110pad_name;
+	pc110pad_dev.phys = pc110pad_phys;
+	pc110pad_dev.idbus = BUS_ISA;
+	pc110pad_dev.idvendor = 0x0003;
+	pc110pad_dev.idproduct = 0x0001;
+	pc110pad_dev.idversion = 0x0100;
+
+	input_register_device(&pc110pad_dev);	
+
+	printk(KERN_INFO "input: %s at %#x irq %d\n",
+		pc110pad_name, pc110pad_io, pc110pad_irq);
+	
+	return 0;
+}
+ 
+static void __exit pc110pad_exit(void)
+{
+	input_unregister_device(&pc110pad_dev);	
+
+	outb(PC110PAD_OFF, pc110pad_io + 2);
+
+	free_irq(pc110pad_irq, 0);
+	release_region(pc110pad_io, 4);
+}
+
+module_init(pc110pad_init);
+module_exit(pc110pad_exit);
diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/psmouse.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,652 @@
+/*
+ * $Id: psmouse.c,v 1.18 2002/03/13 10:03:43 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PS/2 mouse driver");
+MODULE_LICENSE("GPL");
+
+#define PSMOUSE_CMD_SETSCALE11	0x00e6
+#define PSMOUSE_CMD_SETRES	0x10e8
+#define PSMOUSE_CMD_GETINFO	0x03e9
+#define PSMOUSE_CMD_SETSTREAM	0x00ea
+#define PSMOUSE_CMD_POLL	0x03eb	
+#define PSMOUSE_CMD_GETID	0x01f2
+#define PSMOUSE_CMD_SETRATE	0x10f3
+#define PSMOUSE_CMD_ENABLE	0x00f4
+#define PSMOUSE_CMD_RESET_DIS	0x00f6
+
+#define PSMOUSE_RET_BAT		0xaa
+#define PSMOUSE_RET_ACK		0xfa
+#define PSMOUSE_RET_NAK		0xfe
+
+struct psmouse {
+	struct input_dev dev;
+	struct serio *serio;
+	char *vendor;
+	char *name;
+	struct tq_struct tq;
+	unsigned char cmdbuf[8];
+	unsigned char packet[8];
+	unsigned char cmdcnt;
+	unsigned char pktcnt;
+	unsigned char type;
+	unsigned long last;
+	char acking;
+	char ack;
+	char error;
+	char devname[64];
+	char phys[32];
+};
+
+#define PSMOUSE_PS2	1
+#define PSMOUSE_PS2PP	2
+#define PSMOUSE_PS2TPP	3
+#define PSMOUSE_GENPS	4
+#define PSMOUSE_IMPS	5
+#define PSMOUSE_IMEX	6
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+
+/*
+ * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
+ * reports relevant events to the input module.
+ */
+
+static void psmouse_process_packet(struct psmouse *psmouse)
+{
+	struct input_dev *dev = &psmouse->dev;
+	unsigned char *packet = psmouse->packet;
+
+/*
+ * The PS2++ protocol is a little bit complex
+ */
+
+	if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) {
+
+		if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) {
+
+			switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) {
+
+			case 1: /* Mouse extra info */
+
+				input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
+					(int) (packet[2] & 7) - (int) (packet[2] & 8));
+				input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
+				input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
+					
+				break;
+
+			case 3: /* TouchPad extra info */
+
+				input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
+					(int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8));
+				packet[0] = packet[2] | 0x08;
+
+				break;
+
+			default:
+
+				printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
+					((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0));
+
+			}
+
+		packet[0] &= 0x0f;
+		packet[1] = 0;
+		packet[2] = 0;
+
+		}
+	}
+
+/*
+ * Scroll wheel on IntelliMice, scroll buttons on NetMice
+ */
+
+	if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
+		input_report_rel(dev, REL_WHEEL, (signed char) packet[3]);
+
+/*
+ * Scroll wheel and buttons on IntelliMouse Explorer
+ */
+
+	if (psmouse->type == PSMOUSE_IMEX) {
+		input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 7) - (int) (packet[2] & 8));
+		input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+		input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+	}
+
+/*
+ * Extra buttons on Genius NewNet 3D
+ */
+
+	if (psmouse->type == PSMOUSE_GENPS) {
+		input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
+		input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
+	}
+
+/*
+ * Generic PS/2 Mouse
+ */
+
+	input_report_key(dev, BTN_LEFT,    packet[0]       & 1);
+	input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+	input_report_key(dev, BTN_RIGHT,  (packet[0] >> 1) & 1);
+
+	input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
+	input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+
+}
+
+/*
+ * psmouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct psmouse *psmouse = serio->private;
+
+	if (psmouse->acking) {
+		switch (data) {
+			case PSMOUSE_RET_ACK:
+				psmouse->ack = 1;
+				break;
+			case PSMOUSE_RET_NAK:
+				psmouse->ack = -1;
+				break;
+			default:
+				psmouse->ack = 1;	/* Workaround for mice which don't ACK the Get ID command */
+				if (psmouse->cmdcnt)
+					psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+				break;
+		}
+		psmouse->acking = 0;
+		return;
+	}
+
+	if (psmouse->cmdcnt) {
+		psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+		return;
+	}
+
+	if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/20)) {
+		printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+		psmouse->pktcnt = 0;
+	}
+	
+	psmouse->last = jiffies;
+	psmouse->packet[psmouse->pktcnt++] = data;
+
+	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+		if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse);
+		psmouse->pktcnt = 0;
+		return;
+	}
+
+	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
+		queue_task(&psmouse->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		return;
+	}	
+}
+
+/*
+ * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because when there would
+ * be need for retransmissions, the mouse has to be replaced anyway.
+ */
+
+static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
+{
+	int timeout = 10000; /* 100 msec */
+	psmouse->ack = 0;
+	psmouse->acking = 1;
+
+	serio_write(psmouse->serio, byte);
+	while (!psmouse->ack && timeout--) udelay(10);
+
+	return -(psmouse->ack <= 0);
+}
+
+/*
+ * psmouse_command() sends a command and its parameters to the mouse,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+	int timeout = 500000; /* 500 msec */
+	int send = (command >> 12) & 0xf;
+	int receive = (command >> 8) & 0xf;
+	int i;
+
+	psmouse->cmdcnt = receive;
+
+	if (command & 0xff)
+		if (psmouse_sendbyte(psmouse, command & 0xff))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	for (i = 0; i < send; i++)
+		if (psmouse_sendbyte(psmouse, param[i]))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	while (psmouse->cmdcnt && timeout--) udelay(1);
+
+	for (i = 0; i < receive; i++)
+		param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+	if (psmouse->cmdcnt) 
+		return (psmouse->cmdcnt = 0) - 1;
+
+	return 0;
+}
+
+/*
+ * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit
+ * pieces through the SETRES command. This is needed to send extended
+ * commands to mice on notebooks that try to understand the PS/2 protocol
+ * Ugly.
+ */
+
+static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
+{
+	unsigned char d;
+	int i;
+
+	if (psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		d = (command >> i) & 3;
+		if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
+ * the mouse may have.
+ */
+
+static int psmouse_extensions(struct psmouse *psmouse)
+{
+	unsigned char param[4];
+
+	param[0] = 0;
+	psmouse->vendor = "Generic";
+	psmouse->name = "Mouse";
+
+/*
+ * Try Genius NetMouse magic init.
+ */
+
+	param[0] = 3;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+	if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) {
+		psmouse->vendor = "Genius";
+		psmouse->name = "Mouse";
+
+		set_bit(BTN_EXTRA, psmouse->dev.keybit);
+		set_bit(BTN_SIDE, psmouse->dev.keybit);
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+		return PSMOUSE_GENPS;
+	}
+
+/*
+ * Try Logitech magic ID.
+ */
+
+	param[0] = 0;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+	if (param[1]) {
+
+		int i;
+		static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 };
+		static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 };
+		static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
+							76, 80, 81, 83, 88, 96, 97, -1 };
+
+		int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+
+		psmouse->vendor = "Logitech";
+		psmouse->name = "Mouse";
+
+		if (param[1] < 3)
+			clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
+		if (param[1] < 2)
+			clear_bit(BTN_RIGHT, psmouse->dev.keybit);
+
+		psmouse->type = PSMOUSE_PS2;
+
+		for (i = 0; logitech_ps2pp[i] != -1; i++)
+			if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP;
+
+		if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2;
+
+		for (i = 0; logitech_4btn[i] != -1; i++)
+			if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit);
+
+		for (i = 0; logitech_wheel[i] != -1; i++)
+			if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Do Logitech PS2++ / PS2T++ magic init.
+ */
+
+		if (devicetype == 97) { /* TouchPad 3 */
+
+			set_bit(REL_WHEEL, psmouse->dev.relbit);
+			set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+			param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
+			psmouse_command(psmouse, param, 0x30d1);
+			param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
+			psmouse_command(psmouse, param, 0x30d1);
+			param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
+			psmouse_command(psmouse, param, 0x30d1);
+
+			param[0] = 0;
+			if (!psmouse_command(psmouse, param, 0x13d1) &&
+				param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14)
+				return PSMOUSE_PS2TPP;
+
+		} else {
+			psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
+			psmouse_ps2pp_cmd(psmouse, param, 0xDB);
+
+			if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
+				(param[2] & 3) == ((param[1] >> 2) & 3))
+					return PSMOUSE_PS2PP;
+		}
+
+	}
+
+/*
+ * Try IntelliMouse magic init.
+ */
+
+	param[0] = 200;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	param[0] = 100;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  80;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+	
+	if (param[0] == 3) {
+
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Try IntelliMouse Explorer magic init.
+ */
+
+		param[0] = 200;
+		psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+		param[0] = 200;
+		psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+		param[0] =  80;
+		psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+		psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+
+		if (param[0] == 4) {
+
+			psmouse->vendor = "Microsoft";
+			psmouse->name = "IntelliMouse Explorer";
+
+			set_bit(BTN_SIDE, psmouse->dev.keybit);
+			set_bit(BTN_EXTRA, psmouse->dev.keybit);
+
+			return PSMOUSE_IMEX;
+		}
+
+		psmouse->vendor = "Microsoft";
+		psmouse->name = "IntelliMouse";
+
+		return PSMOUSE_IMPS;
+	}
+
+/*
+ * Okay, all failed, we have a standard mouse here. The number of the buttons is
+ * still a question, though.
+ */
+
+	psmouse->vendor = "Generic";
+	psmouse->name = "Mouse";
+
+	return PSMOUSE_PS2;
+}
+
+/*
+ * psmouse_probe() probes for a PS/2 mouse.
+ */
+
+static int psmouse_probe(struct psmouse *psmouse)
+{
+	unsigned char param[2];
+
+/*
+ * First we reset and disable the mouse.
+ */
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
+		return -1;
+
+/*
+ * Next, we check if it's a mouse. It should send 0x00 or 0x03
+ * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ */
+
+	param[0] = param[1] = 0xa5;
+
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
+		return -1;
+
+	if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+		return -1;
+
+/*
+ * And here we try to determine if it has any extensions over the
+ * basic PS/2 3-button mouse.
+ */
+
+	return psmouse->type = psmouse_extensions(psmouse);
+}
+
+/*
+ * psmouse_initialize() initializes the mouse to a sane state.
+ */
+
+static void psmouse_initialize(struct psmouse *psmouse)
+{
+	unsigned char param[2];
+
+/*
+ * We set the mouse report rate to a highest possible value.
+ * We try 100 first in case mouse fails to set 200.
+ */
+
+	param[0] = 100;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+	param[0] = 200;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+/*
+ * We also set the resolution and scaling.
+ */
+
+	param[0] = 3;
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+
+/*
+ * We set the mouse into streaming mode.
+ */
+
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+
+/*
+ * Last, we enable the mouse so that we get reports from it.
+ */
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
+		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
+	}
+
+}
+
+/*
+ * psmouse_disconnect() cleans up after we don't want talk
+ * to the mouse anymore.
+ */
+
+static void psmouse_disconnect(struct serio *serio)
+{
+	struct psmouse *psmouse = serio->private;
+	input_unregister_device(&psmouse->dev);
+	serio_close(serio);
+	kfree(psmouse);
+}
+
+/*
+ * psmouse_powerup() is called when we get the powerup
+ * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
+ */
+
+static void psmouse_powerup(void *data)
+{
+        struct psmouse *psmouse = data;
+
+	if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
+	   (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
+		mdelay(40); /* FIXME!!! Wait some nicer way */
+		serio_rescan(psmouse->serio);
+	}
+}
+
+/*
+ * psmouse_connect() is a callback form the serio module when
+ * an unhandled serio port is found.
+ */
+
+static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct psmouse *psmouse;
+	
+	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+		return;
+
+	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
+		return;
+
+	memset(psmouse, 0, sizeof(struct psmouse));
+
+	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+	psmouse->serio = serio;
+	psmouse->dev.private = psmouse;
+	psmouse->tq.routine = psmouse_powerup;
+	psmouse->tq.data = psmouse;
+
+	serio->private = psmouse;
+
+	if (serio_open(serio, dev)) {
+		kfree(psmouse);
+		return;
+	}
+
+	if (psmouse_probe(psmouse) <= 0) {
+		serio_close(serio);
+		kfree(psmouse);
+		return;
+	}
+	
+	sprintf(psmouse->devname, "%s %s %s",
+		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
+	sprintf(psmouse->phys, "%s/input0",
+		serio->phys);
+
+	psmouse->dev.name = psmouse->devname;
+	psmouse->dev.phys = psmouse->phys;
+	psmouse->dev.idbus = BUS_I8042;
+	psmouse->dev.idvendor = psmouse->type;
+	psmouse->dev.idproduct = 0x0002;
+	psmouse->dev.idversion = 0x0100;
+
+	input_register_device(&psmouse->dev);
+	
+	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+	psmouse_initialize(psmouse);
+}
+
+static struct serio_dev psmouse_dev = {
+	interrupt:	psmouse_interrupt,
+	connect:	psmouse_connect,
+	disconnect:	psmouse_disconnect
+};
+
+int __init psmouse_init(void)
+{
+	serio_register_device(&psmouse_dev);
+	return 0;
+}
+
+void __exit psmouse_exit(void)
+{
+	serio_unregister_device(&psmouse_dev);
+}
+
+module_init(psmouse_init);
+module_exit(psmouse_exit);
diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/rpcmouse.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,111 @@
+/*
+ * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *      Russel King
+ */
+
+/*
+ * Acorn RiscPC mouse driver for Linux/ARM
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
+MODULE_LICENSE("GPL");
+
+#define IOMD_MOUSEBTN	0x800C4000
+
+static short rpcmouse_lastx, rpcmouse_lasty;
+
+static struct input_dev rpcmouse_dev = {
+	evbit:		{ BIT(EV_KEY) | BIT(EV_REL) },
+	keybit: 	{ [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+	relbit:		{ BIT(REL_X) | BIT(REL_Y) },
+	name:		"Acorn RiscPC Mouse",
+	phys:		"rpcmouse/input0",
+	idbus:		BUS_ISA,
+	idvendor:	0x0005,
+	idproduct:	0x0001,
+	idversion:	0x0100,
+};
+
+static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	short x, y, dx, dy, b;
+
+	x = (short) inl(IOMD_MOUSEX);
+	y = (short) inl(IOMD_MOUSEY);
+	b = (short) inl(IOMD_MOUSEBTN);
+
+	dx = x - rpcmouse_lastx;
+	dy = y - rpcmouse_lasty; 
+
+	rpcmouse_lastx = x;
+	rpcmouse_lasty = y;
+
+	input_report_rel(&rpcmouse_dev, REL_X, dx);
+	input_report_rel(&rpcmouse_dev, REL_Y, dy);
+
+	input_report_key(&amimouse_dev, BTN_LEFT,   buttons & 0x10);
+	input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20);
+	input_report_key(&amimouse_dev, BTN_RIGHT,  buttons & 0x40);
+}
+
+static int __init rpcmouse_init(void)
+{
+	rpcmouse_lastx = (short) inl(IOMD_MOUSEX);
+	rpcmouse_lasty = (short) inl(IOMD_MOUSEY);
+
+	if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
+		printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
+		return -1;
+	}
+
+	input_register_device(&rpcmouse_dev);
+	printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
+
+	return 0;
+}
+
+static void __exit rpcmouse_exit(void)
+{
+	input_unregister_device(&rpcmouse_dev);
+	free_irq(IRQ_VSYNCPULSE, NULL);
+}
+
+module_init(rpcmouse_init);
+module_exit(rpcmouse_exit);
diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/sermouse.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,299 @@
+/*
+ * $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  Serial mouse 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Serial mouse driver");
+MODULE_LICENSE("GPL");
+
+static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
+					"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
+					"Logitech MZ++ Mouse"};
+
+struct sermouse {
+	struct input_dev dev;
+	signed char buf[8];
+	unsigned char count;
+	unsigned char type;
+	unsigned long last;
+	char phys[32];
+};
+
+/*
+ * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
+ * applies some prediction to the data, resulting in 96 updates per
+ * second, which is as good as a PS/2 or USB mouse.
+ */
+
+static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
+{
+	struct input_dev *dev = &sermouse->dev;
+	signed char *buf = sermouse->buf;
+
+	switch (sermouse->count) {
+
+		case 0:
+			if ((data & 0xf8) != 0x80) return;
+			input_report_key(dev, BTN_LEFT,   !(data & 4)); 
+			input_report_key(dev, BTN_RIGHT,  !(data & 1));
+			input_report_key(dev, BTN_MIDDLE, !(data & 2));
+			break;
+
+		case 1: 
+		case 3: 
+			input_report_rel(dev, REL_X, data / 2);
+			input_report_rel(dev, REL_Y, -buf[1]);
+			buf[0] = data - data / 2;
+			break;
+
+		case 2: 
+		case 4:
+			input_report_rel(dev, REL_X, buf[0]);
+			input_report_rel(dev, REL_Y, buf[1] - data);
+			buf[1] = data / 2;
+			break;
+	}
+
+	if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
+		sermouse->count = 0;
+}
+
+/*
+ * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
+ * generates events. With prediction it gets 80 updates/sec, assuming
+ * standard 3-byte packets and 1200 bps.
+ */
+
+static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
+{
+	struct input_dev *dev = &sermouse->dev;
+	signed char *buf = sermouse->buf;
+
+	if (data & 0x40) sermouse->count = 0;
+
+	switch (sermouse->count) {
+
+		case 0:
+			buf[1] = data;
+			input_report_key(dev, BTN_LEFT,   (data >> 5) & 1);
+			input_report_key(dev, BTN_RIGHT,  (data >> 4) & 1);
+			break;
+
+		case 1:
+			buf[2] = data;
+			data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
+			input_report_rel(dev, REL_X, data / 2);
+			input_report_rel(dev, REL_Y, buf[4]);
+			buf[3] = data - data / 2;
+			break;
+
+		case 2:
+			/* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
+			if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
+				input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
+			buf[0] = buf[1];
+
+			data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
+			input_report_rel(dev, REL_X, buf[3]);
+			input_report_rel(dev, REL_Y, data - buf[4]);
+			buf[4] = data / 2;
+			break;
+
+		case 3:
+
+			switch (sermouse->type) {
+			
+				case SERIO_MS:
+					 sermouse->type = SERIO_MP;
+
+				case SERIO_MP:
+					if ((data >> 2) & 3) break;	/* M++ Wireless Extension packet. */
+					input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
+					input_report_key(dev, BTN_SIDE,   (data >> 4) & 1);
+					break;
+
+				case SERIO_MZP:
+				case SERIO_MZPP:
+					input_report_key(dev, BTN_SIDE,   (data >> 5) & 1);
+
+				case SERIO_MZ:
+					input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
+					input_report_rel(dev, REL_WHEEL, (data & 7) - (data & 8));
+					break;
+			}
+					
+			break;
+
+		case 4:
+		case 6:	/* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
+			buf[1] = (data >> 2) & 0x0f;
+			break;
+
+		case 5:
+		case 7: /* Ignore anything besides MZ++ */
+			if (sermouse->type != SERIO_MZPP) break;
+
+			switch (buf[1]) {
+
+				case 1: /* Extra mouse info */
+
+					input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
+					input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
+					input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
+
+					break;
+
+				default: /* We don't decode anything else yet. */
+
+					printk(KERN_WARNING
+						"sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
+					break;
+			}
+
+			break;
+	}
+
+	sermouse->count++;
+}
+
+/*
+ * sermouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void sermouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct sermouse *sermouse = serio->private;
+
+	if (time_after(jiffies, sermouse->last + HZ/20)) sermouse->count = 0;
+	sermouse->last = jiffies;
+
+	if (sermouse->type > SERIO_SUN)
+		sermouse_process_ms(sermouse, data);
+	else
+		sermouse_process_msc(sermouse, data);
+}
+
+/*
+ * sermouse_disconnect() cleans up after we don't want talk
+ * to the mouse anymore.
+ */
+
+static void sermouse_disconnect(struct serio *serio)
+{
+	struct sermouse *sermouse = serio->private;
+	input_unregister_device(&sermouse->dev);
+	serio_close(serio);
+	kfree(sermouse);
+}
+
+/*
+ * sermouse_connect() is a callback form the serio module when
+ * an unhandled serio port is found.
+ */
+
+static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct sermouse *sermouse;
+	unsigned char c;
+	
+	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+		return;
+
+	if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
+		return;
+
+	if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
+		return;
+
+	memset(sermouse, 0, sizeof(struct sermouse));
+
+	sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+	sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	sermouse->dev.private = sermouse;
+
+	serio->private = sermouse;
+
+	sermouse->type = serio->type & SERIO_PROTO;
+	c = (serio->type & SERIO_EXTRA) >> 16;
+
+	if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
+	if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
+	if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit);
+	if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit);
+	if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit);
+
+	sprintf(sermouse->phys, "%s/input0", serio->phys);
+
+	sermouse->dev.name = sermouse_protocols[sermouse->type];
+	sermouse->dev.phys = sermouse->phys;
+	sermouse->dev.idbus = BUS_RS232;
+	sermouse->dev.idvendor = sermouse->type;
+	sermouse->dev.idproduct = c;
+	sermouse->dev.idversion = 0x0100;
+
+	if (serio_open(serio, dev)) {
+		kfree(sermouse);
+		return;
+	}
+
+	input_register_device(&sermouse->dev);
+	
+	printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
+}
+
+static struct serio_dev sermouse_dev = {
+	interrupt:	sermouse_interrupt,
+	connect:	sermouse_connect,
+	disconnect:	sermouse_disconnect
+};
+
+int __init sermouse_init(void)
+{
+	serio_register_device(&sermouse_dev);
+	return 0;
+}
+
+void __exit sermouse_exit(void)
+{
+	serio_unregister_device(&sermouse_dev);
+}
+
+module_init(sermouse_init);
+module_exit(sermouse_exit);
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/input/mousedev.c	Fri Jul  5 16:42:59 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: mousedev.c,v 1.38 2001/12/26 21:08:33 jsimmons Exp $
+ * $Id: mousedev.c,v 1.42 2002/04/09 20:51:26 jdeneux Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
@@ -38,6 +38,10 @@
 #include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/random.h>
+#include <linux/major.h>
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+#include <linux/miscdevice.h>
+#endif
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
@@ -225,7 +229,14 @@
 static int mousedev_open(struct inode * inode, struct file * file)
 {
 	struct mousedev_list *list;
-	int i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
+	int i;
+
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+	if (major(inode->i_rdev) == MISC_MAJOR)
+		i = MOUSEDEV_MIX;
+	else
+#endif
+		i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
 
 	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
 		return -ENODEV;
@@ -494,6 +505,12 @@
 	id_table:	mousedev_ids,
 };
 
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+static struct miscdevice psaux_mouse = {
+	PSMOUSE_MINOR, "psaux", &mousedev_fops
+};
+#endif
+
 static int __init mousedev_init(void)
 {
 	input_register_handler(&mousedev_handler);
@@ -504,6 +521,9 @@
 	mousedev_mix.exist = 1;
 	mousedev_mix.minor = MOUSEDEV_MIX;
 	mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+	misc_register(&psaux_mouse);
+#endif
 
 	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
 
@@ -512,6 +532,9 @@
 
 static void __exit mousedev_exit(void)
 {
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+	misc_deregister(&psaux_mouse);
+#endif
 	input_unregister_minor(mousedev_mix.devfs);
 	input_unregister_handler(&mousedev_handler);
 }
diff -Nru a/drivers/input/power.c b/drivers/input/power.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/power.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,180 @@
+/*
+ * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
+ *
+ *  Copyright (c) 2001 "Crazy" James Simmons  
+ *
+ *  Input driver Power Management.
+ *
+ *  Sponsored by Transvirtual Technology.
+ */
+
+/*
+ * 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 <jsimmons@transvirtual.com>.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+static struct input_handler power_handler;
+
+/*
+ * Power management can't be done in a interrupt context. So we have to
+ * use keventd.
+ */
+static int suspend_button_pushed = 0;
+static void suspend_button_task_handler(void *data)
+{
+        //extern void pm_do_suspend(void);
+        udelay(200); /* debounce */
+        //pm_do_suspend();
+        suspend_button_pushed = 0;
+}
+
+static struct tq_struct suspend_button_task = {
+        routine: suspend_button_task_handler
+};
+
+static void power_event(struct input_handle *handle, unsigned int type, 
+		        unsigned int code, int down)
+{
+	struct input_dev *dev = handle->dev;
+
+	printk("Entering power_event\n");
+
+	if (type != EV_KEY || type != EV_PWR) return;
+
+	if (type == EV_PWR) {
+		switch (code) {
+			case KEY_SUSPEND:
+				printk("Powering down entire device\n");
+
+				//pm_send_all(PM_SUSPEND, dev);
+
+				if (!suspend_button_pushed) {
+                			suspend_button_pushed = 1;
+                        		schedule_task(&suspend_button_task);
+                		}
+				break;
+			case KEY_POWER:
+				/* Hum power down the machine. */
+				break;
+			default:	
+				return;
+		}
+	} else {
+		switch (code) {
+			case KEY_SUSPEND:
+				printk("Powering down input device\n");
+				/* This is risky. See pm.h for details. */
+				if (dev->state != PM_RESUME)
+					dev->state = PM_RESUME;
+				else 
+					dev->state = PM_SUSPEND;	
+				pm_send(dev->pm_dev, dev->state, dev); 	
+				break;
+			case KEY_POWER:
+				/* Turn the input device off completely ? */
+				break;
+			default:
+				return;
+		}
+	}
+	return;
+}
+
+static struct input_handle *power_connect(struct input_handler *handler, 
+					  struct input_dev *dev, 
+					  struct input_device_id *id)
+{
+	struct input_handle *handle;
+
+	if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
+		return NULL;	
+
+	if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
+		return NULL;
+
+	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+		return NULL;
+	memset(handle, 0, sizeof(struct input_handle));
+
+	handle->dev = dev;
+	handle->handler = handler;
+
+	input_open_device(handle);
+
+	printk(KERN_INFO "power.c: Adding power management to input layer\n");
+	return handle;
+}
+
+static void power_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	kfree(handle);
+}
+
+static struct input_device_id power_ids[] = {
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+		evbit: { BIT(EV_KEY) },
+		keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
+	},	
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+		evbit: { BIT(EV_KEY) },
+		keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
+	},	
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+		evbit: { BIT(EV_PWR) },
+	},	
+	{ }, 	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, power_ids);
+	
+static struct input_handler power_handler = {
+	event:		power_event,
+	connect:	power_connect,
+	disconnect:	power_disconnect,
+	name:		"power",
+	id_table:	power_ids,
+};
+
+static int __init power_init(void)
+{
+	input_register_handler(&power_handler);
+	return 0;
+}
+
+static void __exit power_exit(void)
+{
+	input_unregister_handler(&power_handler);
+}
+
+module_init(power_init);
+module_exit(power_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input Power Management driver");
diff -Nru a/drivers/input/serio/Config.help b/drivers/input/serio/Config.help
--- a/drivers/input/serio/Config.help	Fri Jul  5 16:42:50 2002
+++ b/drivers/input/serio/Config.help	Fri Jul  5 16:42:50 2002
@@ -12,6 +12,18 @@
   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_I8042
+  i8042 is the chip over which the standard AT keyboard and PS/2
+  mouse are connected to the computer. If you use these devices,
+  you'll 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 i8042.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.
@@ -24,3 +36,38 @@
   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_SERIO_CT82C710
+  Say Y here if you have a Texas Instruments TravelMate notebook
+  equipped with the ct82c710 chip and want to use a mouse connected
+  to the "QuickPort".
+
+  If unsure, say N.
+
+  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 ct82c710.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_PARKBD
+  Say Y here if you built a simple parallel port adapter to attach
+  an additional AT keyboard, XT keyboard or PS/2 mouse.
+
+  More information is available: <file:Documentation/input/input.txt>
+
+  If unsure, say N.
+
+  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 parkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_ACORN
+  Say Y here if you have the Acorn RiscPC and want to use an AT
+  keyboard connected to its keyboard controller.
+
+  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 rpckbd.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
--- a/drivers/input/serio/Config.in	Fri Jul  5 16:43:00 2002
+++ b/drivers/input/serio/Config.in	Fri Jul  5 16:43:00 2002
@@ -4,4 +4,16 @@
 
 tristate 'Serial i/o support' CONFIG_SERIO
 
+dep_tristate '  i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA
+if [ "$CONFIG_SERIO_I8042" != "n" ]; then
+   hex '    Register Base Address' CONFIG_I8042_REG_BASE 60
+   int '    PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1
+   int '    PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12
+fi
 dep_tristate '  Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO 
+dep_tristate '  ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA
+dep_tristate '  Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT
+
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+   dep_tristate '  Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO
+fi
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	Fri Jul  5 16:42:56 2002
+++ b/drivers/input/serio/Makefile	Fri Jul  5 16:42:56 2002
@@ -9,7 +9,11 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_SERIO)		+= serio.o
+obj-$(CONFIG_SERIO_I8042)	+= i8042.o
+obj-$(CONFIG_SERIO_PARKBD)	+= parkbd.o
 obj-$(CONFIG_SERIO_SERPORT)	+= serport.o
+obj-$(CONFIG_SERIO_CT82C710)	+= ct82c710.o
+obj-$(CONFIG_SERIO_RPCKBD)	+= rpckbd.o
 
 # The global Rules.make.
 
diff -Nru a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/ct82c710.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,212 @@
+/*
+ * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  82C710 C&T mouse port chip 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
+MODULE_LICENSE("GPL");
+
+static char ct82c710_name[] = "C&T 82c710 mouse port";
+static char ct82c710_phys[16];
+
+/*
+ * ct82c710 interface
+ */
+
+#define CT82C710_DEV_IDLE     0x01		/* Device Idle */
+#define CT82C710_RX_FULL      0x02		/* Device Char received */
+#define CT82C710_TX_IDLE      0x04		/* Device XMIT Idle */
+#define CT82C710_RESET        0x08		/* Device Reset */
+#define CT82C710_INTS_ON      0x10		/* Device Interrupt On */
+#define CT82C710_ERROR_FLAG   0x20		/* Device Error */
+#define CT82C710_CLEAR        0x40		/* Device Clear */
+#define CT82C710_ENABLE       0x80		/* Device Enable */
+
+#define CT82C710_IRQ          12
+
+static int ct82c710_data = 0;
+static int ct82c710_status = 0;
+
+static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs);
+
+/*
+ * Wait for device to send output char and flush any input char.
+ */
+
+static int ct82c170_wait(void)
+{
+	int timeout = 60000;
+
+	while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
+		       != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
+
+		if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data);
+
+		udelay(1);
+		timeout--;
+	}
+
+	return !timeout;
+}
+
+static void ct82c710_close(struct serio *serio)
+{
+	if (ct82c170_wait())
+		printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+	outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status);
+
+	if (ct82c170_wait())
+		printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+	free_irq(CT82C710_IRQ, NULL);
+}
+
+static int ct82c710_open(struct serio *serio)
+{
+	unsigned char status;
+
+	if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
+		return -1;
+
+	status = inb_p(ct82c710_status);
+
+	status |= (CT82C710_ENABLE | CT82C710_RESET);
+	outb_p(status, ct82c710_status);
+
+	status &= ~(CT82C710_RESET);
+	outb_p(status, ct82c710_status);
+
+	status |= CT82C710_INTS_ON;
+	outb_p(status, ct82c710_status);	/* Enable interrupts */
+
+	while (ct82c170_wait()) {
+		printk(KERN_ERR "ct82c710: Device busy in open()\n");
+		status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
+		outb_p(status, ct82c710_status);
+		free_irq(CT82C710_IRQ, NULL);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Write to the 82C710 mouse device.
+ */
+
+static int ct82c710_write(struct serio *port, unsigned char c)
+{
+	if (ct82c170_wait()) return -1;
+	outb_p(c, ct82c710_data);
+	return 0;
+}
+
+static struct serio ct82c710_port =
+{
+	type:	SERIO_8042,
+	name:	ct82c710_name,
+	phys:	ct82c710_phys,
+	write:	ct82c710_write,
+	open:	ct82c710_open,
+	close:	ct82c710_close,
+};
+
+/*
+ * Interrupt handler for the 82C710 mouse port. A character
+ * is waiting in the 82C710.
+ */
+
+static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+{
+	if (ct82c710_port.dev)
+		ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0);
+}
+
+/*
+ * See if we can find a 82C710 device. Read mouse address.
+ */
+
+static int __init ct82c710_probe(void)
+{
+	outb_p(0x55, 0x2fa);				/* Any value except 9, ff or 36 */
+	outb_p(0xaa, 0x3fa);				/* Inverse of 55 */
+	outb_p(0x36, 0x3fa);				/* Address the chip */
+	outb_p(0xe4, 0x3fa);				/* 390/4; 390 = config address */
+	outb_p(0x1b, 0x2fa);				/* Inverse of e4 */
+	outb_p(0x0f, 0x390);				/* Write index */
+	if (inb_p(0x391) != 0xe4)			/* Config address found? */
+		return -1;				/* No: no 82C710 here */
+
+	outb_p(0x0d, 0x390);				/* Write index */
+	ct82c710_data = inb_p(0x391) << 2;		/* Get mouse I/O address */
+	ct82c710_status = ct82c710_data + 1;
+	outb_p(0x0f, 0x390);
+	outb_p(0x0f, 0x391);				/* Close config mode */
+
+	return 0;
+}
+
+int __init ct82c710_init(void)
+{
+	if (ct82c710_probe())
+		return -ENODEV;
+
+	if (request_region(ct82c710_data, 2, "ct82c710"))
+		return -EBUSY;
+
+	sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data);
+
+	serio_register_port(&ct82c710_port);
+
+	printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n",
+		ct82c710_data, CT82C710_IRQ);
+
+	return 0;
+}
+
+void __exit ct82c710_exit(void)
+{
+	serio_unregister_port(&ct82c710_port);
+	release_region(ct82c710_data, 2);
+}
+
+module_init(ct82c710_init);
+module_exit(ct82c710_exit);
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/i8042.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,717 @@
+/*
+ * $Id: i8042.c,v 1.21 2002/03/01 22:09:27 jsimmons Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  i8042 keyboard and mouse 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/sched.h>	/* request/free_irq */
+
+#include "i8042.h"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(i8042_noaux, "1i");
+MODULE_PARM(i8042_unlock, "1i");
+MODULE_PARM(i8042_reset, "1i");
+MODULE_PARM(i8042_direct, "1i");
+
+static int i8042_noaux;
+static int i8042_unlock;
+static int i8042_reset;
+static int i8042_direct;
+
+spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
+
+struct i8042_values {
+	int irq;
+	unsigned char disable;
+	unsigned char irqen;
+	unsigned char exists;
+	unsigned char *name;
+	unsigned char *phys;
+};
+
+static struct serio i8042_kbd_port;
+static struct serio i8042_aux_port;
+static unsigned char i8042_initial_ctr;
+static unsigned char i8042_ctr;
+
+#ifdef I8042_DEBUG_IO
+static unsigned long i8042_start;
+#endif
+
+static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG];
+static unsigned char i8042_unxlate_table[128] = {
+	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+	 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+	 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+	 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
+	 11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
+	114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
+	 71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+	 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+};
+
+static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/*
+ * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
+ * be ready for reading values from it / writing values to it.
+ */
+
+static int i8042_wait_read(void)
+{
+	int i = 0;
+	while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+		udelay(50);
+		i++;
+	}
+	return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_wait_write(void)
+{
+	int i = 0;
+	while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+		udelay(50);
+		i++;
+	}
+	return -(i == I8042_CTL_TIMEOUT);
+}
+
+/*
+ * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
+ * of the i8042 down the toilet.
+ */
+
+static int i8042_flush(void)
+{
+	unsigned long flags;
+	int i = 0;
+
+	spin_lock_irqsave(&i8042_lock, flags);
+
+	while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
+#ifdef I8042_DEBUG_IO
+		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n",
+			inb(I8042_DATA_REG), (int) (jiffies - i8042_start));
+#else
+		inb(I8042_DATA_REG);
+#endif
+
+	spin_unlock_irqrestore(&i8042_lock, flags);
+
+	return i;
+}
+
+/*
+ * i8042_command() executes a command on the i8042. It also sends the input parameter(s)
+ * of the commands to it, and receives the output value(s). The parameters are to be
+ * stored in the param array, and the output is placed into the same array. The number
+ * of the parameters and output values is encoded in bits 8-11 of the command
+ * number.
+ */
+
+static int i8042_command(unsigned char *param, int command)
+{ 
+	unsigned long flags;
+	int retval = 0, i = 0;
+
+	spin_lock_irqsave(&i8042_lock, flags);
+
+	retval = i8042_wait_write();
+	if (!retval) {
+#ifdef I8042_DEBUG_IO
+		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n",
+			command & 0xff, (int) (jiffies - i8042_start));
+#endif
+		outb(command & 0xff, I8042_COMMAND_REG);
+	}
+	
+	if (!retval)
+		for (i = 0; i < ((command >> 12) & 0xf); i++) {
+			if ((retval = i8042_wait_write())) break;
+#ifdef I8042_DEBUG_IO
+			printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n",
+				param[i], (int) (jiffies - i8042_start));
+#endif
+			outb(param[i], I8042_DATA_REG);
+		}
+
+	if (!retval)
+		for (i = 0; i < ((command >> 8) & 0xf); i++) {
+			if ((retval = i8042_wait_read())) break;
+			if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA) 
+				param[i] = ~inb(I8042_DATA_REG);
+			else
+				param[i] = inb(I8042_DATA_REG);
+#ifdef I8042_DEBUG_IO
+			printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n",
+				param[i], (int) (jiffies - i8042_start));
+#endif
+		}
+
+	spin_unlock_irqrestore(&i8042_lock, flags);
+
+#ifdef I8042_DEBUG_IO
+	if (retval)
+		printk(KERN_DEBUG "i8042.c:      -- i8042 (timeout) [%d]\n",
+			(int) (jiffies - i8042_start));
+#endif
+
+	return retval;
+}
+
+/*
+ * i8042_kbd_write() sends a byte out through the keyboard interface.
+ * It also automatically refreshes the CTR value, since some i8042's
+ * trash their CTR after attempting to send data to an nonexistent
+ * device.
+ */
+
+static int i8042_kbd_write(struct serio *port, unsigned char c)
+{
+	unsigned long flags;
+	int retval = 0;
+
+	spin_lock_irqsave(&i8042_lock, flags);
+
+	if(!(retval = i8042_wait_write())) {
+#ifdef I8042_DEBUG_IO
+		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n",
+			c, (int) (jiffies - i8042_start));
+#endif
+		outb(c, I8042_DATA_REG);
+	}
+
+	spin_unlock_irqrestore(&i8042_lock, flags);
+
+	return retval;
+}
+
+/*
+ * i8042_aux_write() sends a byte out through the aux interface.
+ */
+
+static int i8042_aux_write(struct serio *port, unsigned char c)
+{
+	int retval;
+
+/*
+ * Send the byte out.
+ */
+
+	retval  = i8042_command(&c, I8042_CMD_AUX_SEND);
+
+/*
+ * Here we restore the CTR value. I don't know why, but i8042's in half-AT
+ * mode tend to trash their CTR when doing the AUX_SEND command.
+ */
+
+	retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
+
+/*
+ * Make sure the interrupt happens and the character is received even
+ * in the case the IRQ isn't wired, so that we can receive further
+ * characters later.
+ */
+
+	i8042_interrupt(0, port, NULL);
+	return retval;
+}
+
+/*
+ * i8042_open() is called when a port is open by the higher layer.
+ * It allocates an interrupt and enables the port.
+ */
+
+static int i8042_open(struct serio *port)
+{
+	struct i8042_values *values = port->driver;
+
+/*
+ * Allocate the interrupt
+ */
+
+	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
+		printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name);
+		return -1;
+	}
+
+/*
+ * Enable the device and its interrupt.
+ */
+
+	i8042_ctr |= values->irqen;
+	i8042_ctr &= ~values->disable;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
+		return -1;
+	}
+
+/*
+ * Flush buffers
+ */
+
+	i8042_flush();
+
+	return 0;
+}
+
+/*
+ * i8042_close() frees the interrupt, and disables the interface when the
+ * upper layer doesn't need it anymore.
+ */
+
+static void i8042_close(struct serio *port)
+{
+	struct i8042_values *values = port->driver;
+
+/*
+ * Disable the device and its interrupt.
+ */
+
+	i8042_ctr &= ~values->irqen;
+	i8042_ctr |= values->disable;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
+		return;
+	}
+
+/*
+ * Free the interrupt
+ */
+
+	free_irq(values->irq, NULL);
+}
+
+/*
+ * Structures for registering the devices in the serio.c module.
+ */
+
+static struct i8042_values i8042_kbd_values = {
+	irq:		I8042_KBD_IRQ,
+	irqen:		I8042_CTR_KBDINT,
+	disable:	I8042_CTR_KBDDIS,
+	name:		"KBD",
+	exists:		0,
+};
+
+static struct serio i8042_kbd_port =
+{
+	type:		SERIO_8042,
+	write:		i8042_kbd_write,
+	open:		i8042_open,
+	close:		i8042_close,
+	driver:		&i8042_kbd_values,
+	name:		"i8042 Kbd Port",
+	phys:		"isa0060/serio0",
+};
+
+static struct i8042_values i8042_aux_values = {
+	irq:		I8042_AUX_IRQ,
+	irqen:		I8042_CTR_AUXINT,
+	disable:	I8042_CTR_AUXDIS,
+	name:		"AUX",
+	exists:		0,
+};
+
+static struct serio i8042_aux_port =
+{
+	type:		SERIO_8042,
+	write:		i8042_aux_write,
+	open:		i8042_open,
+	close:		i8042_close,
+	driver:		&i8042_aux_values,
+	name:		"i8042 Aux Port",
+	phys:		"isa0060/serio1",
+};
+
+/*
+ * i8042_interrupt() is the most important function in this driver -
+ * it handles the interrupts from the i8042, and sends incoming bytes
+ * to the upper layers.
+ */
+
+static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned char str, data;
+
+	spin_lock_irqsave(&i8042_lock, flags);
+
+	while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) {
+
+		data = inb(I8042_DATA_REG);
+
+#ifdef I8042_DEBUG_IO
+		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n",
+			data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start));
+#endif
+
+		if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
+			if (i8042_aux_port.dev)
+				i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0);
+		} else {
+			if (i8042_kbd_values.exists && i8042_kbd_port.dev) {
+				if (!i8042_direct) {
+					if (data > 0x7f) {
+						if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
+							i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0);	
+							data = i8042_unxlate_table[data & 0x7f];
+						}
+					} else {
+						set_bit(data, i8042_unxlate_seen);
+						data = i8042_unxlate_table[data];
+					}
+				}
+				i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0);
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&i8042_lock, flags);
+}
+
+/*
+ * i8042_controller init initializes the i8042 controller, and,
+ * most importantly, sets it into non-xlated mode.
+ */
+	
+static int __init i8042_controller_init(void)
+{
+
+/*
+ * Check the i/o region before we touch it.
+ */
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) 	
+	if (check_region(I8042_DATA_REG, 16)) {
+		printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG);
+		return -1;
+	}
+#endif
+
+/*
+ * Test the i8042. We need to know if it thinks it's working correctly
+ * before doing anything else.
+ */
+
+	i8042_flush();
+
+	if (i8042_reset) {
+
+		unsigned char param;
+
+		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
+			printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+			return -1;
+		}
+
+		if (param != I8042_RET_CTL_TEST) {
+			printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
+				 param, I8042_RET_CTL_TEST);
+			return -1;
+		}
+	}
+
+/*
+ * Read the CTR.
+ */
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
+		printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
+		return -1;
+	}
+
+/*
+ * Save the CTR for restoral on unload / reboot.
+ */
+
+	i8042_initial_ctr = i8042_ctr;
+
+/*
+ * Disable both interfaces and their interrupts.
+ */
+
+	i8042_ctr |= I8042_CTR_KBDDIS;
+	i8042_ctr &= ~I8042_CTR_KBDINT;
+
+/*
+ * Handle keylock.
+ */
+
+	if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) {
+
+		if (i8042_unlock) {
+			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
+		} else {
+			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
+		}
+	}
+
+/*
+ * If the chip is configured into nontranslated mode by the BIOS, don't
+ * bother enabling translating and just use that happily.
+ */
+
+	if (~i8042_ctr & I8042_CTR_XLATE)
+		i8042_direct = 1;
+
+/*
+ * Set nontranslated mode for the kbd interface if requested by an option.
+ * This is vital for a working scancode set 3 support. After this the kbd
+ * interface becomes a simple serial in/out, like the aux interface is. If
+ * the user doesn't wish this, the driver tries to untranslate the values
+ * after the i8042 translates them.
+ */
+
+	if (i8042_direct)
+		i8042_ctr &= ~I8042_CTR_XLATE;
+
+/*
+ * Write CTR back.
+ */
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Here we try to reset everything back to a state in which the BIOS will be
+ * able to talk to the hardware when rebooting.
+ */
+
+void i8042_controller_cleanup(void)
+{
+
+/*
+ * Reset the controller.
+ */
+
+	if (i8042_reset) {
+		unsigned char param;
+
+		if (i8042_command(&param, I8042_CMD_CTL_TEST))
+			printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
+	}
+
+/*
+ * Restore the original control register setting.
+ */
+
+	i8042_ctr = i8042_initial_ctr;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
+
+/*
+ * Reset anything that is connected to the ports if the ports
+ * are enabled in the original config.
+ */
+
+	if (i8042_kbd_values.exists)
+		i8042_kbd_write(&i8042_kbd_port, 0xff);
+
+	if (i8042_aux_values.exists)
+		i8042_aux_write(&i8042_aux_port, 0xff);
+}
+
+/*
+ * i8042_check_aux() applies as much paranoia as it can at detecting
+ * the presence of an AUX interface.
+ */
+
+static int __init i8042_check_aux(struct i8042_values *values, struct serio *port)
+{
+	unsigned char param;
+
+	i8042_flush();
+
+/*
+ * Internal loopback test - filters out AT-type i8042's
+ */
+
+	param = 0x5a;
+
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5)
+		return -1;
+
+/*
+ * External connection test - filters out AT-soldered PS/2 i8042's
+ */
+
+	if (i8042_command(&param, I8042_CMD_AUX_TEST) || param)
+		return -1;
+
+/*
+ * Bit assignment test - filters out PS/2 i8042's in AT mode
+ */
+	
+	if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
+		return -1;
+
+	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS))
+		return -1;	
+
+	if (i8042_command(&param, I8042_CMD_AUX_TEST) || param) {
+
+/*
+ * We've got an old AMI i8042 with 'Bad Cache' commands.
+ */
+
+		i8042_command(&param, I8042_CMD_AUX_ENABLE);
+		return -1;
+	}
+
+	if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
+		return -1;
+
+	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
+		return -1;	
+
+/*
+ * Disable the interface.
+ */
+
+	i8042_ctr |= I8042_CTR_AUXDIS;
+	i8042_ctr &= ~I8042_CTR_AUXINT;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * i8042_port_register() marks the device as existing,
+ * registers it, and reports to the user.
+ */
+
+static int __init i8042_port_register(struct i8042_values *values, struct serio *port)
+{
+	values->exists = 1;
+	serio_register_port(port);
+	printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n",
+		values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq);
+
+	return 0;
+}
+
+/*
+ * Module init and cleanup functions.
+ */
+
+void __init i8042_setup(char *str, int *ints)
+{
+	if (!strcmp(str, "i8042_reset=1"))
+		i8042_reset = 1;
+	if (!strcmp(str, "i8042_noaux=1"))
+		i8042_noaux = 1;
+	if (!strcmp(str, "i8042_unlock=1"))
+		i8042_unlock = 1;
+	if (!strcmp(str, "i8042_direct=1"))
+		i8042_direct = 1;
+}
+
+/*
+ * Reset the 8042 back to original mode.
+ */
+static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
+        		    void *unused)
+{
+        if (code==SYS_DOWN || code==SYS_HALT) 
+        	i8042_controller_cleanup();
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block i8042_notifier=
+{
+        i8042_notify_sys,
+        NULL,
+        0
+};
+
+int __init i8042_init(void)
+{
+#ifdef I8042_DEBUG_IO
+	i8042_start = jiffies;
+#endif
+
+	if (i8042_controller_init())
+		return -ENODEV;
+
+	i8042_port_register(&i8042_kbd_values, &i8042_kbd_port);
+		
+	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port))
+		i8042_port_register(&i8042_aux_values, &i8042_aux_port);
+
+/* 
+ * On ix86 platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on ix86 boxes.  
+ */
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+	request_region(I8042_DATA_REG, 16, "i8042");
+#endif
+	register_reboot_notifier(&i8042_notifier);
+	return 0;
+}
+
+void __exit i8042_exit(void)
+{
+	unregister_reboot_notifier(&i8042_notifier);
+	
+	if (i8042_kbd_values.exists)
+		serio_unregister_port(&i8042_kbd_port);
+
+	if (i8042_aux_values.exists)
+		serio_unregister_port(&i8042_aux_port);
+
+	i8042_controller_cleanup();
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+	release_region(I8042_DATA_REG, 16);
+#endif
+}
+
+module_init(i8042_init);
+module_exit(i8042_exit);
diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/i8042.h	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,128 @@
+#ifndef _I8042_H
+#define _I8042_H
+
+/*
+ * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+/*
+ * If you want to reset your i8042 upon boot, define this.
+ */
+
+#undef I8042_RESET
+
+/*
+ * If you want to trace all the i/o the i8042 module does for
+ * debugging purposes, define this.
+ */
+
+#undef I8042_DEBUG_IO
+
+/*
+ * On most PC based systems the keyboard IRQ is 1.
+ */
+
+#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ 
+
+/*
+ * On most PC based systems the aux port IRQ is 12. There are exceptions,
+ * though. Unfortunately IRQ probing is not possible without touching
+ * the device attached to the port.
+ */
+
+#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
+
+/*
+ * This is in 50us units, the time we wait for the i8042 to react. This
+ * has to be long enough for the i8042 itself to timeout on sending a byte
+ * to a non-existent mouse.
+ */
+
+#define I8042_CTL_TIMEOUT	10000
+
+/*
+ * Register numbers.
+ */
+
+#define I8042_COMMAND_REG	CONFIG_I8042_REG_BASE + 4	
+#define I8042_STATUS_REG	CONFIG_I8042_REG_BASE + 4	
+#define I8042_DATA_REG		CONFIG_I8042_REG_BASE	
+
+/*
+ * Status register bits.
+ */
+
+#define I8042_STR_PARITY	0x80
+#define I8042_STR_TIMEOUT	0x40
+#define I8042_STR_AUXDATA	0x20
+#define I8042_STR_KEYLOCK	0x10
+#define I8042_STR_CMDDAT	0x08
+#define I8042_STR_IBF		0x02
+#define	I8042_STR_OBF		0x01
+
+/*
+ * Control register bits.
+ */
+
+#define I8042_CTR_KBDINT	0x01
+#define I8042_CTR_AUXINT	0x02
+#define I8042_CTR_IGNKEYLOCK	0x08
+#define I8042_CTR_KBDDIS	0x10
+#define I8042_CTR_AUXDIS	0x20
+#define I8042_CTR_XLATE		0x40
+
+/*
+ * Commands.
+ */
+
+#define I8042_CMD_CTL_RCTR	0x0120
+#define I8042_CMD_CTL_WCTR	0x1060
+#define I8042_CMD_CTL_TEST	0x01aa
+
+#define I8042_CMD_KBD_DISABLE	0x00ad
+#define I8042_CMD_KBD_ENABLE	0x00ae
+#define I8042_CMD_KBD_TEST	0x01ab
+#define I8042_CMD_KBD_LOOP	0x11d2
+
+#define I8042_CMD_AUX_DISABLE	0x00a7
+#define I8042_CMD_AUX_ENABLE	0x00a8
+#define I8042_CMD_AUX_TEST	0x01a9
+#define I8042_CMD_AUX_SEND	0x10d4
+#define I8042_CMD_AUX_LOOP	0x11d3
+
+/*
+ * Return codes.
+ */
+
+#define I8042_RET_CTL_TEST	0x55
+
+/*
+ * Expected maximum internal i8042 buffer size. This is used for flushing
+ * the i8042 buffers. 32 should be more than enough.
+ */
+
+#define I8042_BUFFER_SIZE	32
+
+#endif /* _I8042_H */
diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/parkbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,203 @@
+/*
+ * $Id: parkbd.c,v 1.10 2002/03/13 10:09:20 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  Parallel port to Keyboard port adapter 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(parkbd, "1i");
+MODULE_PARM(parkbd_mode, "1i");
+
+#define PARKBD_CLOCK	0x01	/* Strobe & Ack */
+#define PARKBD_DATA	0x02	/* AutoFd & Busy */
+
+static int parkbd = 0;
+static int parkbd_mode = SERIO_8042;
+
+static int parkbd_buffer = 0;
+static int parkbd_counter = 0;
+static int parkbd_last = 0;
+static int parkbd_writing = 0;
+static unsigned long parkbd_start = 0;
+
+static struct pardevice *parkbd_dev;
+
+static char parkbd_name[] = "PARKBD AT/XT keyboard adapter";
+static char parkbd_phys[32];
+
+static int parkbd_readlines(void)
+{
+	return (parport_read_status(parkbd_dev->port) >> 6) ^ 2;
+}
+
+static void parkbd_writelines(int data)
+{
+	parport_write_control(parkbd_dev->port, (~data & 3) | 0x10);
+}
+
+static int parkbd_write(struct serio *port, unsigned char c)
+{
+	unsigned char p;
+
+	if (!parkbd_mode) return -1;
+
+        p = c ^ (c >> 4);
+	p = p ^ (p >> 2);
+	p = p ^ (p >> 1);
+
+	parkbd_counter = 0;
+	parkbd_writing = 1;
+	parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600;
+
+	parkbd_writelines(2);
+
+	return 0;
+}
+
+static int parkbd_open(struct serio *port)
+{
+	return 0;
+}
+
+static void parkbd_close(struct serio *port)
+{
+}
+
+static struct serio parkbd_port =
+{
+	write:	parkbd_write,
+	open:	parkbd_open,
+	close:	parkbd_close,
+	name:	parkbd_name,
+	phys:	parkbd_phys,
+};
+
+static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	if (parkbd_writing) {
+
+		if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) {
+			parkbd_counter = 0;
+			parkbd_buffer = 0;
+			parkbd_writing = 0;
+			parkbd_writelines(3);
+			return;
+		}	
+
+		parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
+
+		if (parkbd_counter == 11) {
+			parkbd_counter = 0;
+			parkbd_buffer = 0;
+			parkbd_writing = 0;
+			parkbd_writelines(3);
+		}
+
+	} else {
+
+		if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
+			parkbd_counter = 0;
+			parkbd_buffer = 0;
+		}	
+
+		parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
+
+		if (parkbd_counter == parkbd_mode + 10) {
+			if (parkbd_port.dev)
+				parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
+		}
+	}
+
+	parkbd_last = jiffies;
+}
+
+static int parkbd_getport(void)
+{
+	struct parport *pp;
+
+	if (parkbd < 0) {
+		printk(KERN_ERR "parkbd: no port specified\n");
+		return -ENODEV;
+	}
+
+	for (pp = parport_enumerate(); pp != NULL && (parkbd > 0); pp = pp->next) parkbd--;
+
+	if (pp == NULL) {
+		printk(KERN_ERR "parkbd: no such parport\n");
+		return -ENODEV;
+	}
+
+	parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL);
+
+	if (!parkbd_dev)
+		return -ENODEV;
+
+	if (parport_claim(parkbd_dev)) {
+		parport_unregister_device(parkbd_dev);
+		return -EBUSY;
+	}
+
+	parkbd_start = jiffies;
+
+	return 0;
+}
+
+
+int __init parkbd_init(void)
+{
+	if (parkbd_getport()) return -1;
+	parkbd_writelines(3);
+	parkbd_port.type = parkbd_mode;
+
+	sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name);
+
+	serio_register_port(&parkbd_port);
+
+	printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
+                        parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
+
+	return 0;
+}
+
+void __exit parkbd_exit(void)
+{
+	parport_release(parkbd_dev);
+	serio_unregister_port(&parkbd_port);
+	parport_unregister_device(parkbd_dev);
+}
+
+module_init(parkbd_init);
+module_exit(parkbd_exit);
diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/rpckbd.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,117 @@
+/*
+ * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	unknown author
+ */
+
+/*
+ * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
+ */
+
+/*
+ * 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+#include <asm/system.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
+MODULE_LICENSE("GPL");
+
+static inline void rpckbd_write(unsigned char val)
+{
+	while(!(inb(IOMD_KCTRL) & (1 << 7)));
+	outb(val, IOMD_KARTTX);
+}
+
+static struct serio rpckbd_port =
+{
+	type:	SERIO_8042,
+	write:	rpckbd_write,
+	name: 	"RiscPC PS/2 kbd port",
+	phys:	"rpckbd/serio0",
+};
+
+static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+{
+	kbd_pt_regs = regs;
+
+	while (inb(IOMD_KCTRL) & (1 << 5))
+		if (rpckbd_port.dev)
+               		 rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
+
+}
+
+static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int __init rpckbd_init(void)
+{
+	unsigned long flags;
+
+	/* Reset the keyboard state machine. */
+	outb(0, IOMD_KCTRL);
+	outb(8, IOMD_KCTRL);
+
+	save_flags_cli(flags);
+
+	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) {
+		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n")
+		return -EBUSY;
+	}
+
+	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) {
+		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n")
+		free_irq(IRQ_KEYBOARDRX, NULL);
+		return -EBUSY;
+	}
+
+	disable_irq(IRQ_KEYBOARDTX);
+	(void)IOMD_KARTRX;
+
+	restore_flags(flags);
+
+	register_serio_port(&rpckbd_port);
+	printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX);
+
+	return 0;
+}
+
+static void __exit rpckbd_exit(void)
+{
+	free_irq(IRQ_KEYBOARDRX, NULL);
+	free_irq(IRQ_KEYBOARDTX, NULL);	
+
+	unregister_serio_port(&rpckbd_port);
+}
+
+module_init(rpckbd_init);
+module_exit(rpckbd_exit);
diff -Nru a/drivers/input/touchscreen/Config.help b/drivers/input/touchscreen/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/touchscreen/Config.help	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,16 @@
+CONFIG_INPUT_TOUCHSCREEN
+  Say Y here, and a list of supported touchscreens will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_TOUCHSCREEN_GUNZE
+  Say Y here if you have the Gunze AHL-51 touchscreen connected to
+  your system.
+
+  If unsure, say N.
+
+  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 gunze.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -Nru a/drivers/input/touchscreen/Config.in b/drivers/input/touchscreen/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/touchscreen/Config.in	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,7 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
+
+dep_tristate '  Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
diff -Nru a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/touchscreen/Makefile	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,11 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/touchscreen/gunze.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,178 @@
+/*
+ * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ */
+
+/*
+ * Gunze AHL-51S touchscreen 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, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	GUNZE_MAX_LENGTH	10
+
+static char *gunze_name = "Gunze AHL-51S TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct gunze {
+	struct input_dev dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[GUNZE_MAX_LENGTH];
+	char phys[32];
+};
+
+static void gunze_process_packet(struct gunze* gunze)
+{
+	struct input_dev *dev = &gunze->dev;
+
+	if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
+		(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
+		gunze->data[10] = 0;
+		printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
+		return;
+	}
+
+	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
+	input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
+	input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+}
+
+static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+	struct gunze* gunze = serio->private;
+
+	if (data == '\r') {
+		gunze_process_packet(gunze);
+		gunze->idx = 0;
+	} else {
+		if (gunze->idx < GUNZE_MAX_LENGTH)
+			gunze->data[gunze->idx++] = data;
+	} 
+}
+
+/*
+ * gunze_disconnect() is the opposite of gunze_connect()
+ */
+
+static void gunze_disconnect(struct serio *serio)
+{
+	struct gunze* gunze = serio->private;
+	input_unregister_device(&gunze->dev);
+	serio_close(serio);
+	kfree(gunze);
+}
+
+/*
+ * gunze_connect() is the routine that is called when someone adds a
+ * new serio device. It looks whether it was registered as a Gunze touchscreen
+ * and if yes, registers it as an input device.
+ */
+
+static void gunze_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct gunze *gunze;
+
+	if (serio->type != (SERIO_RS232 | SERIO_GUNZE))
+		return;
+
+	if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
+		return;
+
+	memset(gunze, 0, sizeof(struct gunze));
+
+	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
+	gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	gunze->dev.absmin[ABS_X] = 96;   gunze->dev.absmin[ABS_Y] = 72;
+	gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
+
+	gunze->serio = serio;
+	serio->private = gunze;
+
+	sprintf(gunze->phys, "%s/input0", serio->phys);
+
+	gunze->dev.private = gunze;
+	gunze->dev.name = gunze_name;
+	gunze->dev.phys = gunze->phys;
+	gunze->dev.idbus = BUS_RS232;
+	gunze->dev.idvendor = SERIO_GUNZE;
+	gunze->dev.idproduct = 0x0051;
+	gunze->dev.idversion = 0x0100;
+
+	if (serio_open(serio, dev)) {
+		kfree(gunze);
+		return;
+	}
+
+	input_register_device(&gunze->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev gunze_dev = {
+	interrupt:	gunze_interrupt,
+	connect:	gunze_connect,
+	disconnect:	gunze_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init gunze_init(void)
+{
+	serio_register_device(&gunze_dev);
+	return 0;
+}
+
+void __exit gunze_exit(void)
+{
+	serio_unregister_device(&gunze_dev);
+}
+
+module_init(gunze_init);
+module_exit(gunze_exit);
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/tsdev.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,443 @@
+/*
+ * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
+ *
+ *  Copyright (c) 2001 "Crazy" james Simmons 
+ *
+ *  Input driver to Touchscreen device driver module.
+ *
+ *  Sponsored by Transvirtual Technology
+ */
+
+/*
+ * 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 <jsimmons@transvirtual.com>.
+ */
+
+#define TSDEV_MINOR_BASE 	128
+#define TSDEV_MINORS		32
+#define TSDEV_BUFFER_SIZE	64
+
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/smp_lock.h>
+#include <linux/random.h>
+#include <linux/time.h>
+
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
+#define CONFIG_INPUT_TSDEV_SCREEN_X	240
+#endif
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
+#define CONFIG_INPUT_TSDEV_SCREEN_Y	320
+#endif
+
+struct tsdev {
+	int exist;
+	int open;
+	int minor;
+	char name[16];
+	wait_queue_head_t wait;
+	struct tsdev_list *list;
+	struct input_handle handle;
+	devfs_handle_t devfs;
+};
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+typedef struct {
+	short pressure;
+	short x;
+	short y;
+	short millisecs;
+} TS_EVENT;
+
+struct tsdev_list {
+	struct fasync_struct *fasync;
+	struct tsdev_list *next;
+	struct tsdev *tsdev;
+	int head, tail;
+	int oldx, oldy, pendown;
+	TS_EVENT event[TSDEV_BUFFER_SIZE];
+};
+
+static struct input_handler tsdev_handler;
+
+static struct tsdev *tsdev_table[TSDEV_MINORS];
+
+static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
+static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
+
+static int tsdev_fasync(int fd, struct file *file, int on)
+{
+	struct tsdev_list *list = file->private_data;
+	int retval;
+
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static int tsdev_open(struct inode *inode, struct file *file)
+{
+	int i = minor(inode->i_rdev) - TSDEV_MINOR_BASE;
+	struct tsdev_list *list;
+
+	if (i >= TSDEV_MINORS || !tsdev_table[i])
+		return -ENODEV;
+
+	if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+		return -ENOMEM;
+	memset(list, 0, sizeof(struct tsdev_list));
+
+	list->tsdev = tsdev_table[i];
+	list->next = tsdev_table[i]->list;
+	tsdev_table[i]->list = list;
+	file->private_data = list;
+
+	if (!list->tsdev->open++)
+		if (list->tsdev->exist)
+			input_open_device(&list->tsdev->handle);
+	return 0;
+}
+
+static int tsdev_release(struct inode *inode, struct file *file)
+{
+	struct tsdev_list *list = file->private_data;
+	struct tsdev_list **listptr;
+
+	listptr = &list->tsdev->list;
+	tsdev_fasync(-1, file, 0);
+
+	while (*listptr && (*listptr != list))
+		listptr = &((*listptr)->next);
+	*listptr = (*listptr)->next;
+
+	if (!--list->tsdev->open) {
+		if (list->tsdev->exist) {
+			input_close_device(&list->tsdev->handle);
+		} else {
+			input_unregister_minor(list->tsdev->devfs);
+			tsdev_table[list->tsdev->minor] = NULL;
+			kfree(list->tsdev);
+		}
+	}
+	kfree(list);
+	return 0;
+}
+
+static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
+			  loff_t * ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct tsdev_list *list = file->private_data;
+	int retval = 0;
+
+	if (list->head == list->tail) {
+		add_wait_queue(&list->tsdev->wait, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		while (list->head == list->tail) {
+			if (!list->tsdev->exist) {
+				retval = -ENODEV;
+				break;
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&list->tsdev->wait, &wait);
+	}
+
+	if (retval)
+		return retval;
+
+	while (list->head != list->tail
+	       && retval + sizeof(TS_EVENT) <= count) {
+		if (copy_to_user
+		    (buffer + retval, list->event + list->tail,
+		     sizeof(TS_EVENT)))
+			return -EFAULT;
+		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+		retval += sizeof(TS_EVENT);
+	}
+	return retval;
+}
+
+/* No kernel lock - fine */
+static unsigned int tsdev_poll(struct file *file, poll_table * wait)
+{
+	struct tsdev_list *list = file->private_data;
+
+	poll_wait(file, &list->tsdev->wait, wait);
+	if (list->head != list->tail)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int tsdev_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+/*
+	struct tsdev_list *list = file->private_data;
+        struct tsdev *evdev = list->tsdev;
+        struct input_dev *dev = tsdev->handle.dev;
+        int retval;
+	
+	switch (cmd) {
+		case HHEHE:
+			return 0;
+		case hjff:
+			return 0;
+		default:
+			return 0;
+	}
+*/
+	return -EINVAL;
+}
+
+struct file_operations tsdev_fops = {
+	owner:		THIS_MODULE,
+	open:		tsdev_open,
+	release:	tsdev_release,
+	read:		tsdev_read,
+	poll:		tsdev_poll,
+	fasync:		tsdev_fasync,
+	ioctl:		tsdev_ioctl,
+};
+
+static void tsdev_event(struct input_handle *handle, unsigned int type,
+			unsigned int code, int value)
+{
+	struct tsdev *tsdev = handle->private;
+	struct tsdev_list *list = tsdev->list;
+	struct timeval time;
+	int size;
+
+	while (list) {
+		switch (type) {
+		case EV_ABS:
+			switch (code) {
+			case ABS_X:
+				if (!list->pendown)
+					return;
+
+				size =
+				    handle->dev->absmax[ABS_X] -
+				    handle->dev->absmin[ABS_X];
+				if (size > 0)
+					list->oldx =
+					    ((value -
+					      handle->dev->absmin[ABS_X]) *
+					     xres / size);
+				else
+					list->oldx =
+					    ((value -
+					      handle->dev->absmin[ABS_X]));
+				break;
+			case ABS_Y:
+				if (!list->pendown)
+					return;
+
+				size =
+				    handle->dev->absmax[ABS_Y] -
+				    handle->dev->absmin[ABS_Y];
+				if (size > 0)
+					list->oldy =
+					    ((value -
+					      handle->dev->absmin[ABS_Y]) *
+					     yres / size);
+				else
+					list->oldy =
+					    ((value -
+					      handle->dev->absmin[ABS_Y]));
+				break;
+			case ABS_PRESSURE:
+				list->pendown =
+				    ((value >
+				      handle->dev->
+				      absmin[ABS_PRESSURE])) ? value -
+				    handle->dev->absmin[ABS_PRESSURE] : 0;
+				break;
+			}
+			break;
+
+		case EV_REL:
+			switch (code) {
+			case REL_X:
+				if (!list->pendown)
+					return;
+
+				list->oldx += value;
+				if (list->oldx < 0)
+					list->oldx = 0;
+				else if (list->oldx > xres)
+					list->oldx = xres;
+				break;
+			case REL_Y:
+				if (!list->pendown)
+					return;
+
+				list->oldy += value;
+				if (list->oldy < 0)
+					list->oldy = 0;
+				else if (list->oldy > xres)
+					list->oldy = xres;
+				break;
+			}
+			break;
+
+		case EV_KEY:
+			if (code == BTN_TOUCH || code == BTN_MOUSE) {
+				switch (value) {
+				case 0:
+					list->pendown = 0;
+					break;
+				case 1:
+					if (!list->pendown)
+						list->pendown = 1;
+					break;
+				case 2:
+					return;
+				}
+			} else
+				return;
+			break;
+		}
+		do_gettimeofday(&time);
+		list->event[list->head].millisecs = time.tv_usec / 100;
+		list->event[list->head].pressure = list->pendown;
+		list->event[list->head].x = list->oldx;
+		list->event[list->head].y = list->oldy;
+		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		list = list->next;
+	}
+	wake_up_interruptible(&tsdev->wait);
+}
+
+static struct input_handle *tsdev_connect(struct input_handler *handler,
+					  struct input_dev *dev,
+					  struct input_device_id *id)
+{
+	struct tsdev *tsdev;
+	int minor;
+
+	for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+	     minor++);
+	if (minor == TSDEV_MINORS) {
+		printk(KERN_ERR
+		       "tsdev: You have way too many touchscreens\n");
+		return NULL;
+	}
+
+	if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
+		return NULL;
+	memset(tsdev, 0, sizeof(struct tsdev));
+	init_waitqueue_head(&tsdev->wait);
+
+	tsdev->minor = minor;
+	tsdev_table[minor] = tsdev;
+	sprintf(tsdev->name, "ts%d", minor);
+
+	tsdev->handle.dev = dev;
+	tsdev->handle.name = tsdev->name;
+	tsdev->handle.handler = handler;
+	tsdev->handle.private = tsdev;
+
+	tsdev->devfs =
+	    input_register_minor("ts%d", minor, TSDEV_MINOR_BASE);
+
+	tsdev->exist = 1;
+
+	return &tsdev->handle;
+}
+
+static void tsdev_disconnect(struct input_handle *handle)
+{
+	struct tsdev *tsdev = handle->private;
+
+	tsdev->exist = 0;
+
+	if (tsdev->open) {
+		input_close_device(handle);
+		wake_up_interruptible(&tsdev->wait);
+	} else {
+		input_unregister_minor(tsdev->devfs);
+		tsdev_table[tsdev->minor] = NULL;
+		kfree(tsdev);
+	}
+}
+
+static struct input_device_id tsdev_ids[] = {
+	{
+	      flags:	INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+	      evbit:	{ BIT(EV_KEY) | BIT(EV_REL) },
+	      keybit:	{ [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
+	      relbit:	{ BIT(REL_X) | BIT(REL_Y) },
+	 },/* A mouse like device, at least one button, two relative axes */
+
+	{
+	      flags:	INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+	      evbit:	{ BIT(EV_KEY) | BIT(EV_ABS) },
+	      keybit:	{ [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+	      absbit:	{ BIT(ABS_X) | BIT(ABS_Y) },
+	 },/* A tablet like device, at least touch detection, two absolute axes */
+
+	{},/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, tsdev_ids);
+
+static struct input_handler tsdev_handler = {
+	event:		tsdev_event,
+	connect:	tsdev_connect,
+	disconnect:	tsdev_disconnect,
+	fops:		&tsdev_fops,
+	minor:		TSDEV_MINOR_BASE,
+	name:		"tsdev",
+	id_table:	tsdev_ids,
+};
+
+static int __init tsdev_init(void)
+{
+	input_register_handler(&tsdev_handler);
+	printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
+	return 0;
+}
+
+static void __exit tsdev_exit(void)
+{
+	input_unregister_handler(&tsdev_handler);
+}
+
+module_init(tsdev_init);
+module_exit(tsdev_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input driver to touchscreen converter");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical screen resolution");
diff -Nru a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
--- a/drivers/isdn/capi/capifs.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/isdn/capi/capifs.c	Fri Jul  5 16:42:59 2002
@@ -221,11 +221,9 @@
 	kfree(sbi);
 }
 
-static int capifs_statfs(struct super_block *sb, struct statfs *buf);
-
 static struct super_operations capifs_sops = {
 	put_super:	capifs_put_super,
-	statfs:		capifs_statfs,
+	statfs:		simple_statfs,
 };
 
 static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
@@ -352,19 +350,6 @@
 	return 0;
 fail:
 	return -EINVAL;
-}
-
-static int capifs_statfs(struct super_block *sb, struct statfs *buf)
-{
-	buf->f_type = CAPIFS_SUPER_MAGIC;
-	buf->f_bsize = 1024;
-	buf->f_blocks = 0;
-	buf->f_bfree = 0;
-	buf->f_bavail = 0;
-	buf->f_files = 0;
-	buf->f_ffree = 0;
-	buf->f_namelen = NAME_MAX;
-	return 0;
 }
 
 static struct inode *capifs_new_inode(struct super_block *sb)
diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/md/linear.c	Fri Jul  5 16:42:59 2002
@@ -60,7 +60,6 @@
 			goto out;
 		}
 
-		disk->dev = rdev->dev;
 		disk->bdev = rdev->bdev;
 		atomic_inc(&rdev->bdev->bd_count);
 		disk->size = rdev->size;
@@ -163,7 +162,7 @@
     
 	if (block >= (tmp_dev->size + tmp_dev->offset)
 				|| block < tmp_dev->offset) {
-		printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset);
+		printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, bdevname(tmp_dev->bdev), tmp_dev->size, tmp_dev->offset);
 		bio_io_error(bio);
 		return 0;
 	}
@@ -186,11 +185,11 @@
 	for (j = 0; j < conf->nr_zones; j++)
 	{
 		sz += sprintf(page+sz, "[%s",
-			partition_name(conf->hash_table[j].dev0->dev));
+			bdev_partition_name(conf->hash_table[j].dev0->bdev));
 
 		if (conf->hash_table[j].dev1)
 			sz += sprintf(page+sz, "/%s] ",
-			  partition_name(conf->hash_table[j].dev1->dev));
+			  bdev_partition_name(conf->hash_table[j].dev1->bdev));
 		else
 			sz += sprintf(page+sz, "] ");
 	}
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/md/md.c	Fri Jul  5 16:42:59 2002
@@ -297,20 +297,20 @@
 	return dname->name;
 }
 
-static unsigned int calc_dev_sboffset(kdev_t dev, mddev_t *mddev,
+static unsigned int calc_dev_sboffset(mdk_rdev_t *rdev, mddev_t *mddev,
 						int persistent)
 {
-	unsigned int size = (blkdev_size_in_bytes(dev) >> BLOCK_SIZE_BITS);
+	unsigned int size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	if (persistent)
 		size = MD_NEW_SIZE_BLOCKS(size);
 	return size;
 }
 
-static unsigned int calc_dev_size(kdev_t dev, mddev_t *mddev, int persistent)
+static unsigned int calc_dev_size(mdk_rdev_t *rdev, mddev_t *mddev, int persistent)
 {
 	unsigned int size;
 
-	size = calc_dev_sboffset(dev, mddev, persistent);
+	size = calc_dev_sboffset(rdev, mddev, persistent);
 	if (!mddev->sb) {
 		MD_BUG();
 		return size;
@@ -467,7 +467,7 @@
 	 *
 	 * It also happens to be a multiple of 4Kb.
 	 */
-	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
+	sb_offset = calc_dev_sboffset(rdev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
 
 	if (!sync_page_io(rdev->bdev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ))
@@ -850,7 +850,7 @@
 		return 1;
 	}
 
-	sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1);
+	sb_offset = calc_dev_sboffset(rdev, rdev->mddev, 1);
 	if (rdev->sb_offset != sb_offset) {
 		printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n",
 		       partition_name(dev), rdev->sb_offset, sb_offset);
@@ -861,7 +861,7 @@
 	 * its size has changed to zero silently, and the MD code does
 	 * not yet know that it's faulty.
 	 */
-	size = calc_dev_size(dev, rdev->mddev, 1);
+	size = calc_dev_size(rdev, rdev->mddev, 1);
 	if (size != rdev->size) {
 		printk(KERN_INFO "%s's size has changed from %ld to %ld since import, skipping\n",
 		       partition_name(dev), rdev->size, size);
@@ -1001,19 +1001,19 @@
  *
  * a faulty rdev _never_ has rdev->sb set.
  */
-static int md_import_device(kdev_t newdev, int on_disk)
+static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk)
 {
 	int err;
 	mdk_rdev_t *rdev;
 	unsigned int size;
 
 	if (find_rdev_all(newdev))
-		return -EEXIST;
+		return ERR_PTR(-EEXIST);
 
 	rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL);
 	if (!rdev) {
 		printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(newdev));
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 	memset(rdev, 0, sizeof(*rdev));
 
@@ -1030,7 +1030,7 @@
 	rdev->desc_nr = -1;
 	rdev->faulty = 0;
 
-	size = (blkdev_size_in_bytes(newdev) >> BLOCK_SIZE_BITS);
+	size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	if (!size) {
 		printk(KERN_WARNING
 		       "md: %s has zero or unknown size, marking faulty!\n",
@@ -1066,7 +1066,7 @@
 
 	if (rdev->faulty && rdev->sb)
 		free_disk_sb(rdev);
-	return 0;
+	return rdev;
 
 abort_free:
 	if (rdev->sb) {
@@ -1075,7 +1075,7 @@
 		free_disk_sb(rdev);
 	}
 	kfree(rdev);
-	return err;
+	return ERR_PTR(err);
 }
 
 /*
@@ -1463,7 +1463,7 @@
 			MD_BUG();
 			continue;
 		}
-		rdev->size = calc_dev_size(rdev->dev, mddev, persistent);
+		rdev->size = calc_dev_size(rdev, mddev, persistent);
 		if (rdev->size < sb->chunk_size / 1024) {
 			printk(KERN_WARNING
 				"md: Dev %s smaller than chunk_size: %ldk < %dk\n",
@@ -1741,8 +1741,7 @@
 			md_unregister_thread(mddev->sync_thread);
 			mddev->sync_thread = NULL;
 			if (mddev->spare) {
-				mddev->pers->diskop(mddev, &mddev->spare,
-						    DISKOP_SPARE_INACTIVE);
+				mddev->pers->spare_inactive(mddev);
 				mddev->spare = NULL;
 			}
 		}
@@ -1951,16 +1950,12 @@
 	mdp_super_t *sb = NULL;
 	mdk_rdev_t *start_rdev = NULL, *rdev;
 
-	if (md_import_device(startdev, 1)) {
+	start_rdev = md_import_device(startdev, 1);
+	if (IS_ERR(start_rdev)) {
 		printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev));
 		goto abort;
 	}
 
-	start_rdev = find_rdev_all(startdev);
-	if (!start_rdev) {
-		MD_BUG();
-		goto abort;
-	}
 	if (start_rdev->faulty) {
 		printk(KERN_WARNING "md: can not autostart based on faulty %s!\n",
 						partition_name(startdev));
@@ -1989,16 +1984,12 @@
 			continue;
 		if (kdev_same(dev, startdev))
 			continue;
-		if (md_import_device(dev, 1)) {
+		rdev = md_import_device(dev, 1);
+		if (IS_ERR(rdev)) {
 			printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n",
 			       partition_name(dev));
 			continue;
 		}
-		rdev = find_rdev_all(dev);
-		if (!rdev) {
-			MD_BUG();
-			goto abort;
-		}
 		list_add(&rdev->pending, &pending_raid_disks);
 	}
 
@@ -2108,7 +2099,7 @@
 
 static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 {
-	int err, size, persistent;
+	int size, persistent;
 	mdk_rdev_t *rdev;
 	unsigned int nr;
 	kdev_t dev;
@@ -2121,14 +2112,9 @@
 	}
 	if (!mddev->sb) {
 		/* expecting a device which has a superblock */
-		err = md_import_device(dev, 1);
-		if (err) {
-			printk(KERN_WARNING "md: md_import_device returned %d\n", err);
-			return -EINVAL;
-		}
-		rdev = find_rdev_all(dev);
-		if (!rdev) {
-			MD_BUG();
+		rdev = md_import_device(dev, 1);
+		if (IS_ERR(rdev)) {
+			printk(KERN_WARNING "md: md_import_device returned %ld\n", PTR_ERR(rdev));
 			return -EINVAL;
 		}
 		if (!list_empty(&mddev->disks)) {
@@ -2165,17 +2151,11 @@
 	SET_SB(state);
 
 	if (!(info->state & (1<<MD_DISK_FAULTY))) {
-		err = md_import_device (dev, 0);
-		if (err) {
-			printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
+		rdev = md_import_device (dev, 0);
+		if (IS_ERR(rdev)) {
+			printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev));
 			return -EINVAL;
 		}
-		rdev = find_rdev_all(dev);
-		if (!rdev) {
-			MD_BUG();
-			return -EINVAL;
-		}
-
 		rdev->old_dev = dev;
 		rdev->desc_nr = info->number;
 
@@ -2185,8 +2165,8 @@
 		if (!persistent)
 			printk(KERN_INFO "md: nonpersistent superblock ...\n");
 
-		size = calc_dev_size(dev, mddev, persistent);
-		rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent);
+		size = calc_dev_size(rdev, mddev, persistent);
+		rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent);
 
 		if (!mddev->sb->size || (mddev->sb->size > size))
 			mddev->sb->size = size;
@@ -2250,7 +2230,7 @@
 	printk(KERN_INFO "md: trying to remove %s from md%d ... \n",
 		partition_name(dev), mdidx(mddev));
 
-	if (!mddev->pers->diskop) {
+	if (!mddev->pers->hot_remove_disk) {
 		printk(KERN_WARNING "md%d: personality does not support diskops!\n",
 		       mdidx(mddev));
 		return -EINVAL;
@@ -2274,7 +2254,7 @@
 		return -EINVAL;
 	}
 
-	err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
+	err = mddev->pers->hot_remove_disk(mddev, disk->number);
 	if (err == -EBUSY) {
 		MD_BUG();
 		goto busy;
@@ -2308,35 +2288,31 @@
 	printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n",
 		partition_name(dev), mdidx(mddev));
 
-	if (!mddev->pers->diskop) {
+	if (!mddev->pers->hot_add_disk) {
 		printk(KERN_WARNING "md%d: personality does not support diskops!\n",
 		       mdidx(mddev));
 		return -EINVAL;
 	}
 
-	persistent = !mddev->sb->not_persistent;
-	size = calc_dev_size(dev, mddev, persistent);
-
-	if (size < mddev->sb->size) {
-		printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n",
-				mdidx(mddev), size, mddev->sb->size);
-		return -ENOSPC;
-	}
-
 	rdev = find_rdev(mddev, dev);
 	if (rdev)
 		return -EBUSY;
 
-	err = md_import_device (dev, 0);
-	if (err) {
-		printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
+	rdev = md_import_device (dev, 0);
+	if (IS_ERR(rdev)) {
+		printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev));
 		return -EINVAL;
 	}
-	rdev = find_rdev_all(dev);
-	if (!rdev) {
-		MD_BUG();
-		return -EINVAL;
+	persistent = !mddev->sb->not_persistent;
+	size = calc_dev_size(rdev, mddev, persistent);
+
+	if (size < mddev->sb->size) {
+		printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n",
+				mdidx(mddev), size, mddev->sb->size);
+		err = -ENOSPC;
+		goto abort_export;
 	}
+
 	if (rdev->faulty) {
 		printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n",
 				partition_name(dev), mdidx(mddev));
@@ -2351,7 +2327,7 @@
 	 */
 	rdev->old_dev = dev;
 	rdev->size = size;
-	rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent);
+	rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent);
 
 	disk = mddev->sb->disks + mddev->sb->raid_disks;
 	for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) {
@@ -2386,7 +2362,7 @@
 	disk->major = major(dev);
 	disk->minor = minor(dev);
 
-	if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) {
+	if (mddev->pers->hot_add_disk(mddev, disk, rdev)) {
 		MD_BUG();
 		err = -EINVAL;
 		goto abort_unbind_export;
@@ -2922,7 +2898,7 @@
 	if (!rrdev || rrdev->faulty)
 		return 0;
 	if (!mddev->pers->error_handler
-			|| mddev->pers->error_handler(mddev,rdev) <= 0) {
+			|| mddev->pers->error_handler(mddev,bdev) <= 0) {
 		rrdev->faulty = 1;
 	} else
 		return 1;
@@ -3134,8 +3110,9 @@
 }
 
 static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK];
-void md_sync_acct(kdev_t dev, unsigned long nr_sectors)
+void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors)
 {
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	unsigned int major = major(dev);
 	unsigned int index;
 
@@ -3367,7 +3344,7 @@
 
 	ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) {
 		sb = mddev->sb;
-		if (!sb || !mddev->pers || !mddev->pers->diskop || mddev->ro)
+		if (!sb || !mddev->pers || mddev->ro)
 			goto unlock;
 		if (mddev->recovery_running > 0)
 			/* resync/recovery still happening */
@@ -3381,16 +3358,19 @@
 				 * If we were doing a reconstruction,
 				 * we need to retrieve the spare
 				 */
+				if (!mddev->pers->spare_inactive)
+					goto unlock;
 				if (mddev->spare) {
-					mddev->pers->diskop(mddev, &mddev->spare,
-							    DISKOP_SPARE_INACTIVE);
+					mddev->pers->spare_inactive(mddev);
 					mddev->spare = NULL;
 				}
 			} else {
+				if (!mddev->pers->spare_active)
+					goto unlock;
 				/* success...*/
 				if (mddev->spare) {
-					mddev->pers->diskop(mddev, &mddev->spare,
-							    DISKOP_SPARE_ACTIVE);
+					mddev->pers->spare_active(mddev,
+								&mddev->spare);
 					mark_disk_sync(mddev->spare);
 					mark_disk_active(mddev->spare);
 					sb->active_disks++;
@@ -3429,12 +3409,13 @@
 			if (!mddev->sync_thread) {
 				printk(KERN_ERR "md%d: could not start resync thread...\n", mdidx(mddev));
 				if (mddev->spare)
-					mddev->pers->diskop(mddev, &mddev->spare, DISKOP_SPARE_INACTIVE);
+					mddev->pers->spare_inactive(mddev);
 				mddev->spare = NULL;
 				mddev->recovery_running = 0;
 			} else {
 				if (mddev->spare)
-					mddev->pers->diskop(mddev, &mddev->spare, DISKOP_SPARE_WRITE);
+					mddev->pers->spare_write(mddev,
+						mddev->spare->number);
 				mddev->recovery_running = 1;
 				md_wakeup_thread(mddev->sync_thread);
 			}
@@ -3588,17 +3569,10 @@
 	for (i = 0; i < dev_cnt; i++) {
 		kdev_t dev = detected_devices[i];
 
-		if (md_import_device(dev,1)) {
+		rdev = md_import_device(dev,1);
+		if (IS_ERR(rdev)) {
 			printk(KERN_ALERT "md: could not import %s!\n",
 				partition_name(dev));
-			continue;
-		}
-		/*
-		 * Sanity checks:
-		 */
-		rdev = find_rdev_all(dev);
-		if (!rdev) {
-			MD_BUG();
 			continue;
 		}
 		if (rdev->faulty) {
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/md/multipath.c	Fri Jul  5 16:42:59 2002
@@ -55,9 +55,8 @@
 static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
 struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail;
 
-static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state);
-
-
+static int multipath_spare_write(mddev_t *, int);
+static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d);
 
 static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf)
 {
@@ -313,14 +312,14 @@
 	mddev->sb_dirty = 1;
 	md_wakeup_thread(conf->thread);
 	conf->working_disks--;
-	printk (DISK_FAILED, partition_name (multipath->dev),
+	printk (DISK_FAILED, bdev_partition_name (multipath->bdev),
 				 conf->working_disks);
 }
 
 /*
  * Careful, this can execute in IRQ contexts as well!
  */
-static int multipath_error (mddev_t *mddev, kdev_t dev)
+static int multipath_error (mddev_t *mddev, struct block_device *bdev)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
 	struct multipath_info * multipaths = conf->multipaths;
@@ -345,7 +344,7 @@
 		 * which has just failed.
 		 */
 		for (i = 0; i < disks; i++) {
-			if (kdev_same(multipaths[i].dev, dev) && !multipaths[i].operational)
+			if (multipaths[i].bdev == bdev && !multipaths[i].operational)
 				return 0;
 		}
 		printk (LAST_DISK);
@@ -354,7 +353,7 @@
 		 * Mark disk as unusable
 		 */
 		for (i = 0; i < disks; i++) {
-			if (kdev_same(multipaths[i].dev,dev) && multipaths[i].operational) {
+			if (multipaths[i].bdev == bdev && multipaths[i].operational) {
 				mark_disk_bad(mddev, i);
 				break;
 			}
@@ -366,11 +365,11 @@
 
 			spare = get_spare(mddev);
 			if (spare) {
-				err = multipath_diskop(mddev, &spare, DISKOP_SPARE_WRITE);
+				err = multipath_spare_write(mddev, spare->number);
 				printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare));
 			}
 			if (!err && !disk_faulty(spare)) {
-				multipath_diskop(mddev, &spare, DISKOP_SPARE_ACTIVE);
+				multipath_spare_active(mddev, &spare);
 				mark_disk_sync(spare);
 				mark_disk_active(spare);
 				sb->active_disks++;
@@ -406,259 +405,240 @@
 			printk(" disk%d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n",
 				i, tmp->spare,tmp->operational,
 				tmp->number,tmp->raid_disk,tmp->used_slot,
-				partition_name(tmp->dev));
+				bdev_partition_name(tmp->bdev));
 	}
 }
 
-static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
+/*
+ * Find the spare disk ... (can only be in the 'high' area of the array)
+ */
+static struct multipath_info *find_spare(mddev_t *mddev, int number)
 {
-	int err = 0;
-	int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1;
 	multipath_conf_t *conf = mddev->private;
-	struct multipath_info *tmp, *sdisk, *fdisk, *rdisk, *adisk;
-	mdp_super_t *sb = mddev->sb;
-	mdp_disk_t *failed_desc, *spare_desc, *added_desc;
-	mdk_rdev_t *spare_rdev, *failed_rdev;
-	struct block_device *bdev;
+	int i;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		struct multipath_info *p = conf->multipaths + i;
+		if (p->spare && p->number == number)
+			return p;
+	}
+	return NULL;
+}
+
+static int multipath_spare_inactive(mddev_t *mddev)
+{
+	multipath_conf_t *conf = mddev->private;
+	struct multipath_info *p;
+	int err = 0;
 
 	print_multipath_conf(conf);
 	spin_lock_irq(&conf->device_lock);
-	/*
-	 * find the disk ...
-	 */
-	switch (state) {
-
-	case DISKOP_SPARE_ACTIVE:
-
-		/*
-		 * Find the failed disk within the MULTIPATH configuration ...
-		 * (this can only be in the first conf->working_disks part)
-		 */
-		for (i = 0; i < conf->raid_disks; i++) {
-			tmp = conf->multipaths + i;
-			if ((!tmp->operational && !tmp->spare) ||
-					!tmp->used_slot) {
-				failed_disk = i;
-				break;
-			}
-		}
-		/*
-		 * When we activate a spare disk we _must_ have a disk in
-		 * the lower (active) part of the array to replace. 
-		 */
-		if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		/* fall through */
-
-	case DISKOP_SPARE_WRITE:
-	case DISKOP_SPARE_INACTIVE:
+	p = find_spare(mddev, mddev->spare->number);
+	if (p) {
+		p->operational = 0;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
 
-		/*
-		 * Find the spare disk ... (can only be in the 'high'
-		 * area of the array)
-		 */
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->multipaths + i;
-			if (tmp->spare && tmp->number == (*d)->number) {
-				spare_disk = i;
-				break;
-			}
-		}
-		if (spare_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
+	print_multipath_conf(conf);
+	return err;
+}
 
-	case DISKOP_HOT_REMOVE_DISK:
+static int multipath_spare_write(mddev_t *mddev, int number)
+{
+	multipath_conf_t *conf = mddev->private;
+	struct multipath_info *p;
+	int err = 0;
 
-		for (i = 0; i < MD_SB_DISKS; i++) {
-			tmp = conf->multipaths + i;
-			if (tmp->used_slot && (tmp->number == (*d)->number)) {
-				if (tmp->operational) {
-					printk(KERN_ERR "hot-remove-disk, slot %d is identified to be the requested disk (number %d), but is still operational!\n", i, (*d)->number);
-					err = -EBUSY;
-					goto abort;
-				}
-				removed_disk = i;
-				break;
-			}
-		}
-		if (removed_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
+	print_multipath_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	p = find_spare(mddev, number);
+	if (p) {
+		p->operational = 1;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
 
-	case DISKOP_HOT_ADD_DISK:
+	print_multipath_conf(conf);
+	return err;
+}
 
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->multipaths + i;
-			if (!tmp->used_slot) {
-				added_disk = i;
-				break;
-			}
-		}
-		if (added_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
-	}
+static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d)
+{
+	int err = 0;
+	int i, failed_disk=-1, spare_disk=-1;
+	multipath_conf_t *conf = mddev->private;
+	struct multipath_info *tmp, *sdisk, *fdisk;
+	mdp_super_t *sb = mddev->sb;
+	mdp_disk_t *failed_desc, *spare_desc;
+	mdk_rdev_t *spare_rdev, *failed_rdev;
 
-	switch (state) {
+	print_multipath_conf(conf);
+	spin_lock_irq(&conf->device_lock);
 	/*
-	 * Switch the spare disk to write-only mode:
+	 * Find the failed disk within the MULTIPATH configuration ...
+	 * (this can only be in the first conf->working_disks part)
 	 */
-	case DISKOP_SPARE_WRITE:
-		sdisk = conf->multipaths + spare_disk;
-		sdisk->operational = 1;
-		break;
+	for (i = 0; i < conf->raid_disks; i++) {
+		tmp = conf->multipaths + i;
+		if ((!tmp->operational && !tmp->spare) ||
+				!tmp->used_slot) {
+			failed_disk = i;
+			break;
+		}
+	}
 	/*
-	 * Deactivate a spare disk:
+	 * When we activate a spare disk we _must_ have a disk in
+	 * the lower (active) part of the array to replace. 
 	 */
-	case DISKOP_SPARE_INACTIVE:
-		sdisk = conf->multipaths + spare_disk;
-		sdisk->operational = 0;
-		break;
+	if (failed_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 	/*
-	 * Activate (mark read-write) the (now sync) spare disk,
-	 * which means we switch it's 'raid position' (->raid_disk)
-	 * with the failed disk. (only the first 'conf->nr_disks'
-	 * slots are used for 'real' disks and we must preserve this
-	 * property)
+	 * Find the spare disk ... (can only be in the 'high'
+	 * area of the array)
 	 */
-	case DISKOP_SPARE_ACTIVE:
-		sdisk = conf->multipaths + spare_disk;
-		fdisk = conf->multipaths + failed_disk;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		tmp = conf->multipaths + i;
+		if (tmp->spare && tmp->number == (*d)->number) {
+			spare_disk = i;
+			break;
+		}
+	}
+	if (spare_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 
-		spare_desc = &sb->disks[sdisk->number];
-		failed_desc = &sb->disks[fdisk->number];
+	sdisk = conf->multipaths + spare_disk;
+	fdisk = conf->multipaths + failed_disk;
 
-		if (spare_desc != *d) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	spare_desc = &sb->disks[sdisk->number];
+	failed_desc = &sb->disks[fdisk->number];
 
-		if (spare_desc->raid_disk != sdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-			
-		if (sdisk->raid_disk != spare_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
+	    sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
+	    failed_desc->raid_disk != fdisk->raid_disk) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 
-		if (failed_desc->raid_disk != fdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	/*
+	 * do the switch finally
+	 */
+	spare_rdev = find_rdev_nr(mddev, spare_desc->number);
+	failed_rdev = find_rdev_nr(mddev, failed_desc->number);
+	xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr);
+	spare_rdev->alias_device = 0;
+	failed_rdev->alias_device = 1;
 
-		if (fdisk->raid_disk != failed_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	xchg_values(*spare_desc, *failed_desc);
+	xchg_values(*fdisk, *sdisk);
 
-		/*
-		 * do the switch finally
-		 */
-		spare_rdev = find_rdev_nr(mddev, spare_desc->number);
-		failed_rdev = find_rdev_nr(mddev, failed_desc->number);
-		xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr);
-		spare_rdev->alias_device = 0;
-		failed_rdev->alias_device = 1;
+	/*
+	 * (careful, 'failed' and 'spare' are switched from now on)
+	 *
+	 * we want to preserve linear numbering and we want to
+	 * give the proper raid_disk number to the now activated
+	 * disk. (this means we switch back these values)
+	 */
 
-		xchg_values(*spare_desc, *failed_desc);
-		xchg_values(*fdisk, *sdisk);
+	xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
+	xchg_values(sdisk->raid_disk, fdisk->raid_disk);
+	xchg_values(spare_desc->number, failed_desc->number);
+	xchg_values(sdisk->number, fdisk->number);
 
-		/*
-		 * (careful, 'failed' and 'spare' are switched from now on)
-		 *
-		 * we want to preserve linear numbering and we want to
-		 * give the proper raid_disk number to the now activated
-		 * disk. (this means we switch back these values)
-		 */
-	
-		xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
-		xchg_values(sdisk->raid_disk, fdisk->raid_disk);
-		xchg_values(spare_desc->number, failed_desc->number);
-		xchg_values(sdisk->number, fdisk->number);
+	*d = failed_desc;
 
-		*d = failed_desc;
+	if (!sdisk->bdev)
+		sdisk->used_slot = 0;
+	/*
+	 * this really activates the spare.
+	 */
+	fdisk->spare = 0;
 
-		if (!sdisk->bdev)
-			sdisk->used_slot = 0;
-		/*
-		 * this really activates the spare.
-		 */
-		fdisk->spare = 0;
+	/*
+	 * if we activate a spare, we definitely replace a
+	 * non-operational disk slot in the 'low' area of
+	 * the disk array.
+	 */
 
-		/*
-		 * if we activate a spare, we definitely replace a
-		 * non-operational disk slot in the 'low' area of
-		 * the disk array.
-		 */
+	conf->working_disks++;
+abort:
+	spin_unlock_irq(&conf->device_lock);
 
-		conf->working_disks++;
+	print_multipath_conf(conf);
+	return err;
+}
 
-		break;
+static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
+	mdk_rdev_t *rdev)
+{
+	multipath_conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-	case DISKOP_HOT_REMOVE_DISK:
-		rdisk = conf->multipaths + removed_disk;
+	print_multipath_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		struct multipath_info *p = conf->multipaths + i;
+		if (!p->used_slot) {
+			if (added_desc->number != i)
+				break;
+			p->number = added_desc->number;
+			p->raid_disk = added_desc->raid_disk;
+			p->bdev = rdev->bdev;
+			p->operational = 0;
+			p->spare = 1;
+			p->used_slot = 1;
+			conf->nr_disks++;
+			err = 0;
+			break;
+		}
+	}
+	if (err)
+		MD_BUG();
+	spin_unlock_irq(&conf->device_lock);
 
-		if (rdisk->spare && (removed_disk < conf->raid_disks)) {
-			MD_BUG();	
-			err = 1;
-			goto abort;
-		}
-		bdev = rdisk->bdev;
-		rdisk->dev = NODEV;
-		rdisk->bdev = NULL;
-		rdisk->used_slot = 0;
-		conf->nr_disks--;
-		bdput(bdev);
-		break;
-
-	case DISKOP_HOT_ADD_DISK:
-		adisk = conf->multipaths + added_disk;
-		added_desc = *d;
-
-		if (added_disk != added_desc->number) {
-			MD_BUG();	
-			err = 1;
-			goto abort;
-		}
-
-		adisk->number = added_desc->number;
-		adisk->raid_disk = added_desc->raid_disk;
-		adisk->dev = mk_kdev(added_desc->major,added_desc->minor);
-		/* it will be held open by rdev */
-		adisk->bdev = bdget(kdev_t_to_nr(adisk->dev));
-
-		adisk->operational = 0;
-		adisk->spare = 1;
-		adisk->used_slot = 1;
-		conf->nr_disks++;
+	print_multipath_conf(conf);
+	return err;
+}
 
-		break;
+static int multipath_remove_disk(mddev_t *mddev, int number)
+{
+	multipath_conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-	default:
-		MD_BUG();
-		err = 1;
-		goto abort;
+	print_multipath_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+
+	for (i = 0; i < MD_SB_DISKS; i++) {
+		struct multipath_info *p = conf->multipaths + i;
+		if (p->used_slot && (p->number == number)) {
+			if (p->operational) {
+				printk(KERN_ERR "hot-remove-disk, slot %d is identified to be the requested disk (number %d), but is still operational!\n", i, number);
+				err = -EBUSY;
+				goto abort;
+			}
+			if (p->spare && i < conf->raid_disks)
+				break;
+			p->bdev = NULL;
+			p->used_slot = 0;
+			conf->nr_disks--;
+			err = 0;
+			break;
+		}
 	}
+	if (err)
+		MD_BUG();
 abort:
 	spin_unlock_irq(&conf->device_lock);
 
@@ -666,7 +646,6 @@
 	return err;
 }
 
-
 #define IO_ERROR KERN_ALERT \
 "multipath: %s: unrecoverable IO read error for block %lu\n"
 
@@ -872,7 +851,7 @@
 		if (rdev->faulty) {
 			/* this is a "should never happen" case and if it */
 			/* ever does happen, a continue; won't help */
-			printk(ERRORS, partition_name(rdev->dev));
+			printk(ERRORS, bdev_partition_name(rdev->bdev));
 			continue;
 		} else {
 			/* this is a "should never happen" case and if it */
@@ -892,7 +871,7 @@
 		disk = conf->multipaths + disk_idx;
 
 		if (!disk_sync(desc))
-			printk(NOT_IN_SYNC, partition_name(rdev->dev));
+			printk(NOT_IN_SYNC, bdev_partition_name(rdev->bdev));
 
 		/*
 		 * Mark all disks as spare to start with, then pick our
@@ -901,7 +880,6 @@
 		 */
 		disk->number = desc->number;
 		disk->raid_disk = desc->raid_disk;
-		disk->dev = rdev->dev;
 		disk->bdev = rdev->bdev;
 		atomic_inc(&rdev->bdev->bd_count);
 		disk->operational = 0;
@@ -911,7 +889,7 @@
 
 		if (disk_active(desc)) {
 			if(!conf->working_disks) {
-				printk(OPERATIONAL, partition_name(rdev->dev),
+				printk(OPERATIONAL, bdev_partition_name(rdev->bdev),
  					desc->raid_disk);
 				disk->operational = 1;
 				disk->spare = 0;
@@ -928,7 +906,7 @@
 	if(!conf->working_disks && num_rdevs) {
 		desc = &sb->disks[def_rdev->desc_nr];
 		disk = conf->multipaths + desc->raid_disk;
-		printk(OPERATIONAL, partition_name(def_rdev->dev),
+		printk(OPERATIONAL, bdev_partition_name(def_rdev->bdev),
 			disk->raid_disk);
 		disk->operational = 1;
 		disk->spare = 0;
@@ -1074,7 +1052,11 @@
 	stop:		multipath_stop,
 	status:		multipath_status,
 	error_handler:	multipath_error,
-	diskop:		multipath_diskop,
+	hot_add_disk:	multipath_add_disk,
+	hot_remove_disk:multipath_remove_disk,
+	spare_inactive:	multipath_spare_inactive,
+	spare_active:	multipath_spare_active,
+	spare_write:	multipath_spare_write,
 };
 
 static int __init multipath_init (void)
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Fri Jul  5 16:42:48 2002
+++ b/drivers/md/raid1.c	Fri Jul  5 16:42:48 2002
@@ -589,10 +589,10 @@
 	md_wakeup_thread(conf->thread);
 	if (!mirror->write_only)
 		conf->working_disks--;
-	printk(DISK_FAILED, partition_name(mirror->dev), conf->working_disks);
+	printk(DISK_FAILED, bdev_partition_name(mirror->bdev), conf->working_disks);
 }
 
-static int error(mddev_t *mddev, kdev_t dev)
+static int error(mddev_t *mddev, struct block_device *bdev)
 {
 	conf_t *conf = mddev_to_conf(mddev);
 	mirror_info_t * mirrors = conf->mirrors;
@@ -607,7 +607,7 @@
 	 * else mark the drive as failed
 	 */
 	for (i = 0; i < disks; i++)
-		if (kdev_same(mirrors[i].dev, dev) && mirrors[i].operational)
+		if (mirrors[i].bdev == bdev && mirrors[i].operational)
 			break;
 	if (i == disks)
 		return 0;
@@ -640,7 +640,7 @@
 		printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n",
 			i, tmp->spare, tmp->operational,
 			tmp->number, tmp->raid_disk, tmp->used_slot,
-			partition_name(tmp->dev));
+			bdev_partition_name(tmp->bdev));
 	}
 }
 
@@ -658,263 +658,242 @@
 	conf->r1buf_pool = NULL;
 }
 
-static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
+static mirror_info_t *find_spare(mddev_t *mddev, int number)
+{
+	conf_t *conf = mddev->private;
+	int i;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		mirror_info_t *p = conf->mirrors + i;
+		if (p->spare && p->number == number)
+			return p;
+	}
+	return NULL;
+}
+
+static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d)
 {
 	int err = 0;
-	int i, failed_disk = -1, spare_disk = -1, removed_disk = -1, added_disk = -1;
+	int i, failed_disk = -1, spare_disk = -1;
 	conf_t *conf = mddev->private;
-	mirror_info_t *tmp, *sdisk, *fdisk, *rdisk, *adisk;
+	mirror_info_t *tmp, *sdisk, *fdisk;
 	mdp_super_t *sb = mddev->sb;
-	mdp_disk_t *failed_desc, *spare_desc, *added_desc;
+	mdp_disk_t *failed_desc, *spare_desc;
 	mdk_rdev_t *spare_rdev, *failed_rdev;
-	struct block_device *bdev;
 
 	print_conf(conf);
 	spin_lock_irq(&conf->device_lock);
 	/*
-	 * find the disk ...
+	 * Find the failed disk within the RAID1 configuration ...
+	 * (this can only be in the first conf->working_disks part)
 	 */
-	switch (state) {
-
-	case DISKOP_SPARE_ACTIVE:
-
-		/*
-		 * Find the failed disk within the RAID1 configuration ...
-		 * (this can only be in the first conf->working_disks part)
-		 */
-		for (i = 0; i < conf->raid_disks; i++) {
-			tmp = conf->mirrors + i;
-			if ((!tmp->operational && !tmp->spare) ||
-					!tmp->used_slot) {
-				failed_disk = i;
-				break;
-			}
-		}
-		/*
-		 * When we activate a spare disk we _must_ have a disk in
-		 * the lower (active) part of the array to replace.
-		 */
-		if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		/* fall through */
-
-	case DISKOP_SPARE_WRITE:
-	case DISKOP_SPARE_INACTIVE:
-
-		/*
-		 * Find the spare disk ... (can only be in the 'high'
-		 * area of the array)
-		 */
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->mirrors + i;
-			if (tmp->spare && tmp->number == (*d)->number) {
-				spare_disk = i;
-				break;
-			}
-		}
-		if (spare_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
-
-	case DISKOP_HOT_REMOVE_DISK:
-
-		for (i = 0; i < MD_SB_DISKS; i++) {
-			tmp = conf->mirrors + i;
-			if (tmp->used_slot && (tmp->number == (*d)->number)) {
-				if (tmp->operational) {
-					err = -EBUSY;
-					goto abort;
-				}
-				removed_disk = i;
-				break;
-			}
-		}
-		if (removed_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
-
-	case DISKOP_HOT_ADD_DISK:
-
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->mirrors + i;
-			if (!tmp->used_slot) {
-				added_disk = i;
-				break;
-			}
-		}
-		if (added_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
+	for (i = 0; i < conf->raid_disks; i++) {
+		tmp = conf->mirrors + i;
+		if ((!tmp->operational && !tmp->spare) ||
+				!tmp->used_slot) {
+			failed_disk = i;
+			break;
 		}
-		break;
 	}
-
-	switch (state) {
 	/*
-	 * Switch the spare disk to write-only mode:
+	 * When we activate a spare disk we _must_ have a disk in
+	 * the lower (active) part of the array to replace.
 	 */
-	case DISKOP_SPARE_WRITE:
-		sdisk = conf->mirrors + spare_disk;
-		sdisk->operational = 1;
-		sdisk->write_only = 1;
-		break;
-	/*
-	 * Deactivate a spare disk:
-	 */
-	case DISKOP_SPARE_INACTIVE:
-		sdisk = conf->mirrors + spare_disk;
-		sdisk->operational = 0;
-		sdisk->write_only = 0;
-		break;
+	if (failed_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 	/*
-	 * Activate (mark read-write) the (now sync) spare disk,
-	 * which means we switch it's 'raid position' (->raid_disk)
-	 * with the failed disk. (only the first 'conf->nr_disks'
-	 * slots are used for 'real' disks and we must preserve this
-	 * property)
+	 * Find the spare disk ... (can only be in the 'high'
+	 * area of the array)
 	 */
-	case DISKOP_SPARE_ACTIVE:
-		sdisk = conf->mirrors + spare_disk;
-		fdisk = conf->mirrors + failed_disk;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		tmp = conf->mirrors + i;
+		if (tmp->spare && tmp->number == (*d)->number) {
+			spare_disk = i;
+			break;
+		}
+	}
+	if (spare_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 
-		spare_desc = &sb->disks[sdisk->number];
-		failed_desc = &sb->disks[fdisk->number];
+	sdisk = conf->mirrors + spare_disk;
+	fdisk = conf->mirrors + failed_disk;
 
-		if (spare_desc != *d) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	spare_desc = &sb->disks[sdisk->number];
+	failed_desc = &sb->disks[fdisk->number];
 
-		if (spare_desc->raid_disk != sdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
+	    sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
+	    failed_desc->raid_disk != fdisk->raid_disk) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 
-		if (sdisk->raid_disk != spare_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	/*
+	 * do the switch finally
+	 */
+	spare_rdev = find_rdev_nr(mddev, spare_desc->number);
+	failed_rdev = find_rdev_nr(mddev, failed_desc->number);
 
-		if (failed_desc->raid_disk != fdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	/*
+	 * There must be a spare_rdev, but there may not be a
+	 * failed_rdev. That slot might be empty...
+	 */
+	spare_rdev->desc_nr = failed_desc->number;
+	if (failed_rdev)
+		failed_rdev->desc_nr = spare_desc->number;
 
-		if (fdisk->raid_disk != failed_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	xchg_values(*spare_desc, *failed_desc);
+	xchg_values(*fdisk, *sdisk);
 
-		/*
-		 * do the switch finally
-		 */
-		spare_rdev = find_rdev_nr(mddev, spare_desc->number);
-		failed_rdev = find_rdev_nr(mddev, failed_desc->number);
+	/*
+	 * (careful, 'failed' and 'spare' are switched from now on)
+	 *
+	 * we want to preserve linear numbering and we want to
+	 * give the proper raid_disk number to the now activated
+	 * disk. (this means we switch back these values)
+	 */
+	xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
+	xchg_values(sdisk->raid_disk, fdisk->raid_disk);
+	xchg_values(spare_desc->number, failed_desc->number);
+	xchg_values(sdisk->number, fdisk->number);
 
-		/*
-		 * There must be a spare_rdev, but there may not be a
-		 * failed_rdev. That slot might be empty...
-		 */
-		spare_rdev->desc_nr = failed_desc->number;
-		if (failed_rdev)
-			failed_rdev->desc_nr = spare_desc->number;
+	*d = failed_desc;
 
-		xchg_values(*spare_desc, *failed_desc);
-		xchg_values(*fdisk, *sdisk);
+	if (!sdisk->bdev)
+		sdisk->used_slot = 0;
+	/*
+	 * this really activates the spare.
+	 */
+	fdisk->spare = 0;
+	fdisk->write_only = 0;
 
-		/*
-		 * (careful, 'failed' and 'spare' are switched from now on)
-		 *
-		 * we want to preserve linear numbering and we want to
-		 * give the proper raid_disk number to the now activated
-		 * disk. (this means we switch back these values)
-		 */
-		xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
-		xchg_values(sdisk->raid_disk, fdisk->raid_disk);
-		xchg_values(spare_desc->number, failed_desc->number);
-		xchg_values(sdisk->number, fdisk->number);
+	/*
+	 * if we activate a spare, we definitely replace a
+	 * non-operational disk slot in the 'low' area of
+	 * the disk array.
+	 */
 
-		*d = failed_desc;
+	conf->working_disks++;
+abort:
+	spin_unlock_irq(&conf->device_lock);
 
-		if (!sdisk->bdev)
-			sdisk->used_slot = 0;
-		/*
-		 * this really activates the spare.
-		 */
-		fdisk->spare = 0;
-		fdisk->write_only = 0;
+	print_conf(conf);
+	return err;
+}
 
-		/*
-		 * if we activate a spare, we definitely replace a
-		 * non-operational disk slot in the 'low' area of
-		 * the disk array.
-		 */
+static int raid1_spare_inactive(mddev_t *mddev)
+{
+	conf_t *conf = mddev->private;
+	mirror_info_t *p;
+	int err = 0;
 
-		conf->working_disks++;
+	print_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	p = find_spare(mddev, mddev->spare->number);
+	if (p) {
+		p->operational = 0;
+		p->write_only = 0;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
+	print_conf(conf);
+	return err;
+}
 
-		break;
+static int raid1_spare_write(mddev_t *mddev, int number)
+{
+	conf_t *conf = mddev->private;
+	mirror_info_t *p;
+	int err = 0;
 
-	case DISKOP_HOT_REMOVE_DISK:
-		rdisk = conf->mirrors + removed_disk;
+	print_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	p = find_spare(mddev, number);
+	if (p) {
+		p->operational = 1;
+		p->write_only = 1;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
+	print_conf(conf);
+	return err;
+}
 
-		if (rdisk->spare && (removed_disk < conf->raid_disks)) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		bdev = rdisk->bdev;
-		rdisk->dev = NODEV;
-		rdisk->bdev = NULL;
-		rdisk->used_slot = 0;
-		conf->nr_disks--;
-		bdput(bdev);
-		break;
-
-	case DISKOP_HOT_ADD_DISK:
-		adisk = conf->mirrors + added_disk;
-		added_desc = *d;
+static int raid1_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
+	mdk_rdev_t *rdev)
+{
+	conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-		if (added_disk != added_desc->number) {
-			MD_BUG();
-			err = 1;
-			goto abort;
+	print_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	/*
+	 * find the disk ...
+	 */
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		mirror_info_t *p = conf->mirrors + i;
+		if (!p->used_slot) {
+			if (added_desc->number != i)
+				break;
+			p->number = added_desc->number;
+			p->raid_disk = added_desc->raid_disk;
+			/* it will be held open by rdev */
+			p->bdev = rdev->bdev;
+			p->operational = 0;
+			p->write_only = 0;
+			p->spare = 1;
+			p->used_slot = 1;
+			p->head_position = 0;
+			conf->nr_disks++;
+			err = 0;
+			break;
 		}
+	}
+	if (err)
+		MD_BUG();
+	spin_unlock_irq(&conf->device_lock);
 
-		adisk->number = added_desc->number;
-		adisk->raid_disk = added_desc->raid_disk;
-		adisk->dev = mk_kdev(added_desc->major, added_desc->minor);
-		/* it will be held open by rdev */
-		adisk->bdev = bdget(kdev_t_to_nr(adisk->dev));
-
-		adisk->operational = 0;
-		adisk->write_only = 0;
-		adisk->spare = 1;
-		adisk->used_slot = 1;
-		adisk->head_position = 0;
-		conf->nr_disks++;
+	print_conf(conf);
+	return err;
+}
 
-		break;
+static int raid1_remove_disk(mddev_t *mddev, int number)
+{
+	conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-	default:
-		MD_BUG();
-		err = 1;
-		goto abort;
+	print_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	for (i = 0; i < MD_SB_DISKS; i++) {
+		mirror_info_t *p = conf->mirrors + i;
+		if (p->used_slot && (p->number == number)) {
+			if (p->operational) {
+				err = -EBUSY;
+				goto abort;
+			}
+			if (p->spare && (i < conf->raid_disks))
+				break;
+			p->bdev = NULL;
+			p->used_slot = 0;
+			conf->nr_disks--;
+			err = 0;
+			break;
+		}
 	}
+	if (err)
+		MD_BUG();
 abort:
 	spin_unlock_irq(&conf->device_lock);
 
@@ -922,7 +901,6 @@
 	return err;
 }
 
-
 #define IO_ERROR KERN_ALERT \
 "raid1: %s: unrecoverable I/O read error for block %lu\n"
 
@@ -1045,7 +1023,7 @@
 		if (!mbio)
 			continue;
 
-		md_sync_acct(to_kdev_t(mbio->bi_bdev->bd_dev), mbio->bi_size >> 9);
+		md_sync_acct(mbio->bi_bdev, mbio->bi_size >> 9);
 		generic_make_request(mbio);
 		atomic_inc(&conf->mirrors[i].nr_pending);
 	}
@@ -1217,7 +1195,7 @@
 		BUG();
 	r1_bio->read_bio = read_bio;
 
-	md_sync_acct(to_kdev_t(read_bio->bi_bdev->bd_dev), nr_sectors);
+	md_sync_acct(read_bio->bi_bdev, nr_sectors);
 
 	generic_make_request(read_bio);
 	atomic_inc(&conf->mirrors[conf->last_used].nr_pending);
@@ -1304,7 +1282,7 @@
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
 		if (rdev->faulty) {
-			printk(ERRORS, partition_name(rdev->dev));
+			printk(ERRORS, bdev_partition_name(rdev->bdev));
 		} else {
 			if (!rdev->sb) {
 				MD_BUG();
@@ -1322,7 +1300,6 @@
 		if (disk_faulty(descriptor)) {
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 			atomic_inc(&rdev->bdev->bd_count);
 			disk->operational = 0;
@@ -1335,27 +1312,26 @@
 		if (disk_active(descriptor)) {
 			if (!disk_sync(descriptor)) {
 				printk(NOT_IN_SYNC,
-					partition_name(rdev->dev));
+					bdev_partition_name(rdev->bdev));
 				continue;
 			}
 			if ((descriptor->number > MD_SB_DISKS) ||
 					(disk_idx > sb->raid_disks)) {
 
 				printk(INCONSISTENT,
-					partition_name(rdev->dev));
+					bdev_partition_name(rdev->bdev));
 				continue;
 			}
 			if (disk->operational) {
 				printk(ALREADY_RUNNING,
-					partition_name(rdev->dev),
+					bdev_partition_name(rdev->bdev),
 					disk_idx);
 				continue;
 			}
-			printk(OPERATIONAL, partition_name(rdev->dev),
+			printk(OPERATIONAL, bdev_partition_name(rdev->bdev),
 					disk_idx);
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 			atomic_inc(&rdev->bdev->bd_count);
 			disk->operational = 1;
@@ -1368,10 +1344,9 @@
 		/*
 		 * Must be a spare disk ..
 		 */
-			printk(SPARE, partition_name(rdev->dev));
+			printk(SPARE, bdev_partition_name(rdev->bdev));
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 			atomic_inc(&rdev->bdev->bd_count);
 			disk->operational = 0;
@@ -1405,7 +1380,6 @@
 				!disk->used_slot) {
 			disk->number = descriptor->number;
 			disk->raid_disk = disk_idx;
-			disk->dev = NODEV;
 			disk->bdev = NULL;
 			disk->operational = 0;
 			disk->write_only = 0;
@@ -1495,7 +1469,11 @@
 	stop:		stop,
 	status:		status,
 	error_handler:	error,
-	diskop:		diskop,
+	hot_add_disk:	raid1_add_disk,
+	hot_remove_disk:raid1_remove_disk,
+	spare_write:	raid1_spare_write,
+	spare_inactive:	raid1_spare_inactive,
+	spare_active:	raid1_spare_active,
 	sync_request:	sync_request
 };
 
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/md/raid5.c	Fri Jul  5 16:42:59 2002
@@ -439,7 +439,7 @@
 		dev->sector = compute_blocknr(sh, i);
 }
 
-static int error (mddev_t *mddev, kdev_t dev)
+static int error(mddev_t *mddev, struct block_device *bdev)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	mdp_super_t *sb = mddev->sb;
@@ -449,36 +449,36 @@
 	PRINTK("raid5: error called\n");
 
 	for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) {
-		if (kdev_same(disk->dev, dev)) {
-			if (disk->operational) {
-				disk->operational = 0;
-				mark_disk_faulty(sb->disks+disk->number);
-				mark_disk_nonsync(sb->disks+disk->number);
-				mark_disk_inactive(sb->disks+disk->number);
-				sb->active_disks--;
-				sb->working_disks--;
-				sb->failed_disks++;
-				mddev->sb_dirty = 1;
-				conf->working_disks--;
-				conf->failed_disks++;
-				md_wakeup_thread(conf->thread);
-				printk (KERN_ALERT
-					"raid5: Disk failure on %s, disabling device."
-					" Operation continuing on %d devices\n",
-					partition_name (dev), conf->working_disks);
-			}
-			return 0;
+		if (disk->bdev != bdev)
+			continue;
+		if (disk->operational) {
+			disk->operational = 0;
+			mark_disk_faulty(sb->disks+disk->number);
+			mark_disk_nonsync(sb->disks+disk->number);
+			mark_disk_inactive(sb->disks+disk->number);
+			sb->active_disks--;
+			sb->working_disks--;
+			sb->failed_disks++;
+			mddev->sb_dirty = 1;
+			conf->working_disks--;
+			conf->failed_disks++;
+			md_wakeup_thread(conf->thread);
+			printk (KERN_ALERT
+				"raid5: Disk failure on %s, disabling device."
+				" Operation continuing on %d devices\n",
+				bdev_partition_name(bdev), conf->working_disks);
 		}
+		return 0;
 	}
 	/*
 	 * handle errors in spares (during reconstruction)
 	 */
 	if (conf->spare) {
 		disk = conf->spare;
-		if (kdev_same(disk->dev, dev)) {
+		if (disk->bdev == bdev) {
 			printk (KERN_ALERT
 				"raid5: Disk failure on spare %s\n",
-				partition_name (dev));
+				bdev_partition_name (bdev));
 			if (!conf->spare->operational) {
 				/* probably a SET_DISK_FAULTY ioctl */
 				return -EIO;
@@ -1017,7 +1017,7 @@
 					locked++;
 					PRINTK("Reading block %d (sync=%d)\n", i, syncing);
 					if (syncing)
-						md_sync_acct(conf->disks[i].dev, STRIPE_SECTORS);
+						md_sync_acct(conf->disks[i].bdev, STRIPE_SECTORS);
 				}
 			}
 		}
@@ -1156,9 +1156,9 @@
 			locked++;
 			set_bit(STRIPE_INSYNC, &sh->state);
 			if (conf->disks[failed_num].operational)
-				md_sync_acct(conf->disks[failed_num].dev, STRIPE_SECTORS);
+				md_sync_acct(conf->disks[failed_num].bdev, STRIPE_SECTORS);
 			else if ((spare=conf->spare))
-				md_sync_acct(spare->dev, STRIPE_SECTORS);
+				md_sync_acct(spare->bdev, STRIPE_SECTORS);
 
 		}
 	}
@@ -1428,14 +1428,13 @@
 		disk = conf->disks + raid_disk;
 
 		if (disk_faulty(desc)) {
-			printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", partition_name(rdev->dev));
+			printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", bdev_partition_name(rdev->bdev));
 			if (!rdev->faulty) {
 				MD_BUG();
 				goto abort;
 			}
 			disk->number = desc->number;
 			disk->raid_disk = raid_disk;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 
 			disk->operational = 0;
@@ -1446,23 +1445,22 @@
 		}
 		if (disk_active(desc)) {
 			if (!disk_sync(desc)) {
-				printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", partition_name(rdev->dev));
+				printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", bdev_partition_name(rdev->bdev));
 				MD_BUG();
 				goto abort;
 			}
 			if (raid_disk > sb->raid_disks) {
-				printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", partition_name(rdev->dev));
+				printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", bdev_partition_name(rdev->bdev));
 				continue;
 			}
 			if (disk->operational) {
-				printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", partition_name(rdev->dev), raid_disk);
+				printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", bdev_partition_name(rdev->bdev), raid_disk);
 				continue;
 			}
-			printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", partition_name(rdev->dev), raid_disk);
+			printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", bdev_partition_name(rdev->bdev), raid_disk);
 	
 			disk->number = desc->number;
 			disk->raid_disk = raid_disk;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 			disk->operational = 1;
 			disk->used_slot = 1;
@@ -1472,10 +1470,9 @@
 			/*
 			 * Must be a spare disk ..
 			 */
-			printk(KERN_INFO "raid5: spare disk %s\n", partition_name(rdev->dev));
+			printk(KERN_INFO "raid5: spare disk %s\n", bdev_partition_name(rdev->bdev));
 			disk->number = desc->number;
 			disk->raid_disk = raid_disk;
-			disk->dev = rdev->dev;
 			disk->bdev = rdev->bdev;
 
 			disk->operational = 0;
@@ -1495,7 +1492,6 @@
 
 			disk->number = desc->number;
 			disk->raid_disk = raid_disk;
-			disk->dev = NODEV;
 			disk->bdev = NULL;
 
 			disk->operational = 0;
@@ -1691,282 +1687,246 @@
 		printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n",
 			i, tmp->spare,tmp->operational,
 			tmp->number,tmp->raid_disk,tmp->used_slot,
-			partition_name(tmp->dev));
+			bdev_partition_name(tmp->bdev));
+	}
+}
+
+static struct disk_info *find_spare(mddev_t *mddev, int number)
+{
+	raid5_conf_t *conf = mddev->private;
+	int i;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		struct disk_info *p = conf->disks + i;
+		if (p->spare && p->number == number)
+			return p;
 	}
+	return NULL;
 }
 
-static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
+static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d)
 {
 	int err = 0;
-	int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1;
+	int i, failed_disk=-1, spare_disk=-1;
 	raid5_conf_t *conf = mddev->private;
-	struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk;
+	struct disk_info *tmp, *sdisk, *fdisk;
 	mdp_super_t *sb = mddev->sb;
-	mdp_disk_t *failed_desc, *spare_desc, *added_desc;
+	mdp_disk_t *failed_desc, *spare_desc;
 	mdk_rdev_t *spare_rdev, *failed_rdev;
 
 	print_raid5_conf(conf);
 	spin_lock_irq(&conf->device_lock);
+	for (i = 0; i < conf->raid_disks; i++) {
+		tmp = conf->disks + i;
+		if ((!tmp->operational && !tmp->spare) ||
+				!tmp->used_slot) {
+			failed_disk = i;
+			break;
+		}
+	}
+	if (failed_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 	/*
-	 * find the disk ...
+	 * Find the spare disk ... (can only be in the 'high'
+	 * area of the array)
 	 */
-	switch (state) {
-
-	case DISKOP_SPARE_ACTIVE:
-
-		/*
-		 * Find the failed disk within the RAID5 configuration ...
-		 * (this can only be in the first conf->raid_disks part)
-		 */
-		for (i = 0; i < conf->raid_disks; i++) {
-			tmp = conf->disks + i;
-			if ((!tmp->operational && !tmp->spare) ||
-					!tmp->used_slot) {
-				failed_disk = i;
-				break;
-			}
-		}
-		/*
-		 * When we activate a spare disk we _must_ have a disk in
-		 * the lower (active) part of the array to replace.
-		 */
-		if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		/* fall through */
-
-	case DISKOP_SPARE_WRITE:
-	case DISKOP_SPARE_INACTIVE:
-
-		/*
-		 * Find the spare disk ... (can only be in the 'high'
-		 * area of the array)
-		 */
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->disks + i;
-			if (tmp->spare && tmp->number == (*d)->number) {
-				spare_disk = i;
-				break;
-			}
-		}
-		if (spare_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		tmp = conf->disks + i;
+		if (tmp->spare && tmp->number == (*d)->number) {
+			spare_disk = i;
+			break;
 		}
-		break;
-
-	case DISKOP_HOT_REMOVE_DISK:
+	}
+	if (spare_disk == -1) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
 
-		for (i = 0; i < MD_SB_DISKS; i++) {
-			tmp = conf->disks + i;
-			if (tmp->used_slot && (tmp->number == (*d)->number)) {
-				if (tmp->operational) {
-					err = -EBUSY;
-					goto abort;
-				}
-				removed_disk = i;
-				break;
-			}
-		}
-		if (removed_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
+	if (!conf->spare) {
+		MD_BUG();
+		err = 1;
+		goto abort;
+	}
+	sdisk = conf->disks + spare_disk;
+	fdisk = conf->disks + failed_disk;
 
-	case DISKOP_HOT_ADD_DISK:
+	spare_desc = &sb->disks[sdisk->number];
+	failed_desc = &sb->disks[fdisk->number];
 
-		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
-			tmp = conf->disks + i;
-			if (!tmp->used_slot) {
-				added_disk = i;
-				break;
-			}
-		}
-		if (added_disk == -1) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		break;
+	if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
+	    sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
+	    failed_desc->raid_disk != fdisk->raid_disk) {
+		MD_BUG();
+		err = 1;
+		goto abort;
 	}
 
-	switch (state) {
 	/*
-	 * Switch the spare disk to write-only mode:
+	 * do the switch finally
 	 */
-	case DISKOP_SPARE_WRITE:
-		if (conf->spare) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		sdisk = conf->disks + spare_disk;
-		sdisk->operational = 1;
-		sdisk->write_only = 1;
-		conf->spare = sdisk;
-		break;
-	/*
-	 * Deactivate a spare disk:
+	spare_rdev = find_rdev_nr(mddev, spare_desc->number);
+	failed_rdev = find_rdev_nr(mddev, failed_desc->number);
+
+	/* There must be a spare_rdev, but there may not be a
+	 * failed_rdev.  That slot might be empty...
 	 */
-	case DISKOP_SPARE_INACTIVE:
-		sdisk = conf->disks + spare_disk;
-		sdisk->operational = 0;
-		sdisk->write_only = 0;
-		/*
-		 * Was the spare being resynced?
-		 */
-		if (conf->spare == sdisk)
-			conf->spare = NULL;
-		break;
+	spare_rdev->desc_nr = failed_desc->number;
+	if (failed_rdev)
+		failed_rdev->desc_nr = spare_desc->number;
+	
+	xchg_values(*spare_desc, *failed_desc);
+	xchg_values(*fdisk, *sdisk);
+
 	/*
-	 * Activate (mark read-write) the (now sync) spare disk,
-	 * which means we switch it's 'raid position' (->raid_disk)
-	 * with the failed disk. (only the first 'conf->raid_disks'
-	 * slots are used for 'real' disks and we must preserve this
-	 * property)
+	 * (careful, 'failed' and 'spare' are switched from now on)
+	 *
+	 * we want to preserve linear numbering and we want to
+	 * give the proper raid_disk number to the now activated
+	 * disk. (this means we switch back these values)
 	 */
-	case DISKOP_SPARE_ACTIVE:
-		if (!conf->spare) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-		sdisk = conf->disks + spare_disk;
-		fdisk = conf->disks + failed_disk;
-
-		spare_desc = &sb->disks[sdisk->number];
-		failed_desc = &sb->disks[fdisk->number];
-
-		if (spare_desc != *d) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
 
-		if (spare_desc->raid_disk != sdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-			
-		if (sdisk->raid_disk != spare_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
+	xchg_values(sdisk->raid_disk, fdisk->raid_disk);
+	xchg_values(spare_desc->number, failed_desc->number);
+	xchg_values(sdisk->number, fdisk->number);
 
-		if (failed_desc->raid_disk != fdisk->raid_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
+	*d = failed_desc;
 
-		if (fdisk->raid_disk != failed_disk) {
-			MD_BUG();
-			err = 1;
-			goto abort;
-		}
-
-		/*
-		 * do the switch finally
-		 */
-		spare_rdev = find_rdev_nr(mddev, spare_desc->number);
-		failed_rdev = find_rdev_nr(mddev, failed_desc->number);
-
-		/* There must be a spare_rdev, but there may not be a
-		 * failed_rdev.  That slot might be empty...
-		 */
-		spare_rdev->desc_nr = failed_desc->number;
-		if (failed_rdev)
-			failed_rdev->desc_nr = spare_desc->number;
-		
-		xchg_values(*spare_desc, *failed_desc);
-		xchg_values(*fdisk, *sdisk);
-
-		/*
-		 * (careful, 'failed' and 'spare' are switched from now on)
-		 *
-		 * we want to preserve linear numbering and we want to
-		 * give the proper raid_disk number to the now activated
-		 * disk. (this means we switch back these values)
-		 */
-	
-		xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
-		xchg_values(sdisk->raid_disk, fdisk->raid_disk);
-		xchg_values(spare_desc->number, failed_desc->number);
-		xchg_values(sdisk->number, fdisk->number);
+	if (!sdisk->bdev)
+		sdisk->used_slot = 0;
 
-		*d = failed_desc;
+	/*
+	 * this really activates the spare.
+	 */
+	fdisk->spare = 0;
+	fdisk->write_only = 0;
 
-		if (kdev_none(sdisk->dev))
-			sdisk->used_slot = 0;
+	/*
+	 * if we activate a spare, we definitely replace a
+	 * non-operational disk slot in the 'low' area of
+	 * the disk array.
+	 */
+	conf->failed_disks--;
+	conf->working_disks++;
+	conf->spare = NULL;
+abort:
+	spin_unlock_irq(&conf->device_lock);
+	print_raid5_conf(conf);
+	return err;
+}
 
-		/*
-		 * this really activates the spare.
-		 */
-		fdisk->spare = 0;
-		fdisk->write_only = 0;
+static int raid5_spare_inactive(mddev_t *mddev)
+{
+	raid5_conf_t *conf = mddev->private;
+	struct disk_info *p;
+	int err = 0;
 
-		/*
-		 * if we activate a spare, we definitely replace a
-		 * non-operational disk slot in the 'low' area of
-		 * the disk array.
-		 */
-		conf->failed_disks--;
-		conf->working_disks++;
-		conf->spare = NULL;
+	print_raid5_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	p = find_spare(mddev, mddev->spare->number);
+	if (p) {
+		p->operational = 0;
+		p->write_only = 0;
+		if (conf->spare == p)
+			conf->spare = NULL;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
+	print_raid5_conf(conf);
+	return err;
+}
 
-		break;
+static int raid5_spare_write(mddev_t *mddev, int number)
+{
+	raid5_conf_t *conf = mddev->private;
+	struct disk_info *p;
+	int err = 0;
 
-	case DISKOP_HOT_REMOVE_DISK:
-		rdisk = conf->disks + removed_disk;
+	print_raid5_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	p = find_spare(mddev, number);
+	if (p && !conf->spare) {
+		p->operational = 1;
+		p->write_only = 1;
+		conf->spare = p;
+	} else {
+		MD_BUG();
+		err = 1;
+	}
+	spin_unlock_irq(&conf->device_lock);
+	print_raid5_conf(conf);
+	return err;
+}
 
-		if (rdisk->spare && (removed_disk < conf->raid_disks)) {
-			MD_BUG();	
-			err = 1;
-			goto abort;
-		}
-		rdisk->dev = NODEV;
-		rdisk->bdev = NULL;
-		rdisk->used_slot = 0;
+static int raid5_remove_disk(mddev_t *mddev, int number)
+{
+	raid5_conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-		break;
+	print_raid5_conf(conf);
+	spin_lock_irq(&conf->device_lock);
 
-	case DISKOP_HOT_ADD_DISK:
-		adisk = conf->disks + added_disk;
-		added_desc = *d;
-
-		if (added_disk != added_desc->number) {
-			MD_BUG();	
-			err = 1;
-			goto abort;
+	for (i = 0; i < MD_SB_DISKS; i++) {
+		struct disk_info *p = conf->disks + i;
+		if (p->used_slot && p->number == number) {
+			if (p->operational) {
+				err = -EBUSY;
+				goto abort;
+			}
+			if (p->spare && i < conf->raid_disks)
+				break;
+			p->bdev = NULL;
+			p->used_slot = 0;
+			err = 0;
+			break;
 		}
+	}
+	if (err)
+		MD_BUG();
+abort:
+	spin_unlock_irq(&conf->device_lock);
+	print_raid5_conf(conf);
+	return err;
+}
 
-		adisk->number = added_desc->number;
-		adisk->raid_disk = added_desc->raid_disk;
-		adisk->dev = mk_kdev(added_desc->major,added_desc->minor);
-		/* it will be held open by rdev */
-		adisk->bdev = bdget(kdev_t_to_nr(adisk->dev));
-
-		adisk->operational = 0;
-		adisk->write_only = 0;
-		adisk->spare = 1;
-		adisk->used_slot = 1;
-
+static int raid5_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
+	mdk_rdev_t *rdev)
+{
+	raid5_conf_t *conf = mddev->private;
+	int err = 1;
+	int i;
 
-		break;
+	print_raid5_conf(conf);
+	spin_lock_irq(&conf->device_lock);
+	/*
+	 * find the disk ...
+	 */
 
-	default:
-		MD_BUG();	
-		err = 1;
-		goto abort;
+	for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+		struct disk_info *p = conf->disks + i;
+		if (!p->used_slot) {
+			if (added_desc->number != i)
+				break;
+			p->number = added_desc->number;
+			p->raid_disk = added_desc->raid_disk;
+			/* it will be held open by rdev */
+			p->bdev = rdev->bdev;
+			p->operational = 0;
+			p->write_only = 0;
+			p->spare = 1;
+			p->used_slot = 1;
+			err = 0;
+			break;
+		}
 	}
-abort:
+	if (err)
+		MD_BUG();
 	spin_unlock_irq(&conf->device_lock);
 	print_raid5_conf(conf);
 	return err;
@@ -1980,7 +1940,11 @@
 	stop:		stop,
 	status:		status,
 	error_handler:	error,
-	diskop:		diskop,
+	hot_add_disk:	raid5_add_disk,
+	hot_remove_disk:raid5_remove_disk,
+	spare_write:	raid5_spare_write,
+	spare_inactive:	raid5_spare_inactive,
+	spare_active:	raid5_spare_active,
 	sync_request:	sync_request
 };
 
diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
--- a/drivers/message/fusion/Makefile	Fri Jul  5 16:43:00 2002
+++ b/drivers/message/fusion/Makefile	Fri Jul  5 16:43:00 2002
@@ -51,9 +51,3 @@
 obj-$(CONFIG_FUSION_LAN)	+= mptlan.o
 
 include $(TOPDIR)/Rules.make
-
-
-#  EXP...
-## Fusion MPT extra's...
-##mptscsih.o: $(mptscsih-objs)
-##	$(LD) -r -o $@ $(mptscsih-objs)
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Fri Jul  5 16:42:44 2002
+++ b/drivers/net/3c59x.c	Fri Jul  5 16:42:44 2002
@@ -174,6 +174,10 @@
     - Add `global_options' as default for options[].  Ditto global_enable_wol,
       global_full_duplex.
 
+   LK1.1.18 01Jul02 akpm
+    - Fix for undocumented transceiver power-up bit on some 3c566B's
+      (Donald Becker, Rahul Karnik)
+
     - See http://www.zip.com.au/~akpm/linux/#3c59x-2.3 for more details.
     - Also see Documentation/networking/vortex.txt
 */
@@ -189,8 +193,8 @@
 
 
 #define DRV_NAME	"3c59x"
-#define DRV_VERSION	"LK1.1.17"
-#define DRV_RELDATE	"18 Dec 2001"
+#define DRV_VERSION	"LK1.1.18"
+#define DRV_RELDATE	"1 Jul 2002"
 
 
 
@@ -414,7 +418,7 @@
 	EEPROM_8BIT=0x10,	/* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
 	HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
 	INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
-	EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000 };
+	EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000 };
 
 enum vortex_chips {
 	CH_3C590 = 0,
@@ -522,7 +526,7 @@
 									HAS_HWCKSM, 128, },
 	{"3c556B Laptop Hurricane",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
-									HAS_HWCKSM, 128, },
+	                                WNO_XCVR_PWR|HAS_HWCKSM, 128, },
 	{"3c575 [Megahertz] 10/100 LAN 	CardBus",
 	PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
 
@@ -1222,6 +1226,10 @@
 		if (vp->drv_flags & INVERT_MII_PWR)
 			n |= 0x4000;
 		outw(n, ioaddr + Wn2_ResetOptions);
+		if (vp->drv_flags & WNO_XCVR_PWR) {
+			EL3WINDOW(0);
+			outw(0x0800, ioaddr);
+		}
 	}
 
 	/* Extract our information from the EEPROM data. */
diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
--- a/drivers/net/e100/e100.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/net/e100/e100.h	Fri Jul  5 16:42:59 2002
@@ -1031,14 +1031,6 @@
 extern unsigned char e100_get_link_state(struct e100_private *bdp);
 extern unsigned char e100_wait_scb(struct e100_private *bdp);
 
-#ifndef yield
-#define yield()					\
-        do {					\
-                current->policy |= SCHED_YIELD;	\
-                schedule();			\
-        } while (0)                                     
-#endif
-
 extern void e100_deisolate_driver(struct e100_private *bdp,
 				  u8 recover, u8 full_reset);
 extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
diff -Nru a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile
--- a/drivers/net/hamradio/soundmodem/Makefile	Fri Jul  5 16:42:56 2002
+++ b/drivers/net/hamradio/soundmodem/Makefile	Fri Jul  5 16:42:56 2002
@@ -32,5 +32,5 @@
 $(obj)/sm_fsk9600.o:    $(obj)/sm_tbl_fsk9600.h
 
 $(obj)/sm_tbl_%: $(obj)/gentbl
-	$<
+	$(obj)/gentbl
 
diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c
--- a/drivers/pci/pool.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/pci/pool.c	Fri Jul  5 16:43:00 2002
@@ -303,15 +303,15 @@
 
 #ifdef	CONFIG_DEBUG_SLAB
 	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
-		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
+		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%Lx\n",
 			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, (unsigned long) dma);
+			pool->name, vaddr, (unsigned long long) dma);
 		return;
 	}
 	if (page->bitmap [map] & (1UL << block)) {
-		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
+		printk (KERN_ERR "pci_pool_free %s/%s, dma %Lx already free\n",
 			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, dma);
+			pool->name, (unsigned long long)dma);
 		return;
 	}
 	memset (vaddr, POOL_POISON_BYTE, pool->size);
diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/53c700.c	Fri Jul  5 16:42:59 2002
@@ -283,6 +283,7 @@
 	tpnt->cmd_per_lun = NCR_700_MAX_TAGS;
 	tpnt->use_clustering = DISABLE_CLUSTERING;
 	tpnt->proc_info = NCR_700_proc_directory_info;
+	tpnt->use_blk_tcq = 1;
 	
 	if(tpnt->name == NULL)
 		tpnt->name = "53c700";
@@ -498,46 +499,12 @@
 free_slot(struct NCR_700_command_slot *slot,
 	  struct NCR_700_Host_Parameters *hostdata)
 {
-	int hash;
-	struct NCR_700_command_slot **forw, **back;
-
-
 	if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
 		printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
 	}
 	if(slot->state == NCR_700_SLOT_FREE) {
 		printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
 	}
-	/* remove from queues */
-	if(slot->tag != NCR_700_NO_TAG) {
-		hash = hash_ITLQ(slot->cmnd->target, slot->cmnd->lun,
-				 slot->tag);
-		if(slot->ITLQ_forw == NULL)
-			back = &hostdata->ITLQ_Hash_back[hash];
-		else
-			back = &slot->ITLQ_forw->ITLQ_back;
-
-		if(slot->ITLQ_back == NULL)
-			forw = &hostdata->ITLQ_Hash_forw[hash];
-		else
-			forw = &slot->ITLQ_back->ITLQ_forw;
-
-		*forw = slot->ITLQ_forw;
-		*back = slot->ITLQ_back;
-	}
-	hash = hash_ITL(slot->cmnd->target, slot->cmnd->lun);
-	if(slot->ITL_forw == NULL)
-		back = &hostdata->ITL_Hash_back[hash];
-	else
-		back = &slot->ITL_forw->ITL_back;
-	
-	if(slot->ITL_back == NULL)
-		forw = &hostdata->ITL_Hash_forw[hash];
-	else
-		forw = &slot->ITL_back->ITL_forw;
-	
-	*forw = slot->ITL_forw;
-	*back = slot->ITL_back;
 	
 	slot->resume_offset = 0;
 	slot->cmnd = NULL;
@@ -565,48 +532,6 @@
 	hostdata->cmd = NULL;
 }
 
-/* Most likely nexus is the oldest in each case */
-STATIC inline struct NCR_700_command_slot *
-find_ITL_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun)
-{
-	int hash = hash_ITL(pun, lun);
-	struct NCR_700_command_slot *slot = hostdata->ITL_Hash_back[hash];
-	while(slot != NULL && !(slot->cmnd->target == pun &&
-				slot->cmnd->lun == lun))
-		slot = slot->ITL_back;
-	return slot;
-}
-
-STATIC inline struct NCR_700_command_slot *
-find_ITLQ_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun,
-		__u8 lun, __u8 tag)
-{
-	int hash = hash_ITLQ(pun, lun, tag);
-	struct NCR_700_command_slot *slot = hostdata->ITLQ_Hash_back[hash];
-
-	while(slot != NULL && !(slot->cmnd->target == pun 
-	      && slot->cmnd->lun == lun && slot->tag == tag))
-		slot = slot->ITLQ_back;
-
-#ifdef NCR_700_TAG_DEBUG
-	if(slot != NULL) {
-		struct NCR_700_command_slot *n = slot->ITLQ_back;
-		while(n != NULL && n->cmnd->target != pun
-		      && n->cmnd->lun != lun && n->tag != tag)
-			n = n->ITLQ_back;
-
-		if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun
-		   && n->tag == tag) {
-			printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n",
-			       tag);
-		}
-	}
-#endif
-	return slot;
-}
-
-
-
 /* This translates the SDTR message offset and period to a value
  * which can be loaded into the SXFER_REG.
  *
@@ -696,7 +621,6 @@
 			SCp->underflow = SCp->old_underflow;
 			
 		}
-
 		free_slot(slot, hostdata);
 #ifdef NCR_700_DEBUG
 		if(NCR_700_get_depth(SCp->device) == 0 ||
@@ -1147,6 +1071,7 @@
 		__u8 lun;
 		struct NCR_700_command_slot *slot;
 		__u8 reselection_id = hostdata->reselection_id;
+		Scsi_Device *SDp;
 
 		lun = hostdata->msgin[0] & 0x1f;
 
@@ -1154,34 +1079,39 @@
 		DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
 		       host->host_no, reselection_id, lun));
 		/* clear the reselection indicator */
+		SDp = scsi_find_device(host, 0, reselection_id, lun);
+		if(unlikely(SDp == NULL)) {
+			printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n",
+			       host->host_no, reselection_id, lun);
+			BUG();
+		}
 		if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
-			slot = find_ITLQ_Nexus(hostdata, reselection_id,
-					       lun, hostdata->msgin[2]);
+			Scsi_Cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
+			if(unlikely(SCp == NULL)) {
+				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", 
+				       host->host_no, reselection_id, lun, hostdata->msgin[2]);
+				BUG();
+			}
+
+			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+			DEBUG(("53c700: %d:%d:%d, reselection is tag %d, slot %p(%d)\n",
+			       host->host_no, SDp->id, SDp->lun,
+			       hostdata->msgin[2], slot, slot->tag));
 		} else {
-			slot = find_ITL_Nexus(hostdata, reselection_id, lun);
+			Scsi_Cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
+			if(unlikely(SCp == NULL)) {
+				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for untagged cmd\n", 
+				       host->host_no, reselection_id, lun);
+				BUG();
+			}
+			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
 		}
-	retry:
+
 		if(slot == NULL) {
-			struct NCR_700_command_slot *s = find_ITL_Nexus(hostdata, reselection_id, lun);
 			printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
 			       host->host_no, reselection_id, lun,
 			       hostdata->msgin[0], hostdata->msgin[1],
 			       hostdata->msgin[2]);
-			printk(KERN_ERR " OUTSTANDING TAGS:");
-			while(s != NULL) {
-				if(s->cmnd->target == reselection_id &&
-				   s->cmnd->lun == lun) {
-					printk("%d ", s->tag);
-					if(s->tag == hostdata->msgin[2]) {
-						printk(" ***FOUND*** \n");
-						slot = s;
-						goto retry;
-					}
-						
-				}
-				s = s->ITL_back;
-			}
-			printk("\n");
 		} else {
 			if(hostdata->state != NCR_700_HOST_BUSY)
 				printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
@@ -1473,9 +1403,8 @@
 	 * will refuse all tags, so send the request sense as untagged
 	 * */
 	if((hostdata->tag_negotiated & (1<<SCp->target))
-	   && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
-		hostdata->msgout[count++] = A_SIMPLE_TAG_MSG;
-		hostdata->msgout[count++] = slot->tag;
+	   && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
+		count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]);
 	}
 
 	if(hostdata->fast &&
@@ -1835,7 +1764,6 @@
 	__u32 move_ins;
 	int pci_direction;
 	struct NCR_700_command_slot *slot;
-	int hash;
 
 	if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
 		/* We're over our allocation, this should never happen
@@ -1843,7 +1771,15 @@
 		printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no);
 		return 1;
 	}
-	if(NCR_700_get_depth(SCp->device) != 0 && !(hostdata->tag_negotiated & (1<<SCp->target))) {
+	/* check for untagged commands.  We cannot have any outstanding
+	 * commands if we accept them.  Commands could be untagged because:
+	 *
+	 * - The tag negotiated bitmap is clear
+	 * - The blk layer sent and untagged command
+	 */
+	if(NCR_700_get_depth(SCp->device) != 0
+	   && (!(hostdata->tag_negotiated & (1<<SCp->target))
+	       || !blk_rq_tagged(SCp->request))) {
 		DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n",
 		       SCp->host->host_no, SCp->target, SCp->lun,
 		       NCR_700_get_depth(SCp->device)));
@@ -1882,84 +1818,40 @@
 		 * NOTE: There is a danger here: the mid layer supports
 		 * tag queuing per LUN.  We only support it per PUN because
 		 * of potential reselection issues */
+		printk(KERN_NOTICE "scsi%d: (%d:%d) beginning blk layer TCQ\n",
+		       SCp->device->host->host_no, SCp->target, SCp->lun);
+		scsi_activate_tcq(SCp->device, NCR_700_MAX_TAGS);
+	}
+
+	if(blk_rq_tagged(SCp->request)
+	   && (hostdata->tag_negotiated &(1<<SCp->target)) == 0) {
 		printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun);
 		hostdata->tag_negotiated |= (1<<SCp->target);
 		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
-		SCp->device->tagged_queue = 1;
 	}
 
-	if(hostdata->tag_negotiated &(1<<SCp->target)) {
+	/* here we may have to process an untagged command.  The gate
+	 * above ensures that this will be the only one outstanding,
+	 * so clear the tag negotiated bit.
+	 *
+	 * FIXME: This will royally screw up on multiple LUN devices
+	 * */
+	if(!blk_rq_tagged(SCp->request)
+	   && (hostdata->tag_negotiated &(1<<SCp->target))) {
+		printk(KERN_INFO "scsi%d: (%d:%d) Disabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun);
+		hostdata->tag_negotiated &= ~(1<<SCp->target);
+	}
 
-		struct NCR_700_command_slot *old =
-			find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
-#ifdef NCR_700_TAG_DEBUG
-		struct NCR_700_command_slot *found;
-#endif
-		
-		if(old != NULL && old->tag == SCp->device->current_tag) {
-			/* On some badly starving drives, this can be
-			 * a frequent occurance, so print the message
-			 * only once */
-			if(NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED)) {
-				printk(KERN_WARNING "scsi%d (%d:%d) Target is suffering from tag starvation.\n", SCp->host->host_no, SCp->target, SCp->lun);
-				NCR_700_set_flag(SCp->device, NCR_700_DEV_TAG_STARVATION_WARNED);
-			}
-			/* Release the slot and ajust the depth before refusing
-			 * the command */
-			free_slot(slot, hostdata);
-			NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
-			return 1;
-		}
-		slot->tag = SCp->device->current_tag++;
-#ifdef NCR_700_TAG_DEBUG
-		while((found = find_ITLQ_Nexus(hostdata, SCp->target, SCp->lun, slot->tag)) != NULL) {
-			printk("\n\n**ERROR** already using tag %d, but oldest is %d\n", slot->tag, (old == NULL) ? -1 : old->tag);
-			printk("  FOUND = %p, tag = %d, pun = %d, lun = %d\n",
-			       found, found->tag, found->cmnd->target, found->cmnd->lun);
-			slot->tag = SCp->device->current_tag++;
-			printk("   Tag list is: ");
-			while(old != NULL) {
-				if(old->cmnd->target == SCp->target &&
-				   old->cmnd->lun == SCp->lun)
-					printk("%d ", old->tag);
-				old = old->ITL_back;
-			}
-			printk("\n\n");
-		}
-#endif
-		hash = hash_ITLQ(SCp->target, SCp->lun, slot->tag);
-		/* link into the ITLQ hash queues */
-		slot->ITLQ_forw = hostdata->ITLQ_Hash_forw[hash];
-		hostdata->ITLQ_Hash_forw[hash] = slot;
-#ifdef NCR_700_TAG_DEBUG
-		if(slot->ITLQ_forw != NULL && slot->ITLQ_forw->ITLQ_back != NULL) {
-			printk(KERN_ERR "scsi%d (%d:%d) ITLQ_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun);
-		}
-#endif
-		if(slot->ITLQ_forw != NULL)
-			slot->ITLQ_forw->ITLQ_back = slot;
-		else
-			hostdata->ITLQ_Hash_back[hash] = slot;
-		slot->ITLQ_back = NULL;
+	if((hostdata->tag_negotiated &(1<<SCp->target))) {
+		slot->tag = SCp->request->tag;
+		DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n",
+		       SCp->host->host_no, SCp->target, SCp->lun, slot->tag,
+		       slot));
 	} else {
-		slot->tag = NCR_700_NO_TAG;
+		slot->tag = SCSI_NO_TAG;
+		/* must populate current_cmnd for scsi_find_tag to work */
+		SCp->device->current_cmnd = SCp;
 	}
-	/* link into the ITL hash queues */
-	hash = hash_ITL(SCp->target, SCp->lun);
-	slot->ITL_forw = hostdata->ITL_Hash_forw[hash];
-	hostdata->ITL_Hash_forw[hash] = slot;
-#ifdef NCR_700_TAG_DEBUG
-	if(slot->ITL_forw != NULL && slot->ITL_forw->ITL_back != NULL) {
-		printk(KERN_ERR "scsi%d (%d:%d) ITL_back is not NULL!!!!\n",
-		       SCp->host->host_no, SCp->target, SCp->lun);
-	}
-#endif
-	if(slot->ITL_forw != NULL)
-		slot->ITL_forw->ITL_back = slot;
-	else
-		hostdata->ITL_Hash_back[hash] = slot;
-	slot->ITL_back = NULL;
-
 	/* sanity check: some of the commands generated by the mid-layer
 	 * have an eccentric idea of their sc_data_direction */
 	if(!SCp->use_sg && !SCp->request_bufflen 
@@ -2053,16 +1945,12 @@
 NCR_700_abort(Scsi_Cmnd * SCp)
 {
 	struct NCR_700_command_slot *slot;
-	struct NCR_700_Host_Parameters *hostdata = 
-		(struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
 
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
 	       SCp->host->host_no, SCp->target, SCp->lun);
 	print_command(SCp->cmnd);
 
-	slot = find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
-	while(slot != NULL && slot->cmnd != SCp)
-		slot = slot->ITL_back;
+	slot = (struct NCR_700_command_slot *)SCp->host_scribble;
 
 	if(slot == NULL)
 		/* no outstanding command to abort */
diff -Nru a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
--- a/drivers/scsi/53c700.h	Fri Jul  5 16:42:56 2002
+++ b/drivers/scsi/53c700.h	Fri Jul  5 16:42:56 2002
@@ -9,7 +9,7 @@
 #define _53C700_H
 
 /* Turn on for general debugging---too verbose for normal use */
-#undef NCR_700_DEBUG
+#undef	NCR_700_DEBUG
 /* Debug the tag queues, checking hash queue allocation and deallocation
  * and search for duplicate tags */
 #undef NCR_700_TAG_DEBUG
@@ -189,8 +189,7 @@
 	#define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */
 	#define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */
 	__u8	state;
-	#define NCR_700_NO_TAG	0xdead
-	__u16	tag;
+	int	tag;
 	__u32	resume_offset;
 	Scsi_Cmnd	*cmnd;
 	/* The pci_mapped address of the actual command in cmnd */
diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
--- a/drivers/scsi/aha1542.c	Fri Jul  5 16:42:44 2002
+++ b/drivers/scsi/aha1542.c	Fri Jul  5 16:42:44 2002
@@ -1635,14 +1635,14 @@
 		if (HOSTDATA(SCpnt->host)->SCint[i]) {
 			if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
 				printk(KERN_ERR "Timed out command pending for %s\n",
-				       kdevname(SCpnt->request.rq_dev));
+				       kdevname(SCpnt->request->rq_dev));
 				if (HOSTDATA(SCpnt->host)->mb[i].status) {
 					printk(KERN_ERR "OGMB still full - restarting\n");
 					aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
 				};
 			} else
 				printk(KERN_ERR "Other pending command %s\n",
-				       kdevname(SCpnt->request.rq_dev));
+				       kdevname(SCpnt->request->rq_dev));
 		}
 #endif
 
diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c
--- a/drivers/scsi/constants.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/constants.c	Fri Jul  5 16:43:00 2002
@@ -1006,13 +1006,13 @@
 void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
 {
 	print_sense_internal(devclass, SCpnt->sense_buffer,
-			     SCpnt->request.rq_dev);
+			     SCpnt->request->rq_dev);
 }
 
 void print_req_sense(const char * devclass, Scsi_Request * SRpnt)
 {
 	print_sense_internal(devclass, SRpnt->sr_sense_buffer,
-			     SRpnt->sr_request.rq_dev);
+			     SRpnt->sr_request->rq_dev);
 }
 
 #if (CONSTANTS & CONST_MSG) 
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/eata.c	Fri Jul  5 16:43:00 2002
@@ -1563,7 +1563,7 @@
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
-      flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
       return 0;
       }
 
@@ -1875,11 +1875,11 @@
 
       if (!cpp->din) input_only = FALSE;
 
-      if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector;
-      if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
+      if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector;
+      if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector;
 
-      sl[n] = SCpnt->request.sector;
-      ioseek += SCpnt->request.nr_sectors;
+      sl[n] = SCpnt->request->sector;
+      ioseek += SCpnt->request->nr_sectors;
 
       if (!n) continue;
 
@@ -1907,7 +1907,7 @@
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-      ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
+      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
 
       if (!n) continue;
 
@@ -1935,7 +1935,7 @@
                 " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
                 SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
-                SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
+                SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
                 YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->din);
          }
@@ -2073,7 +2073,7 @@
 
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
-      flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
 
    tstatus = status_byte(spp->target_status);
 
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/scsi/hosts.c	Fri Jul  5 16:42:56 2002
@@ -230,6 +230,7 @@
 
     retval->select_queue_depths = tpnt->select_queue_depths;
     retval->max_sectors = tpnt->max_sectors;
+    retval->use_blk_tcq = tpnt->use_blk_tcq;
 
     if(!scsi_hostlist)
 	scsi_hostlist = retval;
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/hosts.h	Fri Jul  5 16:42:59 2002
@@ -286,6 +286,12 @@
 
     unsigned highmem_io:1;
 
+    /* 
+     * True if the driver wishes to use the generic block layer
+     * tag queueing functions
+     */
+    unsigned use_blk_tcq:1;
+
     /*
      * Name of proc directory
      */
@@ -386,6 +392,7 @@
     unsigned unchecked_isa_dma:1;
     unsigned use_clustering:1;
     unsigned highmem_io:1;
+    unsigned use_blk_tcq:1;
 
     /*
      * Host has rejected a command because it was busy.
@@ -418,6 +425,11 @@
      */
     struct pci_dev *pci_dev;
 
+    /* 
+     * Support for driverfs filesystem
+     */
+    struct device host_driverfs_dev;
+
     /*
      * We should ensure that this is aligned, both for better performance
      * and also because some compilers (m68k) don't automatically force
@@ -478,6 +490,7 @@
                                        struct pci_dev *pdev)
 {
 	SHpnt->pci_dev = pdev;
+	SHpnt->host_driverfs_dev.parent=&pdev->dev;
 }
 
 
@@ -516,6 +529,7 @@
     void (*detach)(Scsi_Device *);
     int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. 
                                            Selects command for blkdevs */
+    struct device_driver scsi_driverfs_driver;
 };
 
 void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
@@ -555,6 +569,26 @@
 #define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
 #define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
 
+
+/**
+ * scsi_find_device - find a device given the host
+ * @channel:	SCSI channel (zero if only one channel)
+ * @pun:	SCSI target number (physical unit number)
+ * @lun:	SCSI Logical Unit Number
+ **/
+static inline Scsi_Device *scsi_find_device(struct Scsi_Host *host,
+                                            int channel, int pun, int lun) {
+        Scsi_Device *SDpnt;
+
+        for(SDpnt = host->host_queue;
+            SDpnt != NULL;
+            SDpnt = SDpnt->next)
+                if(SDpnt->channel == channel && SDpnt->id == pun
+                   && SDpnt->lun ==lun)
+                        break;
+        return SDpnt;
+}
+    
 #endif
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Nru a/drivers/scsi/i60uscsi.c b/drivers/scsi/i60uscsi.c
--- a/drivers/scsi/i60uscsi.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/i60uscsi.c	Fri Jul  5 16:42:59 2002
@@ -66,12 +66,24 @@
  * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
  * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
  * 08/08/99 bv - v1.02c Use waitForPause again.
+ * 06/25/02 Doug Ledford <dledford@redhat.com> - v1.02d
+ *          - Remove limit on number of controllers
+ *          - Port to DMA mapping API
+ *          - Clean up interrupt handler registration
+ *          - Fix memory leaks
+ *          - Fix allocation of scsi host structs and private data
  **************************************************************************/
 
 #include <linux/version.h>
-#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
 #include <asm/io.h>
-#include "i60uscsi.h"
+#include <linux/blkdev.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "inia100.h"
 
 #define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
 #define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
@@ -98,10 +110,7 @@
 extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
 
 /* ---- INTERNAL VARIABLES ---- */
-ORC_HCS orc_hcs[MAX_SUPPORTED_ADAPTERS];
-static INIA100_ADPT_STRUCT inia100_adpt[MAX_SUPPORTED_ADAPTERS];
-/* set by inia100_setup according to the command line */
-int orc_num_scb;
+struct inia100_Adpt_Struc *inia100_adpt;
 
 NVRAM nvram, *nvramp = &nvram;
 static UCHAR dftNvRam[64] =
@@ -300,7 +309,7 @@
 /***************************************************************************/
 void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
 {
-	scbp->SCB_Status = SCB_POST;
+	scbp->SCB_Status = ORCSCB_POST;
 	ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
 	return;
 }
@@ -439,17 +448,11 @@
 {
 	ORC_SCB *pVirScb;
 	int i;
-	UCHAR j;
 	ESCB *pVirEscb;
-	PVOID pPhysEscb;
-	PVOID tPhysEscb;
+	dma_addr_t pPhysEscb;
 
-	j = 0;
-	pVirScb = NULL;
-	tPhysEscb = (PVOID) NULL;
-	pPhysEscb = (PVOID) NULL;
 	/* Setup SCB HCS_Base and SCB Size registers */
-	ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb);	/* Total number of SCBs */
+	ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE);	/* Total number of SCBs */
 	/* SCB HCS_Base address 0      */
 	ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
 	/* SCB HCS_Base address 1      */
@@ -459,8 +462,8 @@
 	pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
 	pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
 
-	for (i = 0; i < orc_num_scb; i++) {
-		pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
+	for (i = 0; i < ORC_MAXQUEUE; i++) {
+		pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
 		pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
 		pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
 		pVirScb->SCB_EScb = pVirEscb;
@@ -534,7 +537,7 @@
 	readBytep = (UCHAR *) & (nvramp->Target00Config);
 	for (i = 0; i < 16; readBytep++, i++) {
 		hcsp->TargetFlag[i] = *readBytep;
-		hcsp->MaximumTags[i] = orc_num_scb;
+		hcsp->MaximumTags[i] = ORC_MAXTAGS;
 	}			/* for                          */
 
 	if (nvramp->SCSI0Config & NCC_BUSRESET) {	/* Reset SCSI bus               */
@@ -578,7 +581,7 @@
  Output         : None.
  Return         : pSRB  -       Pointer to SCSI request block.
 *****************************************************************************/
-int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags)
+int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target, unsigned int ResetFlags)
 {				/* I need Host Control Block Information */
 	ORC_SCB *pScb;
 	ESCB *pVirEscb;
@@ -595,14 +598,14 @@
 
 	initAFlag(pHCB);
 	/* device reset */
-	for (i = 0; i < orc_num_scb; i++) {
+	for (i = 0; i < ORC_MAXQUEUE; i++) {
 		pVirEscb = pVirScb->SCB_EScb;
-		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt))
+		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt))
 			break;
 		pVirScb++;
 	}
 
-	if (i == orc_num_scb) {
+	if (i == ORC_MAXQUEUE) {
 		printk("Unable to Reset - No SCB Found\n");
 		spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 		return (SCSI_RESET_NOT_RUNNING);
@@ -624,7 +627,7 @@
 
 	pVirEscb->SCB_Srb = 0;
 	if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
-		pVirEscb->SCB_Srb = (unsigned char *) SCpnt;
+		pVirEscb->SCB_Srb = SCpnt;
 	}
 	orc_exec_scb(pHCB, pScb);	/* Start execute SCB            */
 	spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
@@ -640,7 +643,6 @@
 	ULONG idx;
 	UCHAR index;
 	UCHAR i;
-	ULONG flags;
 
 	Ch = hcsp->HCS_Index;
 	for (i = 0; i < 8; i++) {
@@ -687,6 +689,22 @@
 }
 
 
+/***************************************************************************/
+void orc_release_dma(ORC_HCS * hcsp, Scsi_Cmnd * SCpnt)
+{
+	struct scatterlist *pSrbSG;
+
+	if (SCpnt->use_sg) {
+		pSrbSG = (struct scatterlist *)SCpnt->request_buffer;
+		pci_unmap_sg(hcsp->pdev, pSrbSG, SCpnt->use_sg,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else if (SCpnt->request_bufflen != 0) {
+		pci_unmap_single(hcsp->pdev, (U32)SCpnt->host_scribble,
+			SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	}
+}
+
 /*****************************************************************************
  Function name	: Addinia100_into_Adapter_table
  Description	: This function will scan PCI bus to get all Orchid card
@@ -695,33 +713,29 @@
  Return		: SUCCESSFUL	- Successful scan
  ohterwise	- No drives founded
 *****************************************************************************/
-int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
-				  BYTE bBus, BYTE bDevice)
+int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, struct pci_dev *pdev,
+		int iAdapters)
 {
 	unsigned int i, j;
 
-	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
+	for (i = 0; i < iAdapters; i++) {
 		if (inia100_adpt[i].ADPT_BIOS < wBIOS)
 			continue;
 		if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
 			if (inia100_adpt[i].ADPT_BASE == wBASE) {
-				if (inia100_adpt[i].ADPT_Bus != 0xFF)
+				if (inia100_adpt[i].ADPT_pdev->bus->number != 0xFF)
 					return (FAILURE);
 			} else if (inia100_adpt[i].ADPT_BASE < wBASE)
 				continue;
 		}
-		for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
+		for (j = iAdapters - 1; j > i; j--) {
 			inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
-			inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR;
 			inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS;
-			inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus;
-			inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device;
+			inia100_adpt[j].ADPT_pdev = inia100_adpt[j - 1].ADPT_pdev;
 		}
 		inia100_adpt[i].ADPT_BASE = wBASE;
-		inia100_adpt[i].ADPT_INTR = bInterrupt;
 		inia100_adpt[i].ADPT_BIOS = wBIOS;
-		inia100_adpt[i].ADPT_Bus = bBus;
-		inia100_adpt[i].ADPT_Device = bDevice;
+		inia100_adpt[i].ADPT_pdev = pdev;
 		return (SUCCESSFUL);
 	}
 	return (FAILURE);
@@ -733,20 +747,23 @@
  Description	: This function will scan PCI bus to get all Orchid card
  Input		: None.
  Output		: None.
- Return		: SUCCESSFUL	- Successful scan
- ohterwise	- No drives founded
+ Return		: 0 on success, 1 on failure
 *****************************************************************************/
-void init_inia100Adapter_table(void)
+int init_inia100Adapter_table(int iAdapters)
 {
 	int i;
 
-	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {	/* Initialize adapter structure */
+	inia100_adpt = kmalloc(sizeof(INIA100_ADPT_STRUCT) * iAdapters,
+			GFP_KERNEL);
+	if(inia100_adpt == NULL)
+		return 1;
+
+	for (i = 0; i < iAdapters; i++) {/* Initialize adapter structure */
 		inia100_adpt[i].ADPT_BIOS = 0xffff;
 		inia100_adpt[i].ADPT_BASE = 0xffff;
-		inia100_adpt[i].ADPT_INTR = 0xff;
-		inia100_adpt[i].ADPT_Bus = 0xff;
-		inia100_adpt[i].ADPT_Device = 0xff;
+		inia100_adpt[i].ADPT_pdev = NULL;
 	}
+	return 0;
 }
 
 /*****************************************************************************
@@ -760,7 +777,7 @@
 {
 	pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE;	/* Supply base address  */
 	pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS;	/* Supply BIOS address  */
-	pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR;	/* Supply interrupt line */
+	pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_pdev->irq;	/* Supply interrupt line */
 	return;
 }
 
@@ -805,7 +822,7 @@
  Output         : None.
  Return         : pSRB  -       Pointer to SCSI request block.
 *****************************************************************************/
-int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt)
+int orc_abort_srb(ORC_HCS * hcsp, Scsi_Cmnd *SCpnt)
 {
 	ESCB *pVirEscb;
 	ORC_SCB *pVirScb;
@@ -816,9 +833,9 @@
 
 	pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
 
-	for (i = 0; i < orc_num_scb; i++, pVirScb++) {
+	for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) {
 		pVirEscb = pVirScb->SCB_EScb;
-		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) {
+		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) {
 			if (pVirScb->SCB_TagMsg == 0) {
 				spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 				return (SCSI_ABORT_BUSY);
diff -Nru a/drivers/scsi/i60uscsi.h b/drivers/scsi/i60uscsi.h
--- a/drivers/scsi/i60uscsi.h	Fri Jul  5 16:43:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,567 +0,0 @@
-/**************************************************************************
- * Initio A100 device driver for Linux.
- *
- * Copyright (c) 1994-1998 Initio Corporation
- * All rights reserved.
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * --------------------------------------------------------------------------
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of 
- * the GNU General Public License ("GPL") and the terms of the GPL would require the 
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- **************************************************************************
- *
- * Module: inia100.h
- * Description: INI-A100U2W LINUX device driver header
- * Revision History:
- *	06/18/98 HL, Initial Version 1.02
- *	12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up.
- **************************************************************************/
-
-#include <linux/config.h>
-#include <linux/types.h>
-
-#define ULONG   unsigned long
-#define PVOID   void *
-#define USHORT  unsigned short
-#define UCHAR   unsigned char
-#define BYTE    unsigned char
-#define WORD    unsigned short
-#define DWORD   unsigned long
-#define UBYTE   unsigned char
-#define UWORD   unsigned short
-#define UDWORD  unsigned long
-#define U32     u32
-
-#ifndef NULL
-#define NULL     0		/* zero          */
-#endif
-#ifndef TRUE
-#define TRUE     (1)		/* boolean true  */
-#endif
-#ifndef FALSE
-#define FALSE    (0)		/* boolean false */
-#endif
-#ifndef FAILURE
-#define FAILURE  (-1)
-#endif
-#if 1
-#define ORC_MAXQUEUE		245
-#else
-#define ORC_MAXQUEUE		25
-#endif
-
-#define TOTAL_SG_ENTRY		32
-#define MAX_TARGETS		16
-#define IMAX_CDB			15
-#define SENSE_SIZE		14
-#define MAX_SUPPORTED_ADAPTERS  4
-#define SUCCESSFUL              0x00
-
-#define I920_DEVICE_ID	0x0002	/* Initio's inic-950 product ID   */
-
-/************************************************************************/
-/*              Scatter-Gather Element Structure                        */
-/************************************************************************/
-typedef struct ORC_SG_Struc {
-	U32 SG_Ptr;		/* Data Pointer */
-	U32 SG_Len;		/* Data Length */
-} ORC_SG;
-
-typedef struct inia100_Adpt_Struc {
-	UWORD ADPT_BIOS;	/* 0 */
-	UWORD ADPT_BASE;	/* 1 */
-	UBYTE ADPT_Bus;		/* 2 */
-	UBYTE ADPT_Device;	/* 3 */
-	UBYTE ADPT_INTR;	/* 4 */
-} INIA100_ADPT_STRUCT;
-
-
-/* SCSI related definition                                              */
-#define DISC_NOT_ALLOW          0x80	/* Disconnect is not allowed    */
-#define DISC_ALLOW              0xC0	/* Disconnect is allowed        */
-
-
-#define ORC_OFFSET_SCB			16
-#define ORC_MAX_SCBS		    250
-#define MAX_CHANNELS       2
-#define MAX_ESCB_ELE				64
-#define TCF_DRV_255_63     0x0400
-
-/********************************************************/
-/*      Orchid Configuration Register Set               */
-/********************************************************/
-#define ORC_PVID	0x00	/* Vendor ID                      */
-#define ORC_VENDOR_ID	0x1101	/* Orchid vendor ID               */
-#define ORC_PDID        0x02	/* Device ID                    */
-#define ORC_DEVICE_ID	0x1060	/* Orchid device ID               */
-#define ORC_COMMAND	0x04	/* Command                        */
-#define BUSMS		0x04	/* BUS MASTER Enable              */
-#define IOSPA		0x01	/* IO Space Enable                */
-#define ORC_STATUS	0x06	/* Status register                */
-#define ORC_REVISION	0x08	/* Revision number                */
-#define ORC_BASE	0x10	/* Base address                   */
-#define ORC_BIOS	0x50	/* Expansion ROM base address     */
-#define ORC_INT_NUM	0x3C	/* Interrupt line         */
-#define ORC_INT_PIN	0x3D	/* Interrupt pin          */
-
-
-/********************************************************/
-/*      Orchid Host Command Set                         */
-/********************************************************/
-#define ORC_CMD_NOP		0x00	/* Host command - NOP             */
-#define ORC_CMD_VERSION		0x01	/* Host command - Get F/W version */
-#define ORC_CMD_ECHO		0x02	/* Host command - ECHO            */
-#define ORC_CMD_SET_NVM		0x03	/* Host command - Set NVRAM       */
-#define ORC_CMD_GET_NVM		0x04	/* Host command - Get NVRAM       */
-#define ORC_CMD_GET_BUS_STATUS	0x05	/* Host command - Get SCSI bus status */
-#define ORC_CMD_ABORT_SCB	0x06	/* Host command - Abort SCB       */
-#define ORC_CMD_ISSUE_SCB	0x07	/* Host command - Issue SCB       */
-
-/********************************************************/
-/*              Orchid Register Set                     */
-/********************************************************/
-#define ORC_GINTS	0xA0	/* Global Interrupt Status        */
-#define QINT		0x04	/* Reply Queue Interrupt  */
-#define ORC_GIMSK	0xA1	/* Global Interrupt MASK  */
-#define MQINT		0x04	/* Mask Reply Queue Interrupt     */
-#define	ORC_GCFG	0xA2	/* Global Configure               */
-#define EEPRG		0x01	/* Enable EEPROM programming */
-#define	ORC_GSTAT	0xA3	/* Global status          */
-#define WIDEBUS		0x10	/* Wide SCSI Devices connected    */
-#define ORC_HDATA	0xA4	/* Host Data                      */
-#define ORC_HCTRL	0xA5	/* Host Control                   */
-#define SCSIRST		0x80	/* SCSI bus reset         */
-#define HDO			0x40	/* Host data out          */
-#define HOSTSTOP		0x02	/* Host stop RISC engine  */
-#define DEVRST		0x01	/* Device reset                   */
-#define ORC_HSTUS	0xA6	/* Host Status                    */
-#define HDI			0x02	/* Host data in                   */
-#define RREADY		0x01	/* RISC engine is ready to receive */
-#define	ORC_NVRAM	0xA7	/* Nvram port address             */
-#define SE2CS		0x008
-#define SE2CLK		0x004
-#define SE2DO		0x002
-#define SE2DI		0x001
-#define ORC_PQUEUE	0xA8	/* Posting queue FIFO             */
-#define ORC_PQCNT	0xA9	/* Posting queue FIFO Cnt */
-#define ORC_RQUEUE	0xAA	/* Reply queue FIFO               */
-#define ORC_RQUEUECNT	0xAB	/* Reply queue FIFO Cnt           */
-#define	ORC_FWBASEADR	0xAC	/* Firmware base address  */
-
-#define	ORC_EBIOSADR0 0xB0	/* External Bios address */
-#define	ORC_EBIOSADR1 0xB1	/* External Bios address */
-#define	ORC_EBIOSADR2 0xB2	/* External Bios address */
-#define	ORC_EBIOSDATA 0xB3	/* External Bios address */
-
-#define	ORC_SCBSIZE	0xB7	/* SCB size register              */
-#define	ORC_SCBBASE0	0xB8	/* SCB base address 0             */
-#define	ORC_SCBBASE1	0xBC	/* SCB base address 1             */
-
-#define	ORC_RISCCTL	0xE0	/* RISC Control                   */
-#define PRGMRST		0x002
-#define DOWNLOAD		0x001
-#define	ORC_PRGMCTR0	0xE2	/* RISC program counter           */
-#define	ORC_PRGMCTR1	0xE3	/* RISC program counter           */
-#define	ORC_RISCRAM	0xEC	/* RISC RAM data port 4 bytes     */
-
-typedef struct orc_extended_scb {	/* Extended SCB                 */
-	ORC_SG ESCB_SGList[TOTAL_SG_ENTRY];	/*0 Start of SG list              */
-	unsigned char *SCB_Srb;	/*50 SRB Pointer */
-//         Scsi_Cmnd    *SCB_Srb;       /*50 SRB Pointer */
-} ESCB;
-
-/***********************************************************************
-		SCSI Control Block
-************************************************************************/
-typedef struct orc_scb {	/* Scsi_Ctrl_Blk                */
-	UBYTE SCB_Opcode;	/*00 SCB command code&residual  */
-	UBYTE SCB_Flags;	/*01 SCB Flags                  */
-	UBYTE SCB_Target;	/*02 Target Id                  */
-	UBYTE SCB_Lun;		/*03 Lun                        */
-	U32 SCB_Reserved0;	/*04 Reserved for ORCHID must 0 */
-	U32 SCB_XferLen;	/*08 Data Transfer Length       */
-	U32 SCB_Reserved1;	/*0C Reserved for ORCHID must 0 */
-	U32 SCB_SGLen;		/*10 SG list # * 8              */
-	U32 SCB_SGPAddr;	/*14 SG List Buf physical Addr  */
-	U32 SCB_SGPAddrHigh;	/*18 SG Buffer high physical Addr */
-	UBYTE SCB_HaStat;	/*1C Host Status                */
-	UBYTE SCB_TaStat;	/*1D Target Status              */
-	UBYTE SCB_Status;	/*1E SCB status                 */
-	UBYTE SCB_Link;		/*1F Link pointer, default 0xFF */
-	UBYTE SCB_SenseLen;	/*20 Sense Allocation Length    */
-	UBYTE SCB_CDBLen;	/*21 CDB Length                 */
-	UBYTE SCB_Ident;	/*22 Identify                   */
-	UBYTE SCB_TagMsg;	/*23 Tag Message                */
-	UBYTE SCB_CDB[IMAX_CDB];	/*24 SCSI CDBs                  */
-	UBYTE SCB_ScbIdx;	/*3C Index for this ORCSCB      */
-	U32 SCB_SensePAddr;	/*34 Sense Buffer physical Addr */
-
-	ESCB *SCB_EScb;		/*38 Extended SCB Pointer       */
-#ifndef ALPHA
-	UBYTE SCB_Reserved2[4];	/*3E Reserved for Driver use    */
-#endif
-} ORC_SCB;
-
-/* Opcodes of ORCSCB_Opcode */
-#define ORC_EXECSCSI	0x00	/* SCSI initiator command with residual */
-#define ORC_BUSDEVRST	0x01	/* SCSI Bus Device Reset  */
-
-/* Status of ORCSCB_Status */
-#define SCB_COMPLETE	0x00	/* SCB request completed  */
-#define SCB_POST	0x01	/* SCB is posted by the HOST      */
-
-/* Bit Definition for ORCSCB_Flags */
-#define SCF_DISINT	0x01	/* Disable HOST interrupt */
-#define SCF_DIR		0x18	/* Direction bits         */
-#define SCF_NO_DCHK	0x00	/* Direction determined by SCSI   */
-#define SCF_DIN		0x08	/* From Target to Initiator       */
-#define SCF_DOUT	0x10	/* From Initiator to Target       */
-#define SCF_NO_XF	0x18	/* No data transfer               */
-#define SCF_POLL   0x40
-
-/* Error Codes for ORCSCB_HaStat */
-#define HOST_SEL_TOUT	0x11
-#define HOST_DO_DU	0x12
-#define HOST_BUS_FREE	0x13
-#define HOST_BAD_PHAS	0x14
-#define HOST_INV_CMD	0x16
-#define HOST_SCSI_RST	0x1B
-#define HOST_DEV_RST	0x1C
-
-
-/* Error Codes for ORCSCB_TaStat */
-#define TARGET_CHK_COND	0x02
-#define TARGET_BUSY	0x08
-#define TARGET_TAG_FULL	0x28
-
-
-/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
-#define MSG_STAG	0x20
-#define MSG_HTAG	0x21
-#define MSG_OTAG	0x22
-
-#define MSG_IGNOREWIDE	0x23
-
-#define MSG_IDENT	0x80
-#define MSG_DISC	0x40	/* Disconnect allowed             */
-
-
-/* SCSI MESSAGE */
-#define	MSG_EXTEND	0x01
-#define	MSG_SDP		0x02
-#define	MSG_ABORT	0x06
-#define	MSG_REJ		0x07
-#define	MSG_NOP		0x08
-#define	MSG_PARITY	0x09
-#define	MSG_DEVRST	0x0C
-#define	MSG_STAG	0x20
-
-/***********************************************************************
-		Target Device Control Structure
-**********************************************************************/
-
-typedef struct ORC_Tar_Ctrl_Struc {
-	UBYTE TCS_DrvDASD;	/* 6 */
-	UBYTE TCS_DrvSCSI;	/* 7 */
-	UBYTE TCS_DrvHead;	/* 8 */
-	UWORD TCS_DrvFlags;	/* 4 */
-	UBYTE TCS_DrvSector;	/* 7 */
-} ORC_TCS, *PORC_TCS;
-
-/* Bit Definition for TCF_DrvFlags */
-#define	TCS_DF_NODASD_SUPT	0x20	/* Suppress OS/2 DASD Mgr support */
-#define	TCS_DF_NOSCSI_SUPT	0x40	/* Suppress OS/2 SCSI Mgr support */
-
-
-/***********************************************************************
-              Host Adapter Control Structure
-************************************************************************/
-typedef struct ORC_Ha_Ctrl_Struc {
-	USHORT HCS_Base;	/* 00 */
-	UBYTE HCS_Index;	/* 02 */
-	UBYTE HCS_Intr;		/* 04 */
-	UBYTE HCS_SCSI_ID;	/* 06    H/A SCSI ID */
-	UBYTE HCS_BIOS;		/* 07    BIOS configuration */
-
-	UBYTE HCS_Flags;	/* 0B */
-	UBYTE HCS_HAConfig1;	/* 1B    SCSI0MAXTags */
-	UBYTE HCS_MaxTar;	/* 1B    SCSI0MAXTags */
-
-	USHORT HCS_Units;	/* Number of units this adapter  */
-	USHORT HCS_AFlags;	/* Adapter info. defined flags   */
-	ULONG HCS_Timeout;	/* Adapter timeout value   */
-	PVOID HCS_virScbArray;	/* 28 Virtual Pointer to SCB array     */
-	U32 HCS_physScbArray;	/* Scb Physical address */
-	PVOID HCS_virEscbArray;	/* Virtual pointer to ESCB Scatter list */
-	U32 HCS_physEscbArray;	/* scatter list Physical address */
-	UBYTE TargetFlag[16];	/* 30  target configuration, TCF_EN_TAG */
-	UBYTE MaximumTags[16];	/* 40  ORC_MAX_SCBS */
-	UBYTE ActiveTags[16][16];	/* 50 */
-	ORC_TCS HCS_Tcs[16];	/* 28 */
-	U32 BitAllocFlag[MAX_CHANNELS][8];	/* Max STB is 256, So 256/32 */
-	spinlock_t BitAllocFlagLock;
-	ULONG pSRB_head;
-	ULONG pSRB_tail;
-	spinlock_t pSRB_lock;
-} ORC_HCS;
-
-/* Bit Definition for HCS_Flags */
-
-#define HCF_SCSI_RESET	0x01	/* SCSI BUS RESET         */
-#define HCF_PARITY    	0x02	/* parity card                    */
-#define HCF_LVDS     	0x10	/* parity card                    */
-
-/* Bit Definition for TargetFlag */
-
-#define TCF_EN_255	    0x08
-#define TCF_EN_TAG	    0x10
-#define TCF_BUSY	      0x20
-#define TCF_DISCONNECT	0x40
-#define TCF_SPIN_UP	  0x80
-
-/* Bit Definition for HCS_AFlags */
-#define	HCS_AF_IGNORE		0x01	/* Adapter ignore         */
-#define	HCS_AF_DISABLE_RESET	0x10	/* Adapter disable reset  */
-#define	HCS_AF_DISABLE_ADPT	0x80	/* Adapter disable                */
-
-
-/*---------------------------------------*/
-/* TimeOut for RESET to complete (30s)   */
-/*                                       */
-/* After a RESET the drive is checked    */
-/* every 200ms.                          */
-/*---------------------------------------*/
-#define DELAYED_RESET_MAX       (30*1000L)
-#define DELAYED_RESET_INTERVAL  200L
-
-/*----------------------------------------------*/
-/* TimeOut for IRQ from last interrupt (5s)     */
-/*----------------------------------------------*/
-#define IRQ_TIMEOUT_INTERVAL    (5*1000L)
-
-/*----------------------------------------------*/
-/* Retry Delay interval (200ms)                 */
-/*----------------------------------------------*/
-#define DELAYED_RETRY_INTERVAL  200L
-
-#define	INQUIRY_SIZE		36
-#define	CAPACITY_SIZE		8
-#define	DEFAULT_SENSE_LEN	14
-
-#define	DEVICE_NOT_FOUND	0x86
-
-/*----------------------------------------------*/
-/* Definition for PCI device                    */
-/*----------------------------------------------*/
-#define	MAX_PCI_DEVICES	21
-#define	MAX_PCI_BUSES	8
-
-typedef struct Adpt_Struc {
-	USHORT ADPT_BIOS;	/* 0 */
-	UBYTE ADPT_BASE;	/* 1 */
-	UBYTE ADPT_Bus;		/* 2 */
-	UBYTE ADPT_Device;	/* 3 */
-	UBYTE ADPT_Reserved[3];
-} JACS, *PJACS;
-
-typedef struct _NVRAM {
-/*----------header ---------------*/
-	UCHAR SubVendorID0;	/* 00 - Sub Vendor ID           */
-	UCHAR SubVendorID1;	/* 00 - Sub Vendor ID           */
-	UCHAR SubSysID0;	/* 02 - Sub System ID           */
-	UCHAR SubSysID1;	/* 02 - Sub System ID           */
-	UCHAR SubClass;		/* 04 - Sub Class               */
-	UCHAR VendorID0;	/* 05 - Vendor ID               */
-	UCHAR VendorID1;	/* 05 - Vendor ID               */
-	UCHAR DeviceID0;	/* 07 - Device ID               */
-	UCHAR DeviceID1;	/* 07 - Device ID               */
-	UCHAR Reserved0[2];	/* 09 - Reserved                */
-	UCHAR Revision;		/* 0B - Revision of data structure */
-	/* ----Host Adapter Structure ---- */
-	UCHAR NumOfCh;		/* 0C - Number of SCSI channel  */
-	UCHAR BIOSConfig1;	/* 0D - BIOS configuration 1    */
-	UCHAR BIOSConfig2;	/* 0E - BIOS boot channel&target ID */
-	UCHAR BIOSConfig3;	/* 0F - BIOS configuration 3    */
-	/* ----SCSI channel Structure ---- */
-	/* from "CTRL-I SCSI Host Adapter SetUp menu "  */
-	UCHAR SCSI0Id;		/* 10 - Channel 0 SCSI ID       */
-	UCHAR SCSI0Config;	/* 11 - Channel 0 SCSI configuration */
-	UCHAR SCSI0MaxTags;	/* 12 - Channel 0 Maximum tags  */
-	UCHAR SCSI0ResetTime;	/* 13 - Channel 0 Reset recovering time */
-	UCHAR ReservedforChannel0[2];	/* 14 - Reserved                */
-
-	/* ----SCSI target Structure ----  */
-	/* from "CTRL-I SCSI device SetUp menu "                        */
-	UCHAR Target00Config;	/* 16 - Channel 0 Target 0 config */
-	UCHAR Target01Config;	/* 17 - Channel 0 Target 1 config */
-	UCHAR Target02Config;	/* 18 - Channel 0 Target 2 config */
-	UCHAR Target03Config;	/* 19 - Channel 0 Target 3 config */
-	UCHAR Target04Config;	/* 1A - Channel 0 Target 4 config */
-	UCHAR Target05Config;	/* 1B - Channel 0 Target 5 config */
-	UCHAR Target06Config;	/* 1C - Channel 0 Target 6 config */
-	UCHAR Target07Config;	/* 1D - Channel 0 Target 7 config */
-	UCHAR Target08Config;	/* 1E - Channel 0 Target 8 config */
-	UCHAR Target09Config;	/* 1F - Channel 0 Target 9 config */
-	UCHAR Target0AConfig;	/* 20 - Channel 0 Target A config */
-	UCHAR Target0BConfig;	/* 21 - Channel 0 Target B config */
-	UCHAR Target0CConfig;	/* 22 - Channel 0 Target C config */
-	UCHAR Target0DConfig;	/* 23 - Channel 0 Target D config */
-	UCHAR Target0EConfig;	/* 24 - Channel 0 Target E config */
-	UCHAR Target0FConfig;	/* 25 - Channel 0 Target F config */
-
-	UCHAR SCSI1Id;		/* 26 - Channel 1 SCSI ID       */
-	UCHAR SCSI1Config;	/* 27 - Channel 1 SCSI configuration */
-	UCHAR SCSI1MaxTags;	/* 28 - Channel 1 Maximum tags  */
-	UCHAR SCSI1ResetTime;	/* 29 - Channel 1 Reset recovering time */
-	UCHAR ReservedforChannel1[2];	/* 2A - Reserved                */
-
-	/* ----SCSI target Structure ----  */
-	/* from "CTRL-I SCSI device SetUp menu "                                          */
-	UCHAR Target10Config;	/* 2C - Channel 1 Target 0 config */
-	UCHAR Target11Config;	/* 2D - Channel 1 Target 1 config */
-	UCHAR Target12Config;	/* 2E - Channel 1 Target 2 config */
-	UCHAR Target13Config;	/* 2F - Channel 1 Target 3 config */
-	UCHAR Target14Config;	/* 30 - Channel 1 Target 4 config */
-	UCHAR Target15Config;	/* 31 - Channel 1 Target 5 config */
-	UCHAR Target16Config;	/* 32 - Channel 1 Target 6 config */
-	UCHAR Target17Config;	/* 33 - Channel 1 Target 7 config */
-	UCHAR Target18Config;	/* 34 - Channel 1 Target 8 config */
-	UCHAR Target19Config;	/* 35 - Channel 1 Target 9 config */
-	UCHAR Target1AConfig;	/* 36 - Channel 1 Target A config */
-	UCHAR Target1BConfig;	/* 37 - Channel 1 Target B config */
-	UCHAR Target1CConfig;	/* 38 - Channel 1 Target C config */
-	UCHAR Target1DConfig;	/* 39 - Channel 1 Target D config */
-	UCHAR Target1EConfig;	/* 3A - Channel 1 Target E config */
-	UCHAR Target1FConfig;	/* 3B - Channel 1 Target F config */
-	UCHAR reserved[3];	/* 3C - Reserved                */
-	/* ---------- CheckSum ----------       */
-	UCHAR CheckSum;		/* 3F - Checksum of NVRam       */
-} NVRAM, *PNVRAM;
-
-/* Bios Configuration for nvram->BIOSConfig1                            */
-#define NBC_BIOSENABLE	0x01	/* BIOS enable                    */
-#define NBC_CDROM	0x02	/* Support bootable CDROM */
-#define NBC_REMOVABLE	0x04	/* Support removable drive        */
-
-/* Bios Configuration for nvram->BIOSConfig2                            */
-#define	NBB_TARGET_MASK	0x0F	/* Boot SCSI target ID number     */
-#define	NBB_CHANL_MASK	0xF0	/* Boot SCSI channel number       */
-
-/* Bit definition for nvram->SCSIConfig                                 */
-#define NCC_BUSRESET	0x01	/* Reset SCSI bus at power up     */
-#define NCC_PARITYCHK	0x02	/* SCSI parity enable             */
-#define NCC_LVDS	0x10	/* Enable LVDS                    */
-#define NCC_ACTTERM1	0x20	/* Enable active terminator 1     */
-#define NCC_ACTTERM2	0x40	/* Enable active terminator 2     */
-#define NCC_AUTOTERM	0x80	/* Enable auto termination        */
-
-/* Bit definition for nvram->TargetxConfig                              */
-#define	NTC_PERIOD	0x07	/* Maximum Sync. Speed            */
-#define NTC_1GIGA	0x08	/* 255 head / 63 sectors (64/32) */
-#define NTC_NO_SYNC	0x10	/* NO SYNC. NEGO          */
-#define NTC_NO_WIDESYNC	0x20	/* NO WIDE SYNC. NEGO             */
-#define	NTC_DISC_ENABLE	0x40	/* Enable SCSI disconnect */
-#define NTC_SPINUP	0x80	/* Start disk drive               */
-
-/* Default NVRam values                                                 */
-#define NBC_DEFAULT	(NBC_ENABLE)
-#define NCC_DEFAULT	(NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK)
-#define NCC_MAX_TAGS	0x20	/* Maximum tags per target        */
-#define	NCC_RESET_TIME	0x0A	/* SCSI RESET recovering time     */
-#define NTC_DEFAULT	(NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
-
-typedef union {			/* Union define for mechanism 1   */
-	struct {
-		unsigned char RegNum;
-		unsigned char FcnNum:3;
-		unsigned char DeviceNum:5;
-		unsigned char BusNum;
-		unsigned char Reserved:7;
-		unsigned char Enable:1;
-	} sConfigAdr;
-	unsigned long lConfigAdr;
-} CONFIG_ADR;
-
-typedef union {			/* Union define for mechanism 2   */
-	struct {
-		unsigned char RegNum;
-		unsigned char DeviceNum;
-		unsigned short Reserved;
-	} sHostAdr;
-	unsigned long lHostAdr;
-} HOST_ADR;
-
-#define ORC_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-#define ORC_RDLONG(x,y)         (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-
-#define ORC_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
-#define ORC_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
-#define ORC_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
-
-
-#define SCSI_ABORT_SNOOZE 0
-#define SCSI_ABORT_SUCCESS 1
-#define SCSI_ABORT_PENDING 2
-#define SCSI_ABORT_BUSY 3
-#define SCSI_ABORT_NOT_RUNNING 4
-#define SCSI_ABORT_ERROR 5
-
-#define SCSI_RESET_SNOOZE 0
-#define SCSI_RESET_PUNT 1
-#define SCSI_RESET_SUCCESS 2
-#define SCSI_RESET_PENDING 3
-#define SCSI_RESET_WAKEUP 4
-#define SCSI_RESET_NOT_RUNNING 5
-#define SCSI_RESET_ERROR 6
-
-#define SCSI_RESET_SYNCHRONOUS		0x01
-#define SCSI_RESET_ASYNCHRONOUS		0x02
-#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
-#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
-
-#define SCSI_RESET_BUS_RESET 0x100
-#define SCSI_RESET_HOST_RESET 0x200
-#define SCSI_RESET_ACTION   0xff
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Fri Jul  5 16:42:50 2002
+++ b/drivers/scsi/ide-scsi.c	Fri Jul  5 16:42:50 2002
@@ -668,7 +668,7 @@
 	struct Scsi_Host *host = drive->driver_data;
 	idescsi_scsi_t *scsi = idescsi_private(host);
 
-	if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+	if (major(cmd->request->rq_dev) == SCSI_GENERIC_MAJOR)
 		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
 }
diff -Nru a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c
--- a/drivers/scsi/inia100.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/inia100.c	Fri Jul  5 16:42:59 2002
@@ -59,6 +59,12 @@
  * 	adapters
  * 09/24/98 hl - v1.02 initial production release.
  * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up.
+ * 06/25/02 Doug Ledford <dledford@redhat.com> - v1.02d
+ *          - Remove limit on number of controllers
+ *          - Port to DMA mapping API
+ *          - Clean up interrupt handler registration
+ *          - Fix memory leaks
+ *          - Fix allocation of scsi host structs and private data
  **************************************************************************/
 
 #define CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
@@ -67,11 +73,8 @@
 #include <linux/version.h>
 #endif
 
-#error Please convert me to Documentation/DMA-mapping.txt
-
 #include <linux/module.h>
 
-#include <stdarg.h>
 #include <asm/irq.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -100,44 +103,34 @@
 char *inia100_Copyright = "Copyright (C) 1998-99";
 char *inia100_InitioName = "by Initio Corporation";
 char *inia100_ProductName = "INI-A100U2W";
-char *inia100_Version = "v1.02c";
+char *inia100_Version = "v1.02d";
 
 /* set by inia100_setup according to the command line */
 static int setup_called = 0;
-static int orc_num_ch = MAX_SUPPORTED_ADAPTERS;		/* Maximum 4 adapters           */
 
 /* ---- INTERNAL VARIABLES ---- */
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 static char *setup_str = (char *) NULL;
 
-static void inia100_intr0(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr1(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr2(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr3(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr4(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr5(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr6(int irq, void *dev_id, struct pt_regs *);
-static void inia100_intr7(int irq, void *dev_id, struct pt_regs *);
-
+static void inia100_intr(int, void *, struct pt_regs *);
 static void inia100_panic(char *msg);
-void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
 
-/* ---- EXTERNAL VARIABLES ---- */
-extern int Addinia100_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
-extern void init_inia100Adapter_table(void);
+/* ---- EXTERNAL FUNCTIONS ---- */
+extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+extern int Addinia100_into_Adapter_table(WORD, WORD, struct pci_dev *, int);
+extern int init_inia100Adapter_table(int);
 extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
 extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
 extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
+extern void orc_release_dma(ORC_HCS * hcsp, Scsi_Cmnd * cmnd);
 extern void orc_interrupt(ORC_HCS * hcsp);
-extern int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags);
+extern int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target, unsigned int ResetFlags);
 extern int orc_reset_scsi_bus(ORC_HCS * pHCB);
 extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb);
-extern int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt);
+extern int orc_abort_srb(ORC_HCS * hcsp, Scsi_Cmnd *SCpnt);
 extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx);
 extern int init_orchid(ORC_HCS * hcsp);
-
-extern int orc_num_scb;
-extern ORC_HCS orc_hcs[];
+extern struct inia100_Adpt_Struc *inia100_adpt;
 
 /*****************************************************************************
  Function name  : inia100AppendSRBToQueue
@@ -209,94 +202,90 @@
 *****************************************************************************/
 int orc_ReturnNumberOfAdapters(void)
 {
-	unsigned int i, iAdapters;
+	unsigned int iAdapters;
 
 	iAdapters = 0;
 	/*
 	 * PCI-bus probe.
 	 */
 	if (pcibios_present()) {
-		struct {
-			unsigned short vendor_id;
-			unsigned short device_id;
-		} const inia100_pci_devices[] =
-		{
-			{ORC_VENDOR_ID, I920_DEVICE_ID},
-			{ORC_VENDOR_ID, ORC_DEVICE_ID}
-		};
-
+		/*
+		 * Note: I removed the struct pci_device_list stuff since this
+		 * driver only cares about one device ID.  If that changes in
+		 * the future it can be added in with only a very moderate
+		 * amount of work.  It made the double scan of the device list
+		 * for getting a count and allocating the device list easier
+		 * to not have the for(i ... ) loop in there....
+		 */
 		unsigned int dRegValue;
 		WORD wBIOS, wBASE;
-		BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum;
-
 #ifdef MMAPIO
 		unsigned long page_offset, base;
 #endif
-
 		struct pci_dev *pdev = NULL;
 
-		bPCIBusNum = 0;
-		bPCIDeviceNum = 0;
-		init_inia100Adapter_table();
-		for (i = 0; i < NUMBER(inia100_pci_devices); i++) {
-			pdev = NULL;
-			while ((pdev = pci_find_device(inia100_pci_devices[i].vendor_id,
-					inia100_pci_devices[i].device_id,
-						       pdev)))
-			{
-				if (pci_enable_device(pdev))
-					continue;
-				if (iAdapters >= MAX_SUPPORTED_ADAPTERS)
-					break;	/* Never greater than maximum   */
-
-				if (i == 0) {
-					/*
-					   printk("inia100: The RAID controller is not supported by\n");
-					   printk("inia100:         this driver, we are ignoring it.\n");
-					 */
-				} else {
-					/*
-					 * Read sundry information from PCI BIOS.
-					 */
-					bPCIBusNum = pdev->bus->number;
-					bPCIDeviceNum = pdev->devfn;
-					dRegValue = pci_resource_start(pdev, 0);
-					if (dRegValue == -1) {	/* Check return code            */
-						printk("\n\rinia100: orchid read configuration error.\n");
-						return (0);	/* Read configuration space error  */
-					}
-
-					/* <02> read from base address + 0x50 offset to get the wBIOS balue. */
-					wBASE = (WORD) dRegValue;
-
-					/* Now read the interrupt line value */
-					dRegValue = pdev->irq;
-					bInterrupt = dRegValue;		/* Assign interrupt line      */
+		/*
+		 * Get a count of adapters that we expect to be able to use.
+		 * Pass that count to init_inia100Adapter_table() for malloc
+		 * reasons.
+		 */
+		pdev = NULL;
+		while((pdev=pci_find_device(ORC_VENDOR_ID, ORC_DEVICE_ID, pdev)))
+		{
+			if (pci_enable_device(pdev))
+				continue;
+			if (pci_set_dma_mask(pdev, (u64)0xffffffff)) {
+				printk(KERN_WARNING "Unable to set 32bit DMA "
+					"on inia100 adapter, ignoring.\n");
+				continue;
+			}
+			iAdapters++;
+		}
+		if(init_inia100Adapter_table(iAdapters))
+			return 0;
+		/*
+		 * Now go through the adapters again actually setting them up
+		 * and putting them in the table this time.
+		 */
+		pdev = NULL;
+		while((pdev=pci_find_device(ORC_VENDOR_ID, ORC_DEVICE_ID, pdev)))
+		{
+			/*
+			 * Read sundry information from PCI BIOS.
+			 */
+			dRegValue = pci_resource_start(pdev, 0);
+			if (dRegValue == -1) {	/* Check return code */
+				printk("\n\rinia100: orchid read configuration error.\n");
+				iAdapters--;
+				continue;	/* Read configuration space error  */
+			}
+
+			/* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+			wBASE = (WORD) dRegValue;
+
+			/* Now read the interrupt line value */
+			dRegValue = pdev->irq;
 
-					wBIOS = ORC_RDWORD(wBASE, 0x50);
+			wBIOS = ORC_RDWORD(wBASE, 0x50);
 
-					pci_set_master(pdev);
+			pci_set_master(pdev);
 
 #ifdef MMAPIO
-					base = wBASE & PAGE_MASK;
-					page_offset = wBASE - base;
+			base = wBASE & PAGE_MASK;
+			page_offset = wBASE - base;
 
-					/*
-					 * replace the next line with this one if you are using 2.1.x:
-					 * temp_p->maddr = ioremap(base, page_offset + 256);
-					 */
-					wBASE = ioremap(base, page_offset + 256);
-					if (wBASE) {
-						wBASE += page_offset;
-					}
+			/*
+			 * replace the next line with this one if you are using 2.1.x:
+			 * temp_p->maddr = ioremap(base, page_offset + 256);
+			 */
+			wBASE = ioremap(base, page_offset + 256);
+			if (wBASE) {
+				wBASE += page_offset;
+			}
 #endif
 
-					if (Addinia100_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum,
-					    bPCIDeviceNum) == SUCCESSFUL)
-						iAdapters++;
-				}
-			}	/* while(pdev=....) */
-		}		/* for PCI_DEVICES */
+			Addinia100_into_Adapter_table(wBIOS, wBASE, pdev, iAdapters);
+		}	/* while(pdev=....) */
 	}			/* PCI BIOS present */
 	return (iAdapters);
 }
@@ -317,8 +306,9 @@
 	int ok = 0, iAdapters;
 	ULONG dBiosAdr;
 	BYTE *pbBiosAdr;
+	struct pci_dev *pdev;
 
-	tpnt->proc_name = "INIA100";
+	tpnt->proc_name = "inia100";
 	if (setup_called) {
 		/* Setup by inia100_setup          */
 		printk("inia100: processing commandline: ");
@@ -330,44 +320,38 @@
 	if (iAdapters == 0)	/* If no orc founded, return */
 		return (0);
 
-	orc_num_ch = (iAdapters > orc_num_ch) ? orc_num_ch : iAdapters;
-	orc_num_scb = ORC_MAXQUEUE;
-
-	/* clear the memory needed for HCS */
-	i = orc_num_ch * sizeof(ORC_HCS);
-	memset((unsigned char *) &orc_hcs[0], 0, i);	/* Initialize orc_hcs 0   */
-
 #if 0
 	printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n",
 	       orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB));
 #endif
 
-	for (i = 0, pHCB = &orc_hcs[0];		/* Get pointer for control block */
-	     i < orc_num_ch;
-	     i++, pHCB++) {
-
-		pHCB->pSRB_head = NULL;		/* Initial SRB save queue       */
-		pHCB->pSRB_tail = NULL;		/* Initial SRB save queue       */
+	for (i = 0; i < iAdapters; i++) {
+		pdev = inia100_adpt[i].ADPT_pdev;
+		hreg = scsi_register(tpnt, sizeof(ORC_HCS));
+		if (hreg == NULL) {
+			goto out_disable;
+		}
+		pHCB = (ORC_HCS *)hreg->hostdata;
+		pHCB->pdev = pdev;
+		pHCB->pSRB_head = NULL;	/* Initial SRB save queue       */
+		pHCB->pSRB_tail = NULL;	/* Initial SRB save queue       */
 		pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
 		pHCB->BitAllocFlagLock = SPIN_LOCK_UNLOCKED;
 		/* Get total memory needed for SCB */
-		sz = orc_num_scb * sizeof(ORC_SCB);
-		if ((pHCB->HCS_virScbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
+		sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
+		if ((pHCB->HCS_virScbArray = (PVOID) pci_alloc_consistent(pdev, sz, &pHCB->HCS_physScbArray)) == NULL) {
 			printk("inia100: SCB memory allocation error\n");
-			return (0);
+			goto out_unregister;
 		}
 		memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz);
-		pHCB->HCS_physScbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virScbArray);
 
 		/* Get total memory needed for ESCB */
-		sz = orc_num_scb * sizeof(ESCB);
-		if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
+		sz = ORC_MAXQUEUE * sizeof(ESCB);
+		if ((pHCB->HCS_virEscbArray = (PVOID) pci_alloc_consistent(pdev, sz, &pHCB->HCS_physEscbArray)) == NULL) {
 			printk("inia100: ESCB memory allocation error\n");
-			/* ?? does pHCB->HCS_virtScbArray leak ??*/
-			return (0);
+			goto out_unalloc;
 		}
 		memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz);
-		pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray);
 
 		get_orcPCIConfig(pHCB, i);
 
@@ -378,30 +362,24 @@
 
 		if (init_orchid(pHCB)) {	/* Initial orchid chip    */
 			printk("inia100: initial orchid fail!!\n");
-			return (0);
+			goto out_unalloc;
 		}
 		request_region(pHCB->HCS_Base, 256, "inia100");	/* Register */
 
-		hreg = scsi_register(tpnt, sizeof(ORC_HCS));
-		if (hreg == NULL) {
-			release_region(pHCB->HCS_Base, 256);	/* Register */
-			return 0;
-		}
 		hreg->io_port = pHCB->HCS_Base;
 		hreg->n_io_port = 0xff;
-		hreg->can_queue = orc_num_scb;	/* 03/05/98                   */
+		hreg->can_queue = ORC_MAXQUEUE;	/* 03/05/98                   */
 
 		hreg->unique_id = pHCB->HCS_Base;
 		hreg->max_id = pHCB->HCS_MaxTar;
 
-		hreg->max_lun = 32;	/* 10/21/97                     */
+		hreg->max_lun = 16;	/* 10/21/97                     */
 /*
    hreg->max_lun = 8;
    hreg->max_channel = 1;
  */
 		hreg->irq = pHCB->HCS_Intr;
 		hreg->this_id = pHCB->HCS_SCSI_ID;	/* Assign HCS index           */
-		hreg->base = (unsigned long)pHCB;
 
 #if 1
 		hreg->sg_tablesize = TOTAL_SG_ENTRY;	/* Maximun support is 32 */
@@ -410,36 +388,7 @@
 #endif
 
 		/* Initial orc chip           */
-		switch (i) {
-		case 0:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 1:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 2:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 3:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 4:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 5:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 6:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		case 7:
-			ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", hreg);
-			break;
-		default:
-			inia100_panic("inia100: Too many host adapters\n");
-			break;
-		}
-
+		ok = request_irq(pHCB->HCS_Intr, inia100_intr, SA_SHIRQ, "inia100", hreg);
 		if (ok < 0) {
 			if (ok == -EINVAL) {
 				printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr);
@@ -453,13 +402,34 @@
 					printk("         Contact author.\n");
 				}
 			}
-			inia100_panic("inia100: driver needs an IRQ.\n");
+			goto out_irq;
 		}
 	}
 
 	tpnt->this_id = -1;
 	tpnt->can_queue = 1;
+	kfree(inia100_adpt);
 	return 1;
+
+out_irq:
+        release_region(pHCB->HCS_Base, 256);
+out_unalloc:
+	if(pHCB->HCS_virEscbArray) {
+		pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ESCB),
+			pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+		pHCB->HCS_virEscbArray = NULL;
+	}
+	if(pHCB->HCS_virScbArray) {
+		pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+			pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+		pHCB->HCS_virScbArray = NULL;
+	}
+out_unregister:
+	scsi_unregister(hreg);
+out_disable:
+	pci_disable_device(pdev);
+	kfree(inia100_adpt);
+	return i;
 }
 
 /*****************************************************************************
@@ -473,7 +443,7 @@
 {				/* Create corresponding SCB     */
 	struct scatterlist *pSrbSG;
 	ORC_SG *pSG;		/* Pointer to SG list           */
-	int i;
+	int i, count_sg;
 	U32 TotalLen;
 	ESCB *pEScb;
 
@@ -493,17 +463,26 @@
 		pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
 		if (SCpnt->use_sg) {
 			TotalLen = 0;
-			pSCB->SCB_SGLen = (U32) (SCpnt->use_sg * 8);
 			pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
-			for (i = 0; i < SCpnt->use_sg; i++, pSG++, pSrbSG++) {
-				pSG->SG_Ptr = (U32) (VIRT_TO_BUS(pSrbSG->address));
-				pSG->SG_Len = (U32) pSrbSG->length;
-				TotalLen += (U32) pSrbSG->length;
+			count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
+				scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			pSCB->SCB_SGLen = (U32) (count_sg * 8);
+			for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
+				pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
+				pSG->SG_Len = (U32) sg_dma_len(pSrbSG);
+				TotalLen += (U32) sg_dma_len(pSrbSG);
 			}
-		} else {	/* Non SG                       */
+		} else if (SCpnt->request_bufflen != 0) {/* Non SG */
 			pSCB->SCB_SGLen = 0x8;
-			pSG->SG_Ptr = (U32) (VIRT_TO_BUS(SCpnt->request_buffer));
+			pSG->SG_Ptr = (U32) pci_map_single(pHCB->pdev,
+				SCpnt->request_buffer, SCpnt->request_bufflen,
+				scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			SCpnt->host_scribble = (void *)pSG->SG_Ptr;
 			pSG->SG_Len = (U32) SCpnt->request_bufflen;
+		} else {
+			pSCB->SCB_SGLen = 0;
+			pSG->SG_Ptr = 0;
+			pSG->SG_Len = 0;
 		}
 	}
 	pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
@@ -538,12 +517,7 @@
 	register ORC_SCB *pSCB;
 	ORC_HCS *pHCB;		/* Point to Host adapter control block */
 
-	if (SCpnt->lun > 16) {
-		SCpnt->result = (DID_TIME_OUT << 16);
-		done(SCpnt);	/* Notify system DONE           */
-		return (0);
-	}
-	pHCB = (ORC_HCS *) SCpnt->host->base;
+	pHCB = (ORC_HCS *) SCpnt->host->hostdata;
 	SCpnt->scsi_done = done;
 	/* Get free SCSI control block  */
 	if ((pSCB = orc_alloc_scb(pHCB)) == NULL) {
@@ -558,19 +532,6 @@
 }
 
 /*****************************************************************************
- Function name  : inia100_command
- Description    : We only support command in interrupt-driven fashion
- Input          : pHCB  -       Pointer to host adapter structure
- Output         : None.
- Return         : pSRB  -       Pointer to SCSI request block.
-*****************************************************************************/
-int inia100_command(Scsi_Cmnd * SCpnt)
-{
-	printk("inia100: interrupt driven driver; use inia100_queue()\n");
-	return -1;
-}
-
-/*****************************************************************************
  Function name  : inia100_abort
  Description    : Abort a queued command.
 	                 (commands that are on the bus can't be aborted easily)
@@ -582,8 +543,8 @@
 {
 	ORC_HCS *hcsp;
 
-	hcsp = (ORC_HCS *) SCpnt->host->base;
-	return orc_abort_srb(hcsp, (ULONG) SCpnt);
+	hcsp = (ORC_HCS *) SCpnt->host->hostdata;
+	return orc_abort_srb(hcsp, SCpnt);
 }
 
 /*****************************************************************************
@@ -597,12 +558,12 @@
 int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {				/* I need Host Control Block Information */
 	ORC_HCS *pHCB;
-	pHCB = (ORC_HCS *) SCpnt->host->base;
+	pHCB = (ORC_HCS *) SCpnt->host->hostdata;
 
 	if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
 		return orc_reset_scsi_bus(pHCB);
 	else
-		return orc_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags);
+		return orc_device_reset(pHCB, SCpnt, SCpnt->target, reset_flags);
 
 }
 
@@ -672,14 +633,14 @@
 		   (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
 	}
 	pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+	orc_release_dma(pHCB, pSRB);  /* release DMA before we call scsi_done */
 	pSRB->scsi_done(pSRB);	/* Notify system DONE           */
 
 	/* Find the next pending SRB    */
 	if ((pSRB = inia100PopSRBFromQueue(pHCB)) != NULL) {	/* Assume resend will success   */
-		/* Reuse old SCB                */
 		inia100BuildSCB(pHCB, pSCB, pSRB);	/* Create corresponding SCB     */
 		orc_exec_scb(pHCB, pSCB);	/* Start execute SCB            */
-	} else {		/* No Pending SRB               */
+	} else {
 		orc_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
 	}
 	return;
@@ -697,7 +658,7 @@
 	ORC_HCS *pHcb;		/* Point to Host adapter control block */
 	ORC_TCS *pTcb;
 
-	pHcb = (ORC_HCS *) disk->device->host->base;
+	pHcb = (ORC_HCS *) disk->device->host->hostdata;
 	pTcb = &pHcb->HCS_Tcs[disk->device->id];
 
 	if (pTcb->TCS_DrvHead) {
@@ -719,62 +680,19 @@
 }
 
 
-static void subIntr(ORC_HCS * pHCB, int irqno, struct Scsi_Host *dev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(dev->host_lock, flags);
-
-	if (pHCB->HCS_Intr != irqno) {
-		spin_unlock_irqrestore(dev->host_lock, flags);
-		return;
-	}
-	orc_interrupt(pHCB);
-
-	spin_unlock_irqrestore(dev->host_lock, flags);
-}
-
 /*
- * Interrupts handler (main routine of the driver)
+ * Interrupt handler (main routine of the driver)
  */
-static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs)
+static void inia100_intr(int irqno, void *devid, struct pt_regs *regs)
 {
-	subIntr(&orc_hcs[0], irqno, dev_id);
-}
-
-static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[1], irqno, dev_id);
-}
-
-static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[2], irqno, dev_id);
-}
-
-static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[3], irqno, dev_id);
-}
-
-static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[4], irqno, dev_id);
-}
-
-static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[5], irqno, dev_id);
-}
-
-static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[6], irqno, dev_id);
-}
+	struct Scsi_Host *host = (struct Scsi_Host *)devid;
+	ORC_HCS *pHcb;
+	unsigned long flags;
 
-static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs)
-{
-	subIntr(&orc_hcs[7], irqno, dev_id);
+ 	pHcb = (ORC_HCS *)host->hostdata;	/* Host adapter control block */
+	spin_lock_irqsave(host->host_lock, flags);
+	orc_interrupt(pHcb);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 /* 
@@ -791,8 +709,21 @@
  */
 int inia100_release(struct Scsi_Host *hreg)
 {
+	ORC_HCS *pHCB = (ORC_HCS *)hreg->hostdata;
+
         free_irq(hreg->irq, hreg);
         release_region(hreg->io_port, 256);
+	if(pHCB->HCS_virEscbArray) {
+		pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ESCB),
+			pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+		pHCB->HCS_virEscbArray = NULL;
+	}
+	if(pHCB->HCS_virScbArray) {
+		pci_free_consistent(pHCB->pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+			pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+		pHCB->HCS_virScbArray = NULL;
+	}
+	pci_disable_device(pHCB->pdev);
         return 0;
 } 
 
diff -Nru a/drivers/scsi/inia100.h b/drivers/scsi/inia100.h
--- a/drivers/scsi/inia100.h	Fri Jul  5 16:42:44 2002
+++ b/drivers/scsi/inia100.h	Fri Jul  5 16:42:44 2002
@@ -58,6 +58,9 @@
  * Revision History:
  *	06/18/98 HL, Initial production Version 1.02
  *	12/19/98 bv, Use spinlocks for 2.1.95 and up
+ *	06/25/02 Doug Ledford <dledford@redhat.com>
+ *		 - This and the i60uscsi.h file are almost identical,
+ *		   merged them into a single header used by both .c files.
  ****************************************************************************/
 
 #ifndef	CVT_LINUX_VERSION
@@ -68,13 +71,14 @@
 #include <linux/version.h>
 #endif
 
+#include <linux/config.h>
 #include <linux/types.h>
+#include <linux/pci.h>
 
 #include "sd.h"
 
 extern int inia100_detect(Scsi_Host_Template *);
 extern int inia100_release(struct Scsi_Host *);
-extern int inia100_command(Scsi_Cmnd *);
 extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 extern int inia100_abort(Scsi_Cmnd *);
 extern int inia100_reset(Scsi_Cmnd *, unsigned int);
@@ -86,13 +90,13 @@
 #define INIA100	{ \
 	next:		NULL,						\
 	module:		NULL,						\
-	proc_name:	"INIA100", \
+	proc_name:	"inia100", \
 	proc_info:	NULL,				\
 	name:		inia100_REVID, \
 	detect:		inia100_detect, \
 	release:	inia100_release, \
 	info:		NULL,					\
-	command:	inia100_command, \
+	command:	NULL, \
 	queuecommand:	inia100_queue, \
  	eh_strategy_handler: NULL, \
  	eh_abort_handler: NULL, \
@@ -112,7 +116,6 @@
 	use_clustering:	ENABLE_CLUSTERING, \
 }
 
-#define VIRT_TO_BUS(i)  (unsigned int) virt_to_bus((void *)(i))
 #define ULONG   unsigned long
 #define PVOID   void *
 #define USHORT  unsigned short
@@ -139,15 +142,16 @@
 #endif
 #if 1
 #define ORC_MAXQUEUE		245
+#define ORC_MAXTAGS		64
 #else
 #define ORC_MAXQUEUE		25
+#define ORC_MAXTAGS		8
 #endif
 
 #define TOTAL_SG_ENTRY		32
 #define MAX_TARGETS		16
 #define IMAX_CDB			15
 #define SENSE_SIZE		14
-#define MAX_SUPPORTED_ADAPTERS  4
 #define SUCCESSFUL              0x00
 
 #define I920_DEVICE_ID	0x0002	/* Initio's inic-950 product ID   */
@@ -160,6 +164,12 @@
 	U32 SG_Len;		/* Data Length */
 } ORC_SG;
 
+typedef struct inia100_Adpt_Struc {
+        UWORD ADPT_BIOS;        /* 0 */
+        UWORD ADPT_BASE;        /* 1 */
+        struct pci_dev *ADPT_pdev;      /* 2 */
+} INIA100_ADPT_STRUCT;
+
 
 /* SCSI related definition                                              */
 #define DISC_NOT_ALLOW          0x80	/* Disconnect is not allowed    */
@@ -374,9 +384,9 @@
 	USHORT HCS_AFlags;	/* Adapter info. defined flags   */
 	ULONG HCS_Timeout;	/* Adapter timeout value   */
 	PVOID HCS_virScbArray;	/* 28 Virtual Pointer to SCB array     */
-	U32 HCS_physScbArray;	/* Scb Physical address */
+	dma_addr_t HCS_physScbArray;	/* Scb Physical address */
 	PVOID HCS_virEscbArray;	/* Virtual pointer to ESCB Scatter list */
-	U32 HCS_physEscbArray;	/* scatter list Physical address */
+	dma_addr_t HCS_physEscbArray;	/* scatter list Physical address */
 	UBYTE TargetFlag[16];	/* 30  target configuration, TCF_EN_TAG */
 	UBYTE MaximumTags[16];	/* 40  ORC_MAX_SCBS */
 	UBYTE ActiveTags[16][16];	/* 50 */
@@ -386,6 +396,7 @@
 	Scsi_Cmnd *pSRB_head;
 	Scsi_Cmnd *pSRB_tail;
 	spinlock_t pSRB_lock;
+	struct pci_dev *pdev;
 } ORC_HCS;
 
 /* Bit Definition for HCS_Flags */
@@ -438,3 +449,148 @@
 /*----------------------------------------------*/
 #define	MAX_PCI_DEVICES	21
 #define	MAX_PCI_BUSES	8
+
+typedef struct Adpt_Struc {
+        USHORT ADPT_BIOS;       /* 0 */
+        UBYTE ADPT_BASE;        /* 1 */
+        UBYTE ADPT_Bus;         /* 2 */
+        UBYTE ADPT_Device;      /* 3 */
+        UBYTE ADPT_Reserved[3];
+} JACS, *PJACS;
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+        UCHAR SubVendorID0;     /* 00 - Sub Vendor ID           */
+        UCHAR SubVendorID1;     /* 00 - Sub Vendor ID           */
+        UCHAR SubSysID0;        /* 02 - Sub System ID           */
+        UCHAR SubSysID1;        /* 02 - Sub System ID           */
+        UCHAR SubClass;         /* 04 - Sub Class               */
+        UCHAR VendorID0;        /* 05 - Vendor ID               */
+        UCHAR VendorID1;        /* 05 - Vendor ID               */
+        UCHAR DeviceID0;        /* 07 - Device ID               */
+        UCHAR DeviceID1;        /* 07 - Device ID               */
+        UCHAR Reserved0[2];     /* 09 - Reserved                */
+        UCHAR Revision;         /* 0B - Revision of data structure */
+        /* ----Host Adapter Structure ---- */
+        UCHAR NumOfCh;          /* 0C - Number of SCSI channel  */
+        UCHAR BIOSConfig1;      /* 0D - BIOS configuration 1    */
+        UCHAR BIOSConfig2;      /* 0E - BIOS boot channel&target ID */
+        UCHAR BIOSConfig3;      /* 0F - BIOS configuration 3    */
+        /* ----SCSI channel Structure ---- */
+        /* from "CTRL-I SCSI Host Adapter SetUp menu "  */
+        UCHAR SCSI0Id;          /* 10 - Channel 0 SCSI ID       */
+        UCHAR SCSI0Config;      /* 11 - Channel 0 SCSI configuration */
+        UCHAR SCSI0MaxTags;     /* 12 - Channel 0 Maximum tags  */
+        UCHAR SCSI0ResetTime;   /* 13 - Channel 0 Reset recovering time */
+        UCHAR ReservedforChannel0[2];   /* 14 - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                        */
+        UCHAR Target00Config;   /* 16 - Channel 0 Target 0 config */
+        UCHAR Target01Config;   /* 17 - Channel 0 Target 1 config */
+        UCHAR Target02Config;   /* 18 - Channel 0 Target 2 config */
+        UCHAR Target03Config;   /* 19 - Channel 0 Target 3 config */
+        UCHAR Target04Config;   /* 1A - Channel 0 Target 4 config */
+        UCHAR Target05Config;   /* 1B - Channel 0 Target 5 config */
+        UCHAR Target06Config;   /* 1C - Channel 0 Target 6 config */
+        UCHAR Target07Config;   /* 1D - Channel 0 Target 7 config */
+        UCHAR Target08Config;   /* 1E - Channel 0 Target 8 config */
+        UCHAR Target09Config;   /* 1F - Channel 0 Target 9 config */
+        UCHAR Target0AConfig;   /* 20 - Channel 0 Target A config */
+        UCHAR Target0BConfig;   /* 21 - Channel 0 Target B config */
+        UCHAR Target0CConfig;   /* 22 - Channel 0 Target C config */
+        UCHAR Target0DConfig;   /* 23 - Channel 0 Target D config */
+        UCHAR Target0EConfig;   /* 24 - Channel 0 Target E config */
+        UCHAR Target0FConfig;   /* 25 - Channel 0 Target F config */
+
+        UCHAR SCSI1Id;          /* 26 - Channel 1 SCSI ID       */
+        UCHAR SCSI1Config;      /* 27 - Channel 1 SCSI configuration */
+        UCHAR SCSI1MaxTags;     /* 28 - Channel 1 Maximum tags  */
+        UCHAR SCSI1ResetTime;   /* 29 - Channel 1 Reset recovering time */
+        UCHAR ReservedforChannel1[2];   /* 2A - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                                          */
+        UCHAR Target10Config;   /* 2C - Channel 1 Target 0 config */
+        UCHAR Target11Config;   /* 2D - Channel 1 Target 1 config */
+        UCHAR Target12Config;   /* 2E - Channel 1 Target 2 config */
+        UCHAR Target13Config;   /* 2F - Channel 1 Target 3 config */
+        UCHAR Target14Config;   /* 30 - Channel 1 Target 4 config */
+        UCHAR Target15Config;   /* 31 - Channel 1 Target 5 config */
+        UCHAR Target16Config;   /* 32 - Channel 1 Target 6 config */
+        UCHAR Target17Config;   /* 33 - Channel 1 Target 7 config */
+        UCHAR Target18Config;   /* 34 - Channel 1 Target 8 config */
+        UCHAR Target19Config;   /* 35 - Channel 1 Target 9 config */
+        UCHAR Target1AConfig;   /* 36 - Channel 1 Target A config */
+        UCHAR Target1BConfig;   /* 37 - Channel 1 Target B config */
+        UCHAR Target1CConfig;   /* 38 - Channel 1 Target C config */
+        UCHAR Target1DConfig;   /* 39 - Channel 1 Target D config */
+        UCHAR Target1EConfig;   /* 3A - Channel 1 Target E config */
+        UCHAR Target1FConfig;   /* 3B - Channel 1 Target F config */
+        UCHAR reserved[3];      /* 3C - Reserved                */
+        /* ---------- CheckSum ----------       */
+        UCHAR CheckSum;         /* 3F - Checksum of NVRam       */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC_BIOSENABLE  0x01    /* BIOS enable                    */
+#define NBC_CDROM       0x02    /* Support bootable CDROM */
+#define NBC_REMOVABLE   0x04    /* Support removable drive        */
+
+/* Bios Configuration for nvram->BIOSConfig2                            */
+#define NBB_TARGET_MASK 0x0F    /* Boot SCSI target ID number     */
+#define NBB_CHANL_MASK  0xF0    /* Boot SCSI channel number       */
+
+/* Bit definition for nvram->SCSIConfig                                 */
+#define NCC_BUSRESET    0x01    /* Reset SCSI bus at power up     */
+#define NCC_PARITYCHK   0x02    /* SCSI parity enable             */
+#define NCC_LVDS        0x10    /* Enable LVDS                    */
+#define NCC_ACTTERM1    0x20    /* Enable active terminator 1     */
+#define NCC_ACTTERM2    0x40    /* Enable active terminator 2     */
+#define NCC_AUTOTERM    0x80    /* Enable auto termination        */
+
+/* Bit definition for nvram->TargetxConfig                              */
+#define NTC_PERIOD      0x07    /* Maximum Sync. Speed            */
+#define NTC_1GIGA       0x08    /* 255 head / 63 sectors (64/32) */
+#define NTC_NO_SYNC     0x10    /* NO SYNC. NEGO          */
+#define NTC_NO_WIDESYNC 0x20    /* NO WIDE SYNC. NEGO             */
+#define NTC_DISC_ENABLE 0x40    /* Enable SCSI disconnect */
+#define NTC_SPINUP      0x80    /* Start disk drive               */
+
+/* Default NVRam values                                                 */
+#define NBC_DEFAULT     (NBC_ENABLE)
+#define NCC_DEFAULT     (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK)
+#define NCC_MAX_TAGS    0x20    /* Maximum tags per target        */
+#define NCC_RESET_TIME  0x0A    /* SCSI RESET recovering time     */
+#define NTC_DEFAULT     (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
+
+typedef union {                 /* Union define for mechanism 1   */
+        struct {
+                unsigned char RegNum;
+                unsigned char FcnNum:3;
+                unsigned char DeviceNum:5;
+                unsigned char BusNum;
+                unsigned char Reserved:7;
+                unsigned char Enable:1;
+        } sConfigAdr;
+        unsigned long lConfigAdr;
+} CONFIG_ADR;
+
+typedef union {                 /* Union define for mechanism 2   */
+        struct {
+                unsigned char RegNum;
+                unsigned char DeviceNum;
+                unsigned short Reserved;
+        } sHostAdr;
+        unsigned long lHostAdr;
+} HOST_ADR;
+
+#define ORC_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+#define ORC_RDLONG(x,y)         (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+#define ORC_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define ORC_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define ORC_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
+
+
+
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/osst.c	Fri Jul  5 16:43:00 2002
@@ -270,7 +270,7 @@
 /* Wakeup from interrupt */
 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 {
-	unsigned int dev = TAPE_NR(SCpnt->request.rq_dev);
+	unsigned int dev = TAPE_NR(SCpnt->request->rq_dev);
 	OS_Scsi_Tape * STp;
 
 	if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) {
@@ -285,13 +285,13 @@
 		}
 		else
 			(STp->buffer)->midlevel_result = SCpnt->result;
-		SCpnt->request.rq_status = RQ_SCSI_DONE;
+		SCpnt->request->rq_status = RQ_SCSI_DONE;
 		(STp->buffer)->last_SRpnt = SCpnt->sc_request;
 
 #if DEBUG
 		STp->write_pending = 0;
 #endif
-		complete(SCpnt->request.waiting);
+		complete(SCpnt->request->waiting);
 	}
 #if DEBUG
 	else if (debugging)
@@ -313,7 +313,7 @@
 #endif
 	if (SRpnt == NULL) {
 		if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) {
-			printk(KERN_ERR "osst%d:E: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+			printk(KERN_ERR "osst%d:E: Can't get SCSI request->\n", TAPE_NR(STp->devt));
 			if (signal_pending(current))
 				(STp->buffer)->syscall_result = (-EINTR);
 			else
@@ -336,15 +336,15 @@
 		bp = (STp->buffer)->b_data;
 	SRpnt->sr_data_direction = direction;
 	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_request.waiting = &(STp->wait);
-	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
-	SRpnt->sr_request.rq_dev = STp->devt;
+	SRpnt->sr_request->waiting = &(STp->wait);
+	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request->rq_dev = STp->devt;
 
 	scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
 
 	if (do_wait) {
-		wait_for_completion(SRpnt->sr_request.waiting);
-		SRpnt->sr_request.waiting = NULL;
+		wait_for_completion(SRpnt->sr_request->waiting);
+		SRpnt->sr_request->waiting = NULL;
 		STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
 #ifdef OSST_INJECT_ERRORS
 		if (STp->buffer->syscall_result == 0 &&
@@ -377,7 +377,7 @@
 		STp->nbr_finished++;
 #endif
 	wait_for_completion(&(STp->wait));
-	(STp->buffer)->last_SRpnt->sr_request.waiting = NULL;
+	(STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
 
 	STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
 
diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/qla1280.c	Fri Jul  5 16:43:00 2002
@@ -4236,7 +4236,7 @@
 				/* Set transfer direction (READ and WRITE) */
 				/* Linux doesn't tell us                   */
 				/*
-				 * For block devices, cmd->request.cmd has the operation
+				 * For block devices, cmd->request->cmd has the operation
 				 * For character devices, this isn't always set properly, so
 				 * we need to check data_cmnd[0].  This catches the conditions
 				 * for st.c, but not sg. Generic commands are pass down to us.
@@ -6241,7 +6241,7 @@
 	       cmd->tag, cmd->flags, cmd->transfersize);
 	printk("  Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd));
 	printk(" underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n",
-	       cmd->underflow, sp->dir, cmd->request.cmd);
+	       cmd->underflow, sp->dir, cmd->request->cmd);
 }
 
 /**************************************************************************
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi.c	Fri Jul  5 16:43:00 2002
@@ -130,8 +130,13 @@
 	16, 12, 10, 10
 };
 static unsigned long serial_number;
-static Scsi_Cmnd *scsi_bh_queue_head;
-static Scsi_Cmnd *scsi_bh_queue_tail;
+
+struct softscsi_data {
+	Scsi_Cmnd *head;
+	Scsi_Cmnd *tail;
+};
+
+static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned;
 
 /*
  * Note - the initial logging level can be set here to log events at boot time.
@@ -253,11 +258,20 @@
  
 static void scsi_wait_done(Scsi_Cmnd * SCpnt)
 {
-	struct request *req;
+	struct request *req = SCpnt->request;
+        struct request_queue *q = &SCpnt->device->request_queue;
+        unsigned long flags;
 
-	req = &SCpnt->request;
+        ASSERT_LOCK(q->queue_lock, 0);
 	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
 
+        spin_lock_irqsave(q->queue_lock, flags);
+
+        if(blk_rq_tagged(req))
+                blk_queue_end_tag(q, req);
+
+        spin_unlock_irqrestore(q->queue_lock, flags);
+
 	if (req->waiting)
 		complete(req->waiting);
 }
@@ -271,12 +285,6 @@
 static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Used to protect insertion into and removal from the queue of
- * commands to be processed by the bottom half handler.
- */
-static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
-
-/*
  * Function:    scsi_allocate_request
  *
  * Purpose:     Allocate a request descriptor.
@@ -296,17 +304,19 @@
 Scsi_Request *scsi_allocate_request(Scsi_Device * device)
 {
   	Scsi_Request *SRpnt = NULL;
+        const int offset = ALIGN(sizeof(Scsi_Request), 4);
+        const int size = offset + sizeof(struct request);
   
   	if (!device)
   		panic("No device passed to scsi_allocate_request().\n");
   
-	SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC);
+        SRpnt = (Scsi_Request *) kmalloc(size, GFP_ATOMIC);
 	if( SRpnt == NULL )
 	{
 		return NULL;
 	}
-
-	memset(SRpnt, 0, sizeof(Scsi_Request));
+	memset(SRpnt, 0, size);
+        SRpnt->sr_request = (struct request *)(((char *)SRpnt) + offset);
 	SRpnt->sr_device = device;
 	SRpnt->sr_host = device->host;
 	SRpnt->sr_magic = SCSI_REQ_MAGIC;
@@ -434,7 +444,7 @@
 			 * Now we can check for a free command block for this device.
 			 */
 			for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) {
-				if (SCpnt->request.rq_status == RQ_INACTIVE)
+				if (SCpnt->request == NULL)
 					break;
 			}
 		}
@@ -503,9 +513,7 @@
 		}
 	}
 
-	SCpnt->request.rq_status = RQ_SCSI_BUSY;
-	SCpnt->request.waiting = NULL;	/* And no one is waiting for this
-					 * to complete */
+	SCpnt->request = NULL;
 	atomic_inc(&SCpnt->host->host_active);
 	atomic_inc(&SCpnt->device->device_active);
 
@@ -548,7 +556,7 @@
 
         SDpnt = SCpnt->device;
 
-	SCpnt->request.rq_status = RQ_INACTIVE;
+	SCpnt->request = NULL;
 	SCpnt->state = SCSI_STATE_UNUSED;
 	SCpnt->owner = SCSI_OWNER_NOBODY;
 	atomic_dec(&SCpnt->host->host_active);
@@ -771,13 +779,13 @@
 	DECLARE_COMPLETION(wait);
 	request_queue_t *q = &SRpnt->sr_device->request_queue;
 	
-	SRpnt->sr_request.waiting = &wait;
-	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request->waiting = &wait;
+	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
 	scsi_do_req (SRpnt, (void *) cmnd,
 		buffer, bufflen, scsi_wait_done, timeout, retries);
 	generic_unplug_device(q);
 	wait_for_completion(&wait);
-	SRpnt->sr_request.waiting = NULL;
+	SRpnt->sr_request->waiting = NULL;
 	if( SRpnt->sr_command != NULL )
 	{
 		scsi_release_command(SRpnt->sr_command);
@@ -928,8 +936,7 @@
 	SCpnt->cmd_len = SRpnt->sr_cmd_len;
 	SCpnt->use_sg = SRpnt->sr_use_sg;
 
-	memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request,
-	       sizeof(SRpnt->sr_request));
+        SCpnt->request = SRpnt->sr_request;
 	memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd, 
 	       sizeof(SCpnt->data_cmnd));
 	SCpnt->reset_chain = NULL;
@@ -1089,37 +1096,29 @@
 	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
 }
 
-void scsi_tasklet_func(unsigned long);
-static DECLARE_TASKLET(scsi_tasklet, scsi_tasklet_func, 0);
-
-/*
+/**
+ * scsi_done - Mark this command as done
+ * @SCpnt: The SCSI Command which we think we've completed.
+ *
  * This function is the mid-level interrupt routine, which decides how
- *  to handle error conditions.  Each invocation of this function must
- *  do one and *only* one of the following:
+ * to handle error conditions.  Each invocation of this function must
+ * do one and *only* one of the following:
  *
  *      1) Insert command in BH queue.
  *      2) Activate error handler for host.
  *
- * FIXME(eric) - I am concerned about stack overflow (still).  An
- * interrupt could come while we are processing the bottom queue,
- * which would cause another command to be stuffed onto the bottom
- * queue, and it would in turn be processed as that interrupt handler
- * is returning.  Given a sufficiently steady rate of returning
- * commands, this could cause the stack to overflow.  I am not sure
- * what is the most appropriate solution here - we should probably
- * keep a depth count, and not process any commands while we still
- * have a bottom handler active higher in the stack.
- *
- * There is currently code in the bottom half handler to monitor
- * recursion in the bottom handler and report if it ever happens.  If
- * this becomes a problem, it won't be hard to engineer something to
- * deal with it so that only the outer layer ever does any real
- * processing.  
+ * There is no longer a problem with stack overflow.  Interrupts queue
+ * Scsi_Cmnd on a per-CPU queue and the softirq handler removes them
+ * from the queue one at a time.
+ *
+ * This function is sometimes called from interrupt context, but sometimes
+ * from task context.
  */
 void scsi_done(Scsi_Cmnd * SCpnt)
 {
 	unsigned long flags;
-	int tstatus;
+	int cpu, tstatus;
+	struct softscsi_data *queue;
 
 	/*
 	 * We don't have to worry about this one timing out any more.
@@ -1155,7 +1154,6 @@
 		SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt));
 		return;
 	}
-	spin_lock_irqsave(&scsi_bhqueue_lock, flags);
 
 	SCpnt->serial_number_at_timeout = 0;
 	SCpnt->state = SCSI_STATE_BHQUEUE;
@@ -1163,75 +1161,49 @@
 	SCpnt->bh_next = NULL;
 
 	/*
-	 * Next, put this command in the BH queue.
-	 * 
-	 * We need a spinlock here, or compare and exchange if we can reorder incoming
-	 * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times
-	 * before bh is serviced. -jj
+	 * Next, put this command in the softirq queue.
 	 *
-	 * We already have the io_request_lock here, since we are called from the
-	 * interrupt handler or the error handler. (DB)
-	 *
-	 * This may be true at the moment, but I would like to wean all of the low
-	 * level drivers away from using io_request_lock.   Technically they should
-	 * all use their own locking.  I am adding a small spinlock to protect
-	 * this datastructure to make it safe for that day.  (ERY)
-	 */
-	if (!scsi_bh_queue_head) {
-		scsi_bh_queue_head = SCpnt;
-		scsi_bh_queue_tail = SCpnt;
+	 * This is a per-CPU queue, so we just disable local interrupts
+	 * and need no spinlock.
+	 */
+
+	local_irq_save(flags);
+
+	cpu = smp_processor_id();
+	queue = &softscsi_data[cpu];
+
+	if (!queue->head) {
+		queue->head = SCpnt;
+		queue->tail = SCpnt;
 	} else {
-		scsi_bh_queue_tail->bh_next = SCpnt;
-		scsi_bh_queue_tail = SCpnt;
+		queue->tail->bh_next = SCpnt;
+		queue->tail = SCpnt;
 	}
 
-	spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
-	/*
-	 * Mark the bottom half handler to be run.
-	 */
-	tasklet_hi_schedule(&scsi_tasklet);
+	cpu_raise_softirq(cpu, SCSI_SOFTIRQ);
+
+	local_irq_restore(flags);
 }
 
-/*
- * Procedure:   scsi_bottom_half_handler
- *
- * Purpose:     Called after we have finished processing interrupts, it
- *              performs post-interrupt handling for commands that may
- *              have completed.
- *
- * Notes:       This is called with all interrupts enabled.  This should reduce
- *              interrupt latency, stack depth, and reentrancy of the low-level
- *              drivers.
+/**
+ * scsi_softirq - Perform post-interrupt handling for completed commands
  *
- * The io_request_lock is required in all the routine. There was a subtle
- * race condition when scsi_done is called after a command has already
- * timed out but before the time out is processed by the error handler.
- * (DB)
- *
- * I believe I have corrected this.  We simply monitor the return status of
- * del_timer() - if this comes back as 0, it means that the timer has fired
- * and that a timeout is in progress.   I have modified scsi_done() such
- * that in this instance the command is never inserted in the bottom
- * half queue.  Thus the only time we hold the lock here is when
- * we wish to atomically remove the contents of the queue.
+ * This is called with all interrupts enabled.  This should reduce
+ * interrupt latency, stack depth, and reentrancy of the low-level
+ * drivers.
  */
-void scsi_tasklet_func(unsigned long ignore)
+static void scsi_softirq(struct softirq_action *h)
 {
-	Scsi_Cmnd *SCpnt;
-	Scsi_Cmnd *SCnext;
-	unsigned long flags;
+	int cpu = smp_processor_id();
+	struct softscsi_data *queue = &softscsi_data[cpu];
 
+	while (queue->head) {
+		Scsi_Cmnd *SCpnt, *SCnext;
 
-	while (1 == 1) {
-		spin_lock_irqsave(&scsi_bhqueue_lock, flags);
-		SCpnt = scsi_bh_queue_head;
-		scsi_bh_queue_head = NULL;
-		spin_unlock_irqrestore(&scsi_bhqueue_lock, flags);
-
-		if (SCpnt == NULL) {
-			return;
-		}
-		SCnext = SCpnt->bh_next;
+		local_irq_disable();
+		SCpnt = queue->head;
+		queue->head = NULL;
+		local_irq_enable();
 
 		for (; SCpnt; SCpnt = SCnext) {
 			SCnext = SCpnt->bh_next;
@@ -1249,10 +1221,11 @@
 				break;
 			case NEEDS_RETRY:
 				/*
-				 * We only come in here if we want to retry a command.  The
-				 * test to see whether the command should be retried should be
-				 * keeping track of the number of tries, so we don't end up looping,
-				 * of course.
+				 * We only come in here if we want to retry a
+				 * command.  The test to see whether the
+				 * command should be retried should be keeping
+				 * track of the number of tries, so we don't
+				 * end up looping, of course.
 				 */
 				SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
 				SCpnt->host->host_failed, SCpnt->result));
@@ -1261,12 +1234,14 @@
 				break;
 			case ADD_TO_MLQUEUE:
 				/* 
-				 * This typically happens for a QUEUE_FULL message -
-				 * typically only when the queue depth is only
-				 * approximate for a given device.  Adding a command
-				 * to the queue for the device will prevent further commands
-				 * from being sent to the device, so we shouldn't end up
-				 * with tons of things being sent down that shouldn't be.
+				 * This typically happens for a QUEUE_FULL
+				 * message - typically only when the queue
+				 * depth is only approximate for a given
+				 * device.  Adding a command to the queue for
+				 * the device will prevent further commands
+				 * from being sent to the device, so we
+				 * shouldn't end up with tons of things being
+				 * sent down that shouldn't be.
 				 */
 				SCSI_LOG_MLCOMPLETE(3, printk("Command rejected as device queue full, put on ml queue %p\n",
                                                               SCpnt));
@@ -1274,8 +1249,8 @@
 				break;
 			default:
 				/*
-				 * Here we have a fatal error of some sort.  Turn it over to
-				 * the error handler.
+				 * Here we have a fatal error of some sort.
+				 * Turn it over to the error handler.
 				 */
 				SCSI_LOG_MLCOMPLETE(3, printk("Command failed %p %x active=%d busy=%d failed=%d\n",
 						    SCpnt, SCpnt->result,
@@ -1295,8 +1270,10 @@
 					SCpnt->state = SCSI_STATE_FAILED;
 					SCpnt->host->in_recovery = 1;
 					/*
-					 * If the host is having troubles, then look to see if this was the last
-					 * command that might have failed.  If so, wake up the error handler.
+					 * If the host is having troubles, then
+					 * look to see if this was the last
+					 * command that might have failed.  If
+					 * so, wake up the error handler.
 					 */
 					if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
 						SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
@@ -1305,15 +1282,14 @@
 					}
 				} else {
 					/*
-					 * We only get here if the error recovery thread has died.
+					 * We only get here if the error
+					 * recovery thread has died.
 					 */
 					scsi_finish_command(SCpnt);
 				}
-			}
+			}	/* switch */
 		}		/* for(; SCpnt...) */
-
-	}			/* while(1==1) */
-
+	}			/* while(queue->head) */
 }
 
 /*
@@ -1490,7 +1466,7 @@
 		SCpnt->target = SDpnt->id;
 		SCpnt->lun = SDpnt->lun;
 		SCpnt->channel = SDpnt->channel;
-		SCpnt->request.rq_status = RQ_INACTIVE;
+		SCpnt->request = NULL;
 		SCpnt->use_sg = 0;
 		SCpnt->old_use_sg = 0;
 		SCpnt->old_cmd_len = 0;
@@ -1942,6 +1918,11 @@
 				}
 				printk(KERN_INFO "scsi%d : %s\n",		/* And print a little message */
 				       shpnt->host_no, name);
+				strncpy(shpnt->host_driverfs_dev.name,name,
+					DEVICE_NAME_SIZE-1);
+				sprintf(shpnt->host_driverfs_dev.bus_id,
+					"scsi%d",
+					shpnt->host_no);
 			}
 		}
 
@@ -1950,6 +1931,8 @@
 		 */
 		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
 			if (shpnt->hostt == tpnt) {
+				/* first register parent with driverfs */
+				device_register(&shpnt->host_driverfs_dev);
 				scan_scsis(shpnt, 0, 0, 0, 0);
 				if (shpnt->select_queue_depths != NULL) {
 					(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
@@ -2062,16 +2045,16 @@
 			     SCpnt = SCpnt->next) {
 				online_status = SDpnt->online;
 				SDpnt->online = FALSE;
-				if (SCpnt->request.rq_status != RQ_INACTIVE) {
+				if (SCpnt->request && SCpnt->request->rq_status != RQ_INACTIVE) {
 					printk(KERN_ERR "SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n",
-					       SCpnt->request.rq_status, SCpnt->target, SCpnt->pid,
+					       SCpnt->request->rq_status, SCpnt->target, SCpnt->pid,
 					     SCpnt->state, SCpnt->owner);
 					for (SDpnt1 = shpnt->host_queue; SDpnt1;
 					     SDpnt1 = SDpnt1->next) {
 						for (SCpnt = SDpnt1->device_queue; SCpnt;
 						     SCpnt = SCpnt->next)
-							if (SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
-								SCpnt->request.rq_status = RQ_INACTIVE;
+							if (SCpnt->request->rq_status == RQ_SCSI_DISCONNECTING)
+								SCpnt->request->rq_status = RQ_INACTIVE;
 					}
 					SDpnt->online = online_status;
 					printk(KERN_ERR "Device busy???\n");
@@ -2082,7 +2065,8 @@
 				 * continue on.
 				 */
 				SCpnt->state = SCSI_STATE_DISCONNECTING;
-				SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;	/* Mark as busy */
+                                if(SCpnt->request)
+                                        SCpnt->request->rq_status = RQ_SCSI_DISCONNECTING;	/* Mark as busy */
 			}
 		}
 	}
@@ -2104,6 +2088,7 @@
 				goto err_out;
 			}
 			devfs_unregister (SDpnt->de);
+			put_device(&SDpnt->sdev_driverfs_dev);
 		}
 	}
 
@@ -2154,6 +2139,7 @@
 		/* Remove the /proc/scsi directory entry */
 		sprintf(name,"%d",shpnt->host_no);
 		remove_proc_entry(name, tpnt->proc_dir);
+		put_device(&shpnt->host_driverfs_dev);
 		if (tpnt->release)
 			(*tpnt->release) (shpnt);
 		else {
@@ -2392,11 +2378,11 @@
 				       SCpnt->target,
 				       SCpnt->lun,
 
-				       kdevname(SCpnt->request.rq_dev),
-				       SCpnt->request.sector,
-				       SCpnt->request.nr_sectors,
-				       (long)SCpnt->request.current_nr_sectors,
-				       SCpnt->request.rq_status,
+				       kdevname(SCpnt->request->rq_dev),
+				       SCpnt->request->sector,
+				       SCpnt->request->nr_sectors,
+				       (long)SCpnt->request->current_nr_sectors,
+				       SCpnt->request->rq_status,
 				       SCpnt->use_sg,
 
 				       SCpnt->retries,
@@ -2481,7 +2467,9 @@
 
 	sgp = scsi_sg_pools + SCpnt->sglist_len;
 
+	current->flags |= PF_NOWARN;
 	sgl = mempool_alloc(sgp->pool, gfp_mask);
+	current->flags &= ~PF_NOWARN;
 	if (sgl) {
 		memset(sgl, 0, sgp->size);
 		return sgl;
@@ -2502,6 +2490,34 @@
 	mempool_free(sgl, sgp->pool);
 }
 
+static int scsi_bus_match(struct device *scsi_driverfs_dev, 
+                          struct device_driver *scsi_driverfs_drv)
+{
+        char *p=0;
+
+        if (!strcmp("sd", scsi_driverfs_drv->name)) {
+                if ((p = strstr(scsi_driverfs_dev->bus_id, ":disc")) || 
+		    (p = strstr(scsi_driverfs_dev->bus_id, ":p"))) { 
+                        return 1;
+                }
+        } else if (!strcmp("sg", scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id, ":gen"))
+                        return 1;
+        } else if (!strcmp("sr",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":cd"))
+                        return 1;
+        } else if (!strcmp("st",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":mt"))
+                        return 1;
+        }
+        return 0;
+}
+
+struct bus_type scsi_driverfs_bus_type = {
+        name: "scsi",
+        match: scsi_bus_match,
+};
+
 static int __init init_scsi(void)
 {
 	struct proc_dir_entry *generic;
@@ -2548,6 +2564,11 @@
 		printk(KERN_INFO "scsi: host order: %s\n", scsihosts);	
 	scsi_host_no_init (scsihosts);
 
+	bus_register(&scsi_driverfs_bus_type);
+
+	/* Where we handle work queued by scsi_done */
+	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
+
 	return 0;
 }
 
@@ -2556,8 +2577,6 @@
 	Scsi_Host_Name *shn, *shn2 = NULL;
 	int i;
 
-	tasklet_kill(&scsi_tasklet);
-
         devfs_unregister (scsi_devfs_handle);
         for (shn = scsi_host_no_list;shn;shn = shn->next) {
 		if (shn->name)
@@ -2708,16 +2727,18 @@
 scsi_reset_provider(Scsi_Device *dev, int flag)
 {
 	Scsi_Cmnd SC, *SCpnt = &SC;
+        struct request req;
 	int rtn;
 
+        SCpnt->request = &req;
 	memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
 	SCpnt->host                    	= dev->host;
 	SCpnt->device                  	= dev;
 	SCpnt->target                  	= dev->id;
 	SCpnt->lun                     	= dev->lun;
 	SCpnt->channel                 	= dev->channel;
-	SCpnt->request.rq_status       	= RQ_SCSI_BUSY;
-	SCpnt->request.waiting        	= NULL;
+	SCpnt->request->rq_status      	= RQ_SCSI_BUSY;
+	SCpnt->request->waiting        	= NULL;
 	SCpnt->use_sg                  	= 0;
 	SCpnt->old_use_sg              	= 0;
 	SCpnt->old_cmd_len             	= 0;
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/scsi.h	Fri Jul  5 16:42:59 2002
@@ -417,6 +417,8 @@
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 
+extern struct bus_type scsi_driverfs_bus_type;
+
 
 /*
  * These are the error handling functions defined in scsi_error.c
@@ -566,6 +568,7 @@
         atomic_t                device_active; /* commands checked out for device */
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
+        Scsi_Cmnd *current_cmnd;	/* currently active command */
 
 	unsigned int id, lun, channel;
 
@@ -622,6 +625,7 @@
 
 	// Flag to allow revalidate to succeed in sd_open
 	int allow_revalidate;
+	struct device sdev_driverfs_dev;
 };
 
 
@@ -662,7 +666,7 @@
 	struct Scsi_Host *sr_host;
 	Scsi_Device *sr_device;
 	Scsi_Cmnd *sr_command;
-	struct request sr_request;	/* A copy of the command we are
+	struct request *sr_request;	/* A copy of the command we are
 				   working on */
 	unsigned sr_bufflen;	/* Size of data buffer */
 	void *sr_buffer;		/* Data buffer */
@@ -773,8 +777,8 @@
 				   transferred less actual number
 				   transferred (0 if not supported) */
 
-	struct request request;	/* A copy of the command we are
-				   working on */
+	struct request *request;	/* The command we are
+				   	   working on */
 
 	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];		/* obtained by REQUEST SENSE
 						 * when CHECK CONDITION is
@@ -855,5 +859,88 @@
 #define SCSI_TRY_RESET_HOST	3
 
 extern int scsi_reset_provider(Scsi_Device *, int);
+
+/**
+ * scsi_activate_tcq - turn on tag command queueing
+ * @SDpnt:	device to turn on TCQ for
+ * @depth:	queue depth
+ *
+ * Notes:
+ *	Eventually, I hope depth would be the maximum depth
+ *	the device could cope with and the real queue depth
+ *	would be adjustable from 0 to depth.
+ **/
+static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) {
+        request_queue_t *q = &SDpnt->request_queue;
+
+        if(SDpnt->tagged_supported && !blk_queue_tagged(q)) {
+                blk_queue_init_tags(q, depth);
+                SDpnt->tagged_queue = 1;
+        }
+}
+
+/**
+ * scsi_deactivate_tcq - turn off tag command queueing
+ * @SDpnt:	device to turn off TCQ for
+ **/
+static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt) {
+        blk_queue_free_tags(&SDpnt->request_queue);
+        SDpnt->tagged_queue = 0;
+}
+#define MSG_SIMPLE_TAG	0x20
+#define MSG_HEAD_TAG	0x21
+#define MSG_ORDERED_TAG	0x22
+
+#define SCSI_NO_TAG	(-1)    /* identify no tag in use */
+
+/**
+ * scsi_populate_tag_msg - place a tag message in a buffer
+ * @SCpnt:	pointer to the Scsi_Cmnd for the tag
+ * @msg:	pointer to the area to place the tag
+ *
+ * Notes:
+ *	designed to create the correct type of tag message for the 
+ *	particular request.  Returns the size of the tag message.
+ *	May return 0 if TCQ is disabled for this device.
+ **/
+static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) {
+        struct request *req = SCpnt->request;
+
+        if(!blk_rq_tagged(req))
+                return 0;
+    
+        if(req->flags & REQ_BARRIER)
+                *msg++ = MSG_ORDERED_TAG;
+        else
+                *msg++ = MSG_SIMPLE_TAG;
+
+        *msg++ = SCpnt->request->tag;
+
+        return 2;
+}
+
+/**
+ * scsi_find_tag - find a tagged command by device
+ * @SDpnt:	pointer to the ScSI device
+ * @tag:	the tag number
+ *
+ * Notes:
+ *	Only works with tags allocated by the generic blk layer.
+ **/
+static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
+
+        struct request *req;
+
+        if(tag == SCSI_NO_TAG)
+                /* single command, look in space */
+                return SDpnt->current_cmnd;
+
+        req = blk_queue_find_tag(&SDpnt->request_queue, tag);
+
+        if(req == NULL)
+                return NULL;
+
+        return (Scsi_Cmnd *)req->special;
+}
 
 #endif
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi_debug.c	Fri Jul  5 16:43:00 2002
@@ -694,7 +694,7 @@
 	{
 		int delay = SCSI_SETUP_LATENCY;
 
-		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+		delay += SCpnt->request->nr_sectors * SCSI_DATARATE;
 		if (delay)
 			usleep(delay);
 	}
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Fri Jul  5 16:42:48 2002
+++ b/drivers/scsi/scsi_error.c	Fri Jul  5 16:42:48 2002
@@ -319,7 +319,7 @@
 		return;
 	}
 
-	SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
 
 	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
 	SCpnt->eh_state = SUCCESS;
@@ -346,7 +346,7 @@
 STATIC
 void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer)
 {
-	SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
 
 	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
 	SCpnt->eh_state = (answer ? SUCCESS : FAILED);
@@ -601,7 +601,7 @@
 		 * Set up the semaphore so we wait for the command to complete.
 		 */
 		SCpnt->host->eh_action = &sem;
-		SCpnt->request.rq_status = RQ_SCSI_BUSY;
+		SCpnt->request->rq_status = RQ_SCSI_BUSY;
 
 		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		host->hostt->queuecommand(SCpnt, scsi_eh_done);
@@ -633,7 +633,7 @@
 				SCpnt->host->hostt->eh_abort_handler(SCpnt);
 			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			
-			SCpnt->request.rq_status = RQ_SCSI_DONE;
+			SCpnt->request->rq_status = RQ_SCSI_DONE;
 			SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
 			
 			SCpnt->eh_state = FAILED;
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi_lib.c	Fri Jul  5 16:43:00 2002
@@ -76,12 +76,10 @@
 	 * must not attempt merges on this) and that it acts as a soft
 	 * barrier
 	 */
-	rq->flags = REQ_SPECIAL | REQ_BARRIER;
+	rq->flags &= REQ_QUEUED;
+	rq->flags |= REQ_SPECIAL | REQ_BARRIER;
 
 	rq->special = data;
-	rq->q = NULL;
-	rq->bio = rq->biotail = NULL;
-	rq->nr_phys_segments = 0;
 
 	/*
 	 * We have the option of inserting the head or the tail of the queue.
@@ -90,6 +88,9 @@
 	 * device, or a host that is unable to accept a particular command.
 	 */
 	spin_lock_irqsave(q->queue_lock, flags);
+	/* If command is tagged, release the tag */
+	if(blk_rq_tagged(rq))
+		blk_queue_end_tag(q, rq);
 	_elv_add_request(q, rq, !at_head, 0);
 	q->request_fn(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
@@ -120,7 +121,7 @@
 {
 	request_queue_t *q = &SCpnt->device->request_queue;
 
-	__scsi_insert_special(q, &SCpnt->request, SCpnt, at_head);
+	__scsi_insert_special(q, SCpnt->request, SCpnt, at_head);
 	return 0;
 }
 
@@ -148,7 +149,7 @@
 {
 	request_queue_t *q = &SRpnt->sr_device->request_queue;
 
-	__scsi_insert_special(q, &SRpnt->sr_request, SRpnt, at_head);
+	__scsi_insert_special(q, SRpnt->sr_request, SRpnt, at_head);
 	return 0;
 }
 
@@ -259,8 +260,10 @@
 		 * in which case we need to request the blocks that come after
 		 * the bad sector.
 		 */
-		SCpnt->request.special = (void *) SCpnt;
-		_elv_add_request(q, &SCpnt->request, 0, 0);
+		SCpnt->request->special = (void *) SCpnt;
+		if(blk_rq_tagged(SCpnt->request))
+			blk_queue_end_tag(q, SCpnt->request);
+		_elv_add_request(q, SCpnt->request, 0, 0);
 	}
 
 	/*
@@ -356,15 +359,18 @@
 				     int frequeue)
 {
 	request_queue_t *q = &SCpnt->device->request_queue;
-	struct request *req = &SCpnt->request;
+	struct request *req = SCpnt->request;
+	int flags;
 
 	ASSERT_LOCK(q->queue_lock, 0);
 
+	spin_lock_irqsave(q->queue_lock, flags);
 	/*
 	 * If there are blocks left over at the end, set up the command
 	 * to queue the remainder of them.
 	 */
 	if (end_that_request_first(req, uptodate, sectors)) {
+		spin_unlock_irqrestore(q->queue_lock, flags);
 		if (!requeue)
 			return SCpnt;
 
@@ -376,15 +382,15 @@
 		return SCpnt;
 	}
 
-	/*
-	 * This request is done.  If there is someone blocked waiting for this
-	 * request, wake them up.
-	 */
-	if (req->waiting)
-		complete(req->waiting);
-
 	add_blkdev_randomness(major(req->rq_dev));
 
+	if(blk_rq_tagged(req))
+		blk_queue_end_tag(q, req);
+
+	end_that_request_last(req);
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
 	/*
 	 * This will goose the queue request function at the end, so we don't
 	 * need to worry about launching another command.
@@ -441,7 +447,7 @@
  */
 static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
 {
-	struct request *req = &SCpnt->request;
+	struct request *req = SCpnt->request;
 
 	ASSERT_LOCK(SCpnt->host->host_lock, 0);
 
@@ -491,7 +497,7 @@
 	int result = SCpnt->result;
 	int this_count = SCpnt->bufflen >> 9;
 	request_queue_t *q = &SCpnt->device->request_queue;
-	struct request *req = &SCpnt->request;
+	struct request *req = SCpnt->request;
 
 	/*
 	 * We must do one of several things here:
@@ -675,7 +681,7 @@
 	if (result) {
 		struct Scsi_Device_Template *STpnt;
 
-		STpnt = scsi_get_request_dev(&SCpnt->request);
+		STpnt = scsi_get_request_dev(SCpnt->request);
 		printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n",
 		       (STpnt ? STpnt->name : "device"),
 		       SCpnt->device->host->host_no,
@@ -868,7 +874,7 @@
 		 * the remainder of a partially fulfilled request that can 
 		 * come up when there is a medium error.  We have to treat
 		 * these two cases differently.  We differentiate by looking
-		 * at request.cmd, as this tells us the real story.
+		 * at request->cmd, as this tells us the real story.
 		 */
 		if (req->flags & REQ_SPECIAL) {
 			STpnt = NULL;
@@ -904,6 +910,9 @@
 			 */
 			if (!SCpnt)
 				break;
+
+			/* pull a tag out of the request if we have one */
+			SCpnt->tag = req->tag;
 		} else {
 			blk_dump_rq_flags(req, "SCSI bad req");
 			break;
@@ -924,18 +933,15 @@
 		 * reason to search the list, because all of the commands
 		 * in this queue are for the same device.
 		 */
-		blkdev_dequeue_request(req);
+		if(!(blk_queue_tagged(q) && (blk_queue_start_tag(q, req) == 0)))
+			blkdev_dequeue_request(req);
 
-		if (req != &SCpnt->request && req != &SRpnt->sr_request ) {
-			memcpy(&SCpnt->request, req, sizeof(struct request));
+		/* note the overloading of req->special.  When the tag
+		 * is active it always means SCpnt.  If the tag goes
+		 * back for re-queueing, it may be reset */
+		req->special = SCpnt;
+		SCpnt->request = req;
 
-			/*
-			 * We have copied the data out of the request block -
-			 * it is now in a field in SCpnt.  Release the request
-			 * block.
-			 */
-			blkdev_release_request(req);
-		}
 		/*
 		 * Now it is finally safe to release the lock.  We are
 		 * not going to noodle the request list until this
@@ -945,7 +951,7 @@
 		req = NULL;
 		spin_unlock_irq(q->queue_lock);
 
-		if (SCpnt->request.flags & REQ_CMD) {
+		if (SCpnt->request->flags & REQ_CMD) {
 			/*
 			 * This will do a couple of things:
 			 *  1) Fill in the actual SCSI command.
@@ -959,7 +965,7 @@
 			 * request to be rejected immediately.
 			 */
 			if (STpnt == NULL)
-				STpnt = scsi_get_request_dev(&SCpnt->request);
+				STpnt = scsi_get_request_dev(SCpnt->request);
 
 			/* 
 			 * This sets up the scatter-gather table (allocating if
@@ -973,9 +979,11 @@
 					SDpnt->starved = 1;
 					SHpnt->some_device_starved = 1;
 				}
-				SCpnt->request.special = SCpnt;
-				SCpnt->request.flags |= REQ_SPECIAL;
-				_elv_add_request(q, &SCpnt->request, 0, 0);
+				SCpnt->request->special = SCpnt;
+				SCpnt->request->flags |= REQ_SPECIAL;
+				if(blk_rq_tagged(SCpnt->request))
+					blk_queue_end_tag(q, SCpnt->request);
+				_elv_add_request(q, SCpnt->request, 0, 0);
 				break;
 			}
 
@@ -985,7 +993,7 @@
 			if (!STpnt->init_command(SCpnt)) {
 				scsi_release_buffers(SCpnt);
 				SCpnt = __scsi_end_request(SCpnt, 0, 
-							   SCpnt->request.nr_sectors, 0, 0);
+							   SCpnt->request->nr_sectors, 0, 0);
 				if( SCpnt != NULL )
 				{
 					panic("Should not have leftover blocks\n");
diff -Nru a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
--- a/drivers/scsi/scsi_merge.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi_merge.c	Fri Jul  5 16:43:00 2002
@@ -57,7 +57,7 @@
  */
 int scsi_init_io(Scsi_Cmnd *SCpnt)
 {
-	struct request     *req = &SCpnt->request;
+	struct request     *req = SCpnt->request;
 	struct scatterlist *sgpnt;
 	int count, gfp_mask;
 
@@ -74,8 +74,10 @@
 	SCpnt->use_sg = count;
 
 	gfp_mask = GFP_NOIO;
-	if (in_interrupt())
+	if (in_interrupt()) {
 		gfp_mask &= ~__GFP_WAIT;
+		gfp_mask |= __GFP_HIGH;
+	}
 
 	/*
 	 * if sg table allocation fails, requeue request later.
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi_scan.c	Fri Jul  5 16:43:00 2002
@@ -54,6 +54,7 @@
 		char *scsi_result);
 static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
 				struct Scsi_Host *shpnt);
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt);
 
 struct dev_info {
 	const char *vendor;
@@ -288,6 +289,31 @@
 }
 #endif
 
+/* Driverfs file content handlers */
+static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page, 
+	size_t count, loff_t off)
+{
+	struct scsi_device *SDpnt = list_entry(driverfs_dev,
+		struct scsi_device, sdev_driverfs_dev);
+
+	if ((SDpnt->type <= MAX_SCSI_DEVICE_CODE) && 
+		(scsi_device_types[(int)SDpnt->type] != NULL))
+		return off ? 0 : 
+			sprintf(page, "%s\n", 
+				scsi_device_types[(int)SDpnt->type]);
+	else
+		return off ? 0 : sprintf(page, "UNKNOWN\n");
+
+	return 0;
+}
+
+static struct driver_file_entry scsi_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: scsi_device_type_read,
+};
+/* end content handlers */
+
 static void print_inquiry(unsigned char *data)
 {
 	int i;
@@ -786,6 +812,22 @@
 
 	print_inquiry(scsi_result);
 
+	/* interrogate scsi target to provide device identifier */
+	scsi_load_identifier(SDpnt, SRpnt);
+
+	/* create driverfs files */
+	sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
+		SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
+	
+	SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev;
+	SDpnt->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type;
+
+	device_register(&SDpnt->sdev_driverfs_dev); 
+
+	/* Create driverfs file entries */
+	device_create_file(&SDpnt->sdev_driverfs_dev, 
+			&scsi_device_type_file);
+
         sprintf (devname, "host%d/bus%d/target%d/lun%d",
                  SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
         if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
@@ -1305,4 +1347,375 @@
 	}
 	/* haven't found lun0, should send INQUIRY but take easy route */
 	return res;
+}
+
+#define SCSI_UID_DEV_ID  'U'
+#define SCSI_UID_SER_NUM 'S'
+#define SCSI_UID_UNKNOWN 'Z'
+
+unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	evpd_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
+	if (!evpd_page)
+		return NULL;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd) {
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x00;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* check to see if response was truncated */
+	if (evpd_page[3] > 255) {
+		int max_lgth = evpd_page[3] + 4;
+
+		kfree(evpd_page);
+		evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!evpd_page) {
+			kfree(scsi_cmd);
+			return NULL;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x00;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	kfree(scsi_cmd);
+	/* some ill behaved devices return the std inquiry here rather than
+		the evpd data. snoop the data to verify */
+	if (evpd_page[3] > 16) {
+		/* if vend id appears in the evpd page assume evpd is invalid */
+		if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) {
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	return evpd_page;
+}
+
+int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt)
+{
+	unsigned char *id_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int scnt, i, j, idtype;
+	char * id = SDpnt->sdev_driverfs_dev.name;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	id_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); 
+	if (!id_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x83;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+
+	/* check to see if response was truncated */
+	if (id_page[3] > 255) {
+		int max_lgth = id_page[3] + 4;
+
+		kfree(id_page);
+		id_page = kmalloc(max_lgth,
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC)); 
+		if (!id_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x83;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	idtype = 3;
+	while (idtype > 0) {
+		for(scnt = 4; scnt <= id_page[3] + 3; 
+		    scnt += id_page[scnt + 3] + 4) {
+			if ((id_page[scnt + 1] & 0x0f) != idtype) {
+				continue;
+			}
+			if ((id_page[scnt] & 0x0f) == 2) {  
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if (id_page[i] > 0x20) {
+						if (j == DEVICE_NAME_SIZE) {
+							memset(id, 0, 
+							    DEVICE_NAME_SIZE);
+							break;
+						}
+						id[j++] = id_page[i];
+					}
+				}
+			} else if ((id_page[scnt] & 0x0f) == 1) {
+				static const char hex_str[]="0123456789abcdef";
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if ((j + 1) == DEVICE_NAME_SIZE) {
+						memset(id, 0, DEVICE_NAME_SIZE);
+						break;
+					}
+					id[j++] = hex_str[(id_page[i] & 0xf0) >>
+								4];
+					id[j++] = hex_str[id_page[i] & 0x0f];
+				}
+			}
+			if (id[1] != 0) goto leave;
+		}
+		idtype--;
+	}
+ leave:
+	kfree(id_page);
+	if (id[1] != 0) {
+		id[0] = SCSI_UID_DEV_ID;
+		return 1;
+	}
+	return 0;
+}
+
+int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *serialnumber_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+	int i, j;
+
+	serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+	if (!serialnumber_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else	
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x80;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+	/* check to see if response was truncated */
+	if (serialnumber_page[3] > 255) {
+		int max_lgth = serialnumber_page[3] + 4;
+
+		kfree(serialnumber_page);
+		serialnumber_page = kmalloc(max_lgth, 
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!serialnumber_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x80;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, 
+				(void *) serialnumber_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
+	for(i = 0, j = 1; i < serialnumber_page[3]; i++) {
+		if (serialnumber_page[4 + i] > 0x20)
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				serialnumber_page[4 + i];
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i];
+		}
+	}
+	kfree(serialnumber_page);
+	return 1;
+ leave:
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	kfree(serialnumber_page);
+	return 0;
+}
+
+int scsi_get_default_name(Scsi_Device *SDpnt)
+{
+	int i, j;
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
+	for(i = 0, j = 1; i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->vendor[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); 
+	    i < 16; i++) {
+		if (SDpnt->model[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->model[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) {
+		if (SDpnt->rev[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i];
+		}
+	}	
+	return 1;
+}
+
+
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	int cnt;
+
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	evpd_page = scsi_get_evpd_page(SDpnt, SRpnt);
+	if (!evpd_page) {
+		/* try to obtain serial number anyway */
+		if (!scsi_get_serialnumber(SDpnt, SRpnt))
+			goto leave;
+		goto leave;
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x83) {
+			if (scsi_get_deviceid(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x80) {
+			if (scsi_get_serialnumber(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+leave:
+	if (SDpnt->sdev_driverfs_dev.name[0] == 0)
+		scsi_get_default_name(SDpnt);
+
+	if (evpd_page) kfree(evpd_page);
+	return;
 }
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/scsi_syms.c	Fri Jul  5 16:43:00 2002
@@ -101,3 +101,8 @@
 extern int scsi_delete_timer(Scsi_Cmnd *);
 EXPORT_SYMBOL(scsi_add_timer);
 EXPORT_SYMBOL(scsi_delete_timer);
+
+/*
+ * driverfs support for determining driver types
+ */
+EXPORT_SYMBOL(scsi_driverfs_bus_type);
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/sd.c	Fri Jul  5 16:42:59 2002
@@ -129,6 +129,7 @@
 
 static Scsi_Disk * sd_get_sdisk(int index);
 
+extern void driverfs_remove_partitions(struct gendisk *hd, int minor);
 
 #if defined(CONFIG_PPC32)
 /**
@@ -327,13 +328,13 @@
 	/*
 	 * don't support specials for nwo
 	 */
-	if (!(SCpnt->request.flags & REQ_CMD))
+	if (!(SCpnt->request->flags & REQ_CMD))
 		return 0;
 
-	part_nr = SD_PARTITION(SCpnt->request.rq_dev);
-	dsk_nr = DEVICE_NR(SCpnt->request.rq_dev);
+	part_nr = SD_PARTITION(SCpnt->request->rq_dev);
+	dsk_nr = DEVICE_NR(SCpnt->request->rq_dev);
 
-	block = SCpnt->request.sector;
+	block = SCpnt->request->sector;
 	this_count = SCpnt->request_bufflen >> 9;
 
 	SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%d, "
@@ -344,9 +345,9 @@
 	/* >>>>> this change is not in the lk 2.5 series */
 	if (part_nr >= (sd_template.dev_max << 4) || (part_nr & 0xf) ||
 	    !sdp || !sdp->online ||
- 	    block + SCpnt->request.nr_sectors > sd[part_nr].nr_sects) {
+ 	    block + SCpnt->request->nr_sectors > sd[part_nr].nr_sects) {
 		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", 
-				 SCpnt->request.nr_sectors));
+				 SCpnt->request->nr_sectors));
 		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
@@ -375,7 +376,7 @@
 	 * for this.
 	 */
 	if (sdp->sector_size == 1024) {
-		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
+		if ((block & 1) || (SCpnt->request->nr_sectors & 1)) {
 			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
@@ -384,7 +385,7 @@
 		}
 	}
 	if (sdp->sector_size == 2048) {
-		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
+		if ((block & 3) || (SCpnt->request->nr_sectors & 3)) {
 			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
@@ -393,7 +394,7 @@
 		}
 	}
 	if (sdp->sector_size == 4096) {
-		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
+		if ((block & 7) || (SCpnt->request->nr_sectors & 7)) {
 			printk(KERN_ERR "sd: Bad block number requested");
 			return 0;
 		} else {
@@ -401,25 +402,25 @@
 			this_count = this_count >> 3;
 		}
 	}
-	if (rq_data_dir(&SCpnt->request) == WRITE) {
+	if (rq_data_dir(SCpnt->request) == WRITE) {
 		if (!sdp->writeable) {
 			return 0;
 		}
 		SCpnt->cmnd[0] = WRITE_6;
 		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
-	} else if (rq_data_dir(&SCpnt->request) == READ) {
+	} else if (rq_data_dir(SCpnt->request) == READ) {
 		SCpnt->cmnd[0] = READ_6;
 		SCpnt->sc_data_direction = SCSI_DATA_READ;
 	} else {
 		printk(KERN_ERR "sd: Unknown command %lx\n", 
-		       SCpnt->request.flags);
-/* overkill 	panic("Unknown sd command %lx\n", SCpnt->request.flags); */
+		       SCpnt->request->flags);
+/* overkill 	panic("Unknown sd command %lx\n", SCpnt->request->flags); */
 		return 0;
 	}
 
 	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", 
-		nbuff, (rq_data_dir(&SCpnt->request) == WRITE) ? 
-		"writing" : "reading", this_count, SCpnt->request.nr_sectors));
+		nbuff, (rq_data_dir(SCpnt->request) == WRITE) ? 
+		"writing" : "reading", this_count, SCpnt->request->nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
 			 ((SCpnt->lun << 5) & 0xe0) : 0;
@@ -664,7 +665,7 @@
 #if CONFIG_SCSI_LOGGING
 	char nbuff[6];
 
-	SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request.rq_dev), 
+	SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request->rq_dev), 
 			    nbuff));
 	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
 				      nbuff, result));
@@ -690,8 +691,8 @@
 			(SCpnt->sense_buffer[4] << 16) |
 			(SCpnt->sense_buffer[5] << 8) |
 			SCpnt->sense_buffer[6];
-			if (SCpnt->request.bio != NULL)
-				block_sectors = bio_sectors(SCpnt->request.bio);
+			if (SCpnt->request->bio != NULL)
+				block_sectors = bio_sectors(SCpnt->request->bio);
 			switch (SCpnt->device->sector_size) {
 			case 1024:
 				error_sector <<= 1;
@@ -716,7 +717,7 @@
 			}
 
 			error_sector &= ~(block_sectors - 1);
-			good_sectors = error_sector - SCpnt->request.sector;
+			good_sectors = error_sector - SCpnt->request->sector;
 			if (good_sectors < 0 || good_sectors >= this_count)
 				good_sectors = 0;
 			break;
@@ -1277,12 +1278,15 @@
 
 		init_mem_lth(sd_gendisks[k].de_arr, N);
 		init_mem_lth(sd_gendisks[k].flags, N);
+		init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
-		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
+		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags ||
+				!sd_gendisks[k].driverfs_dev_arr)
 			goto cleanup_gendisks;
 
 		zero_mem_lth(sd_gendisks[k].de_arr, N);
 		zero_mem_lth(sd_gendisks[k].flags, N);
+		zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
 		sd_gendisks[k].major = SD_MAJOR(k);
 		sd_gendisks[k].major_name = "sd";
@@ -1291,7 +1295,6 @@
 		sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
 		sd_gendisks[k].nr_real = 0;
 	}
-
 	return 0;
 
 #undef init_mem_lth
@@ -1302,6 +1305,7 @@
 	for (k = 0; k < N_USED_SD_MAJORS; k++) {
 		vfree(sd_gendisks[k].de_arr);
 		vfree(sd_gendisks[k].flags);
+		vfree(sd_gendisks[k].driverfs_dev_arr);
 	}
 cleanup_mem:
 	vfree(sd_gendisks);
@@ -1436,6 +1440,8 @@
 	SD_GENDISK(dsk_nr).nr_real++;
         devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
         SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
+        SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] = 
+		&sdp->sdev_driverfs_dev;
         if (sdp->removable)
 		SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
 	sd_dskname(dsk_nr, diskname);
@@ -1535,6 +1541,8 @@
 	max_p = 1 << sd_gendisk.minor_shift;
 	start = dsk_nr << sd_gendisk.minor_shift;
 	dev = MKDEV_SD_PARTITION(start);
+	driverfs_remove_partitions(&SD_GENDISK (dsk_nr), 
+					SD_MINOR_NUMBER (start));
 	wipe_partitions(dev);
 	for (j = max_p - 1; j >= 0; j--)
 		sd_sizes[start + j] = 0;
@@ -1556,9 +1564,16 @@
  **/
 static int __init init_sd(void)
 {
+	int rc;
 	SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
 	sd_template.module = THIS_MODULE;
-	return scsi_register_device(&sd_template);
+	rc = scsi_register_device(&sd_template);
+	if (!rc) {
+		sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
+		sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sd_template.scsi_driverfs_driver);
+	}
+	return rc;
 }
 
 /**
@@ -1591,6 +1606,7 @@
 	sd_template.dev_max = 0;
 	if (sd_gendisks != &sd_gendisk)
 		vfree(sd_gendisks);
+	remove_driver(&sd_template.scsi_driverfs_driver);
 }
 
 static Scsi_Disk * sd_get_sdisk(int index)
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/sg.c	Fri Jul  5 16:43:00 2002
@@ -194,6 +194,7 @@
     volatile char detached;  /* 0->attached, 1->detached pending removal */
     volatile char exclude;   /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+    struct device sg_driverfs_dev;
 } Sg_device; /* 36 bytes long on i386 */
 
 
@@ -695,7 +696,7 @@
 
     srp->my_cmdp = SRpnt;
     q = &SRpnt->sr_device->request_queue;
-    SRpnt->sr_request.rq_dev = sdp->i_rdev;
+    SRpnt->sr_request->rq_dev = sdp->i_rdev;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
     if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -1222,7 +1223,7 @@
     SRpnt->sr_bufflen = 0;
     SRpnt->sr_buffer = NULL;
     SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
+    SRpnt->sr_request->rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
 
     srp->my_cmdp = NULL;
     srp->done = 1;
@@ -1370,6 +1371,29 @@
 __setup("sg_def_reserved_size=", sg_def_reserved_size_setup);
 #endif
 
+/* Driverfs file support */
+static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off)
+{
+	Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
+	return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value);
+}
+static struct driver_file_entry sg_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sg_device_kdev_read,
+};
+
+static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sg_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sg_device_type_read,
+};
 
 static int sg_attach(Scsi_Device * scsidp)
 {
@@ -1428,6 +1452,18 @@
     sdp->detached = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
     sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
+
+    memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device));
+    sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
+	    scsidp->sdev_driverfs_dev.bus_id);
+    sprintf(sdp->sg_driverfs_dev.name, "%sgeneric", 
+	    scsidp->sdev_driverfs_dev.name);
+    sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
+    sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
+    device_register(&sdp->sg_driverfs_dev);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_type_file);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_kdev_file);
+
     sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
                              SCSI_GENERIC_MAJOR, k,
                              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
@@ -1496,6 +1532,9 @@
             }
 	    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
 	    devfs_unregister (sdp->de);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_type_file.name);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_kdev_file.name);
+	    put_device(&sdp->sg_driverfs_dev);
 	    sdp->de = NULL;
 	    if (NULL == sdp->headfp) {
 		kfree((char *)sdp);
@@ -1505,6 +1544,7 @@
         else { /* nothing active, simple case */
             SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 	    devfs_unregister (sdp->de);
+	    put_device(&sdp->sg_driverfs_dev);
 	    kfree((char *)sdp);
 	    sg_dev_arr[k] = NULL;
         }
@@ -1529,9 +1569,16 @@
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
 
 static int __init init_sg(void) {
+    int rc;
     if (def_reserved_size >= 0)
 	sg_big_buff = def_reserved_size;
-    return scsi_register_device(&sg_template);
+    rc = scsi_register_device(&sg_template);
+    if (!rc) {
+	sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag;
+	sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+	driver_register(&sg_template.scsi_driverfs_driver);
+    }
+    return rc; 
 }
 
 static void __exit exit_sg( void)
@@ -1546,6 +1593,7 @@
         sg_dev_arr = NULL;
     }
     sg_template.dev_max = 0;
+    remove_driver(&sg_template.scsi_driverfs_driver);
 }
 
 
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/sr.c	Fri Jul  5 16:42:59 2002
@@ -197,11 +197,11 @@
 	int this_count = SCpnt->bufflen >> 9;
 	int good_sectors = (result == 0 ? this_count : 0);
 	int block_sectors = 0;
-	int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
+	int device_nr = DEVICE_NR(SCpnt->request->rq_dev);
 	Scsi_CD *SCp = &scsi_CDs[device_nr];
 
 #ifdef DEBUG
-	printk("sr.c done: %x %p\n", result, SCpnt->request.bh->b_data);
+	printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data);
 #endif
 	/*
 	   Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success.
@@ -219,14 +219,14 @@
 		(SCpnt->sense_buffer[4] << 16) |
 		(SCpnt->sense_buffer[5] << 8) |
 		SCpnt->sense_buffer[6];
-		if (SCpnt->request.bio != NULL)
-			block_sectors = bio_sectors(SCpnt->request.bio);
+		if (SCpnt->request->bio != NULL)
+			block_sectors = bio_sectors(SCpnt->request->bio);
 		if (block_sectors < 4)
 			block_sectors = 4;
 		if (SCp->device->sector_size == 2048)
 			error_sector <<= 2;
 		error_sector &= ~(block_sectors - 1);
-		good_sectors = error_sector - SCpnt->request.sector;
+		good_sectors = error_sector - SCpnt->request->sector;
 		if (good_sectors < 0 || good_sectors >= this_count)
 			good_sectors = 0;
 		/*
@@ -266,14 +266,14 @@
 	int dev, devm, block=0, this_count, s_size;
 	Scsi_CD *SCp;
 
-	devm = minor(SCpnt->request.rq_dev);
-	dev = DEVICE_NR(SCpnt->request.rq_dev);
+	devm = minor(SCpnt->request->rq_dev);
+	dev = DEVICE_NR(SCpnt->request->rq_dev);
 	SCp = &scsi_CDs[dev];
 
 	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
 
 	if (dev >= sr_template.nr_dev || !SCp->device || !SCp->device->online) {
-		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
+		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request->nr_sectors));
 		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
@@ -286,8 +286,8 @@
 		return 0;
 	}
 
-	if (!(SCpnt->request.flags & REQ_CMD)) {
-		blk_dump_rq_flags(&SCpnt->request, "sr unsup command");
+	if (!(SCpnt->request->flags & REQ_CMD)) {
+		blk_dump_rq_flags(SCpnt->request, "sr unsup command");
 		return 0;
 	}
 
@@ -308,23 +308,23 @@
 		return 0;
 	}
 
-	if (rq_data_dir(&SCpnt->request) == WRITE) {
+	if (rq_data_dir(SCpnt->request) == WRITE) {
 		if (!SCp->device->writeable)
 			return 0;
 		SCpnt->cmnd[0] = WRITE_10;
 		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
-	} else if (rq_data_dir(&SCpnt->request) == READ) {
+	} else if (rq_data_dir(SCpnt->request) == READ) {
 		SCpnt->cmnd[0] = READ_10;
 		SCpnt->sc_data_direction = SCSI_DATA_READ;
 	} else {
-		blk_dump_rq_flags(&SCpnt->request, "Unknown sr command");
+		blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
 		return 0;
 	}
 
 	/*
 	 * request doesn't start on hw block boundary, add scatter pads
 	 */
-	if ((SCpnt->request.sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) {
+	if ((SCpnt->request->sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) {
 		printk("sr: unaligned transfer\n");
 		return 0;
 	}
@@ -334,13 +334,13 @@
 
 	SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
                                    devm,
-		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
-				 this_count, SCpnt->request.nr_sectors));
+		   (rq_data_dir(SCpnt->request) == WRITE) ? "writing" : "reading",
+				 this_count, SCpnt->request->nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
 			 ((SCpnt->lun << 5) & 0xe0) : 0;
 
-	block = SCpnt->request.sector / (s_size >> 9);
+	block = SCpnt->request->sector / (s_size >> 9);
 
 	if (this_count > 0xffff)
 		this_count = 0xffff;
@@ -496,7 +496,7 @@
 		cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
 			 ((SCp->device->lun << 5) & 0xe0) : 0;
 		memset((void *) &cmd[2], 0, 8);
-		SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
+		SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
 		SRpnt->sr_cmd_len = 0;
 
 		memset(buffer, 0, 8);
@@ -522,8 +522,8 @@
 		SCp->needs_sector_size = 1;
 	} else {
 #if 0
-		if (cdrom_get_last_written(mkdev(MAJOR_NR, i),
-					   &scsi_CDs[i].capacity))
+		if (cdrom_get_last_written(&SCp->cdi,
+					   &SCp->capacity))
 #endif
 			SCp->capacity = 1 + ((buffer[0] << 24) |
 						    (buffer[1] << 16) |
@@ -731,6 +731,32 @@
 	return 1;
 }
 
+/* Driverfs file support */
+static ssize_t sr_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry sr_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sr_device_kdev_read,
+};
+
+static ssize_t sr_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sr_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sr_device_type_read,
+};
+
+
 void sr_finish()
 {
 	int i;
@@ -776,6 +802,20 @@
 
 		sprintf(name, "sr%d", i);
 		strcpy(SCp->cdi.name, name);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
+			SCp->device->sdev_driverfs_dev.bus_id);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.name, "%scdrom",
+			SCp->device->sdev_driverfs_dev.name);
+		SCp->cdi.cdrom_driverfs_dev.parent = 
+			&SCp->device->sdev_driverfs_dev;
+		SCp->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
+		SCp->cdi.cdrom_driverfs_dev.driver_data = 
+			(void *)__mkdev(MAJOR_NR, i);
+		device_register(&SCp->cdi.cdrom_driverfs_dev);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_type_file);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_kdev_file);
                 SCp->cdi.de = devfs_register(SCp->device->de, "cd",
                                     DEVFS_FL_DEFAULT, MAJOR_NR, i,
                                     S_IFBLK | S_IRUGO | S_IWUGO,
@@ -816,7 +856,14 @@
 
 static int __init init_sr(void)
 {
-	return scsi_register_device(&sr_template);
+	int rc;
+	rc = scsi_register_device(&sr_template);
+	if (!rc) {
+		sr_template.scsi_driverfs_driver.name = (char *)sr_template.tag;
+		sr_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sr_template.scsi_driverfs_driver);
+	}
+	return rc;
 }
 
 static void __exit exit_sr(void)
@@ -833,6 +880,7 @@
 	blk_clear(MAJOR_NR);
 
 	sr_template.dev_max = 0;
+	remove_driver(&sr_template.scsi_driverfs_driver);
 }
 
 module_init(init_sr);
diff -Nru a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
--- a/drivers/scsi/sr_ioctl.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/sr_ioctl.c	Fri Jul  5 16:43:00 2002
@@ -93,7 +93,7 @@
 	SRpnt->sr_data_direction = readwrite;
 
 	/* use ISA DMA buffer if necessary */
-	SRpnt->sr_request.buffer = buffer;
+	SRpnt->sr_request->buffer = buffer;
 	if (buffer && SRpnt->sr_host->unchecked_isa_dma &&
 	    (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
 		bounce_buffer = (char *) kmalloc(buflength, GFP_DMA);
@@ -112,7 +112,7 @@
 	scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
 		      IOCTL_TIMEOUT, IOCTL_RETRIES);
 
-	req = &SRpnt->sr_request;
+	req = SRpnt->sr_request;
 	if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
 		memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
 		kfree(SRpnt->sr_buffer);
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/scsi/st.c	Fri Jul  5 16:43:00 2002
@@ -229,7 +229,7 @@
 		scode = 0;
 	}
 
-	dev = TAPE_NR(SRpnt->sr_request.rq_dev);
+	dev = TAPE_NR(SRpnt->sr_request->rq_dev);
         DEB(
         if (debugging) {
                 printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
@@ -306,7 +306,7 @@
 	int remainder;
 	Scsi_Tape *STp;
 
-	st_nbr = TAPE_NR(SCpnt->request.rq_dev);
+	st_nbr = TAPE_NR(SCpnt->request->rq_dev);
 	read_lock(&st_dev_arr_lock);
 	STp = scsi_tapes[st_nbr];
 	read_unlock(&st_dev_arr_lock);
@@ -328,11 +328,11 @@
 			(STp->buffer)->midlevel_result = INT_MAX;	/* OK */
 	} else
 		(STp->buffer)->midlevel_result = SCpnt->result;
-	SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
 	(STp->buffer)->last_SRpnt = SCpnt->sc_request;
 	DEB( STp->write_pending = 0; )
 
-	complete(SCpnt->request.waiting);
+	complete(SCpnt->request->waiting);
 }
 
 
@@ -371,16 +371,16 @@
 		bp = (STp->buffer)->b_data;
 	SRpnt->sr_data_direction = direction;
 	SRpnt->sr_cmd_len = 0;
-	SRpnt->sr_request.waiting = &(STp->wait);
-	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
-	SRpnt->sr_request.rq_dev = STp->devt;
+	SRpnt->sr_request->waiting = &(STp->wait);
+	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request->rq_dev = STp->devt;
 
 	scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
 		    st_sleep_done, timeout, retries);
 
 	if (do_wait) {
-		wait_for_completion(SRpnt->sr_request.waiting);
-		SRpnt->sr_request.waiting = NULL;
+		wait_for_completion(SRpnt->sr_request->waiting);
+		SRpnt->sr_request->waiting = NULL;
 		(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
 	}
 	return SRpnt;
@@ -403,7 +403,7 @@
         ) /* end DEB */
 
 	wait_for_completion(&(STp->wait));
-	(STp->buffer)->last_SRpnt->sr_request.waiting = NULL;
+	(STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
 
 	(STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
 	scsi_release_request((STp->buffer)->last_SRpnt);
@@ -3531,6 +3531,31 @@
 
 #endif
 
+/* Driverfs file support */
+static ssize_t st_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry st_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: st_device_kdev_read,
+};
+
+static ssize_t st_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry st_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: st_device_type_read,
+};
+
 
 static struct file_operations st_fops =
 {
@@ -3632,6 +3657,18 @@
 
 	    /*  Rewind entry  */
 	    sprintf (name, "mt%s", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_r[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5));
+	    device_register(&tpnt->driverfs_dev_r[mode]);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], 
+			       &st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], &st_device_kdev_file);
 	    tpnt->de_r[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5),
@@ -3639,6 +3676,19 @@
 				&st_fops, NULL);
 	    /*  No-rewind entry  */
 	    sprintf (name, "mt%sn", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_n[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
+	    device_register(&tpnt->driverfs_dev_n[mode]);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_kdev_file);
 	    tpnt->de_n[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5) + 128,
@@ -3738,8 +3788,18 @@
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 				devfs_unregister (tpnt->de_r[mode]);
 				tpnt->de_r[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_r[mode]);
 				devfs_unregister (tpnt->de_n[mode]);
 				tpnt->de_n[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_n[mode]);
 			}
 			if (tpnt->buffer) {
 				tpnt->buffer->orig_sg_segs = 0;
@@ -3770,8 +3830,16 @@
 		verstr, st_fixed_buffer_size, st_write_threshold,
 		st_max_sg_segs);
 
-	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
-		return scsi_register_device(&st_template);
+	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) {
+		if (scsi_register_device(&st_template) == 0) {
+			st_template.scsi_driverfs_driver.name = 
+				(char *)st_template.tag;
+			st_template.scsi_driverfs_driver.bus = 
+				&scsi_driverfs_bus_type;
+			driver_register(&st_template.scsi_driverfs_driver);
+			return 0;
+		}
+	}
 
 	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
 	return 1;
@@ -3790,6 +3858,7 @@
 		kfree(scsi_tapes);
 	}
 	st_template.dev_max = 0;
+	remove_driver(&st_template.scsi_driverfs_driver);
 	printk(KERN_INFO "st: Unloaded.\n");
 }
 
diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h
--- a/drivers/scsi/st.h	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/st.h	Fri Jul  5 16:42:59 2002
@@ -94,6 +94,8 @@
 	int current_mode;
 	devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
 	devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
+	struct device driverfs_dev_r[ST_NBR_MODES];
+	struct device driverfs_dev_n[ST_NBR_MODES];
 
 	/* Status variables */
 	int partition;
diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
--- a/drivers/scsi/sun3_NCR5380.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/scsi/sun3_NCR5380.c	Fri Jul  5 16:42:56 2002
@@ -1217,7 +1217,7 @@
 	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
 	       NCR5380_read(STATUS_REG));
 
-    if((sun3scsi_dma_finish(hostdata->connected->request.cmd))) {
+    if((sun3scsi_dma_finish(hostdata->connected->request->cmd))) {
 	    printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
 	    printk("please e-mail sammy@oh.verio.com with a description of how this\n");
 	    printk("error was produced.\n");
@@ -2016,9 +2016,9 @@
 		if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
 						  != cmd))
 		{
-			if((cmd->request.cmd == 0) || (cmd->request.cmd == 1)) {
+			if((cmd->request->cmd == 0) || (cmd->request->cmd == 1)) {
 				sun3scsi_dma_setup(d, count,
-						   cmd->request.cmd);
+						   cmd->request->cmd);
 				sun3_dma_setup_done = cmd;
 			}
 		}
@@ -2628,7 +2628,7 @@
 						  != tmp))
 		{
 			sun3scsi_dma_setup(d, count,
-					   tmp->request.cmd);
+					   tmp->request->cmd);
 			sun3_dma_setup_done = tmp;
 		}
 #endif
diff -Nru a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
--- a/drivers/scsi/sun3_scsi.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/scsi/sun3_scsi.c	Fri Jul  5 16:42:56 2002
@@ -518,7 +518,7 @@
 static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
 				    int write_flag)
 {
-	if((cmd->request.cmd == 0) || (cmd->request.cmd == 1))
+	if((cmd->request->cmd == 0) || (cmd->request->cmd == 1))
  		return wanted;
 	else
 		return 0;
diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
--- a/drivers/scsi/u14-34f.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/scsi/u14-34f.c	Fri Jul  5 16:42:59 2002
@@ -1206,7 +1206,7 @@
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type)) {
       HD(j)->cp_stat[i] = READY;
-      flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE);
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
       return 0;
       }
 
@@ -1529,11 +1529,11 @@
 
       if (!(cpp->xdir == DTD_IN)) input_only = FALSE;
 
-      if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector;
-      if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
+      if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector;
+      if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector;
 
-      sl[n] = SCpnt->request.sector;
-      ioseek += SCpnt->request.nr_sectors;
+      sl[n] = SCpnt->request->sector;
+      ioseek += SCpnt->request->nr_sectors;
 
       if (!n) continue;
 
@@ -1561,7 +1561,7 @@
 
    if (!input_only) for (n = 0; n < n_ready; n++) {
       k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
-      ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
+      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
 
       if (!n) continue;
 
@@ -1589,7 +1589,7 @@
                 " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
                 (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
                 SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
-                SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
+                SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
                 YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
                 YESNO(overlap), cpp->xdir);
          }
@@ -1718,7 +1718,7 @@
 
    if (linked_comm && SCpnt->device->queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
-      flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
 
    tstatus = status_byte(spp->target_status);
 
diff -Nru a/drivers/tc/Makefile b/drivers/tc/Makefile
--- a/drivers/tc/Makefile	Fri Jul  5 16:42:59 2002
+++ b/drivers/tc/Makefile	Fri Jul  5 16:42:59 2002
@@ -15,5 +15,16 @@
 
 include $(TOPDIR)/Rules.make
 
-$(obj)/lk201-map.c: $(src)/lk201-map.map
+$(obj)/lk201-map.o: $(obj)/lk201-map.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/lk201-map.c: $(obj)/%.c: $(src)/%.map
 	loadkeys --mktable $< > $@
+
+endif
diff -Nru a/drivers/tc/lk201-map.c_shipped b/drivers/tc/lk201-map.c_shipped
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/tc/lk201-map.c_shipped	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,265 @@
+
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf11b,
+	0xf11c,	0xf110,	0xf111,	0xf112,	0xf113,	0xf060,	0xf031,	0xf032,
+	0xf033,	0xf034,	0xf035,	0xf036,	0xf037,	0xf038,	0xf039,	0xf030,
+	0xf02d,	0xf03d,	0xf07f,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf009,	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,
+	0xfb79,	0xfb75,	0xfb69,	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf201,
+	0xf117,	0xf118,	0xf119,	0xf307,	0xf308,	0xf309,	0xf30b,	0xf702,
+	0xf207,	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,
+	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf05c,	0xf603,	0xf304,	0xf305,
+	0xf306,	0xf200,	0xf700,	0xf03e,	0xfb7a,	0xfb78,	0xfb63,	0xfb76,
+	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf301,	0xf302,	0xf303,	0xf30e,	0xf200,	0xf703,
+	0xf020,	0xf200,	0xf200,	0xf300,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short shift_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf203,
+	0xf11c,	0xf110,	0xf111,	0xf112,	0xf113,	0xf07e,	0xf021,	0xf040,
+	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,	0xf02a,	0xf028,	0xf029,
+	0xf05f,	0xf02b,	0xf07f,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf009,	0xfb51,	0xfb57,	0xfb45,	0xfb52,	0xfb54,
+	0xfb59,	0xfb55,	0xfb49,	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf201,
+	0xf117,	0xf20b,	0xf20a,	0xf307,	0xf308,	0xf309,	0xf30b,	0xf702,
+	0xf207,	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb47,	0xfb48,	0xfb4a,
+	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf07c,	0xf603,	0xf304,	0xf305,
+	0xf306,	0xf200,	0xf700,	0xf03c,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
+	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf301,	0xf302,	0xf303,	0xf30e,	0xf200,	0xf703,
+	0xf020,	0xf200,	0xf200,	0xf300,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf202,
+	0xf11c,	0xf110,	0xf111,	0xf112,	0xf113,	0xf200,	0xf200,	0xf040,
+	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,	0xf05b,	0xf05d,	0xf07d,
+	0xf05c,	0xf200,	0xf200,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xfb71,	0xfb77,	0xf918,	0xfb72,	0xfb74,
+	0xfb79,	0xfb75,	0xfb69,	0xfb6f,	0xfb70,	0xf200,	0xf07e,	0xf201,
+	0xf117,	0xf118,	0xf119,	0xf911,	0xf912,	0xf913,	0xf30b,	0xf702,
+	0xf207,	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb67,	0xfb68,	0xfb6a,
+	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf200,	0xf603,	0xf90e,	0xf90f,
+	0xf910,	0xf200,	0xf700,	0xf200,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
+	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf90b,	0xf90c,	0xf90d,	0xf30e,	0xf200,	0xf703,
+	0xf200,	0xf200,	0xf200,	0xf90a,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf204,
+	0xf11c,	0xf110,	0xf111,	0xf112,	0xf113,	0xf81b,	0xf200,	0xf000,
+	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,	0xf07f,	0xf200,	0xf200,
+	0xf01f,	0xf200,	0xf008,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,
+	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,	0xf01b,	0xf01d,	0xf201,
+	0xf117,	0xf118,	0xf119,	0xf307,	0xf308,	0xf309,	0xf30b,	0xf702,
+	0xf207,	0xf001,	0xf013,	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,
+	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf01c,	0xf603,	0xf304,	0xf305,
+	0xf306,	0xf200,	0xf700,	0xf200,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf301,	0xf302,	0xf303,	0xf30e,	0xf200,	0xf703,
+	0xf000,	0xf200,	0xf200,	0xf300,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
+	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf200,
+	0xf11c,	0xf110,	0xf111,	0xf112,	0xf113,	0xf200,	0xf200,	0xf000,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf01f,	0xf200,	0xf200,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,
+	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf201,
+	0xf117,	0xf118,	0xf119,	0xf307,	0xf308,	0xf309,	0xf30b,	0xf702,
+	0xf207,	0xf001,	0xf013,	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,
+	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf200,	0xf603,	0xf304,	0xf305,
+	0xf306,	0xf200,	0xf700,	0xf200,	0xf01a,	0xf018,	0xf003,	0xf016,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf301,	0xf302,	0xf303,	0xf30e,	0xf200,	0xf703,
+	0xf200,	0xf200,	0xf200,	0xf300,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short alt_map[NR_KEYS] = {
+	0xf200,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
+	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf50c,	0xf50d,	0xf200,
+	0xf11c,	0xf510,	0xf511,	0xf512,	0xf513,	0xf01b,	0xf831,	0xf832,
+	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,	0xf838,	0xf839,	0xf830,
+	0xf82d,	0xf83d,	0xf87f,	0xf114,	0xf115,	0xf116,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf809,	0xf871,	0xf877,	0xf865,	0xf872,	0xf874,
+	0xf879,	0xf875,	0xf869,	0xf86f,	0xf870,	0xf85b,	0xf85d,	0xf80d,
+	0xf117,	0xf118,	0xf119,	0xf907,	0xf908,	0xf909,	0xf30b,	0xf702,
+	0xf207,	0xf861,	0xf873,	0xf864,	0xf866,	0xf867,	0xf868,	0xf86a,
+	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf85c,	0xf603,	0xf904,	0xf905,
+	0xf906,	0xf200,	0xf700,	0xf200,	0xf87a,	0xf878,	0xf863,	0xf876,
+	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf200,	0xf210,
+	0xf600,	0xf211,	0xf901,	0xf902,	0xf903,	0xf30e,	0xf200,	0xf703,
+	0xf820,	0xf200,	0xf200,	0xf900,	0xf310,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+static u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
+	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf50c,	0xf50d,	0xf200,
+	0xf11c,	0xf510,	0xf511,	0xf512,	0xf513,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf114,	0xf115,	0xf20c,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf811,	0xf817,	0xf805,	0xf812,	0xf814,
+	0xf819,	0xf815,	0xf809,	0xf80f,	0xf810,	0xf200,	0xf200,	0xf201,
+	0xf117,	0xf118,	0xf119,	0xf307,	0xf308,	0xf309,	0xf30b,	0xf702,
+	0xf207,	0xf801,	0xf813,	0xf804,	0xf806,	0xf807,	0xf808,	0xf80a,
+	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf200,	0xf603,	0xf304,	0xf305,
+	0xf306,	0xf200,	0xf700,	0xf200,	0xf81a,	0xf818,	0xf803,	0xf816,
+	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf601,
+	0xf600,	0xf602,	0xf301,	0xf302,	0xf303,	0xf30e,	0xf200,	0xf703,
+	0xf200,	0xf200,	0xf200,	0xf300,	0xf20c,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', 'À'},	{'`', 'a', 'à'},
+	{'\'', 'A', 'Á'},	{'\'', 'a', 'á'},
+	{'^', 'A', 'Â'},	{'^', 'a', 'â'},
+	{'~', 'A', 'Ã'},	{'~', 'a', 'ã'},
+	{'"', 'A', 'Ä'},	{'"', 'a', 'ä'},
+	{'O', 'A', 'Å'},	{'o', 'a', 'å'},
+	{'0', 'A', 'Å'},	{'0', 'a', 'å'},
+	{'A', 'A', 'Å'},	{'a', 'a', 'å'},
+	{'A', 'E', 'Æ'},	{'a', 'e', 'æ'},
+	{',', 'C', 'Ç'},	{',', 'c', 'ç'},
+	{'`', 'E', 'È'},	{'`', 'e', 'è'},
+	{'\'', 'E', 'É'},	{'\'', 'e', 'é'},
+	{'^', 'E', 'Ê'},	{'^', 'e', 'ê'},
+	{'"', 'E', 'Ë'},	{'"', 'e', 'ë'},
+	{'`', 'I', 'Ì'},	{'`', 'i', 'ì'},
+	{'\'', 'I', 'Í'},	{'\'', 'i', 'í'},
+	{'^', 'I', 'Î'},	{'^', 'i', 'î'},
+	{'"', 'I', 'Ï'},	{'"', 'i', 'ï'},
+	{'-', 'D', 'Ð'},	{'-', 'd', 'ð'},
+	{'~', 'N', 'Ñ'},	{'~', 'n', 'ñ'},
+	{'`', 'O', 'Ò'},	{'`', 'o', 'ò'},
+	{'\'', 'O', 'Ó'},	{'\'', 'o', 'ó'},
+	{'^', 'O', 'Ô'},	{'^', 'o', 'ô'},
+	{'~', 'O', 'Õ'},	{'~', 'o', 'õ'},
+	{'"', 'O', 'Ö'},	{'"', 'o', 'ö'},
+	{'/', 'O', 'Ø'},	{'/', 'o', 'ø'},
+	{'`', 'U', 'Ù'},	{'`', 'u', 'ù'},
+	{'\'', 'U', 'Ú'},	{'\'', 'u', 'ú'},
+	{'^', 'U', 'Û'},	{'^', 'u', 'û'},
+	{'"', 'U', 'Ü'},	{'"', 'u', 'ü'},
+	{'\'', 'Y', 'Ý'},	{'\'', 'y', 'ý'},
+	{'T', 'H', 'Þ'},	{'t', 'h', 'þ'},
+	{'s', 's', 'ß'},	{'"', 'y', 'ÿ'},
+	{'s', 'z', 'ß'},	{'i', 'j', 'ÿ'},
+};
+
+unsigned int accent_table_size = 68;
diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/class/bluetty.c	Fri Jul  5 16:42:59 2002
@@ -1151,7 +1151,8 @@
 
 	endpoint = bulk_out_endpoint[0];
 	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-	
+	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
+
 	/* create our write urb pool */ 
 	for (i = 0; i < NUM_BULK_URBS; ++i) {
 		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -1166,8 +1167,6 @@
 		}
 		bluetooth->write_urb_pool[i] = urb;
 	}
-	
-	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
 
 	endpoint = interrupt_in_endpoint[0];
 	bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
diff -Nru a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
--- a/drivers/usb/class/printer.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/class/printer.c	Fri Jul  5 16:42:59 2002
@@ -372,7 +372,7 @@
 {
 	devfs_unregister (usblp->devfs);
 	usblp_table [usblp->minor] = NULL;
-	usb_deregister_dev (&usblp_driver, 1, usblp->minor);
+	usb_deregister_dev (1, usblp->minor);
 	info("usblp%d: removed", usblp->minor);
 
 	kfree (usblp->writeurb->transfer_buffer);
@@ -812,20 +812,10 @@
 	init_waitqueue_head(&usblp->wait);
 	usblp->ifnum = ifnum;
 
-	retval = usb_register_dev(&usblp_driver, 1, &usblp->minor);
+	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
 	if (retval) {
-		if (retval != -ENODEV) {
-			err("Not able to get a minor for this device.");
-			goto abort;
-		}
-		/* Look for a free usblp_table entry on our own. */
-		while (usblp_table[usblp->minor]) {
-			usblp->minor++;
-			if (usblp->minor >= USBLP_MINORS) {
-				err("no more free usblp devices");
-				goto abort;
-			}
-		}
+		err("Not able to get a minor for this device.");
+		goto abort;
 	}
 
 	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
@@ -901,7 +891,7 @@
 	return usblp;
 
 abort_minor:
-	usb_deregister_dev (&usblp_driver, 1, usblp->minor);
+	usb_deregister_dev (1, usblp->minor);
 abort:
 	if (usblp) {
 		usb_free_urb(usblp->writeurb);
@@ -1111,9 +1101,6 @@
 	name:		"usblp",
 	probe:		usblp_probe,
 	disconnect:	usblp_disconnect,
-	fops:		&usblp_fops,
-	minor:		USBLP_MINOR_BASE,
-	num_minors:	USBLP_MINORS,
 	id_table:	usblp_ids,
 };
 
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/core/Makefile	Fri Jul  5 16:43:00 2002
@@ -2,17 +2,17 @@
 # Makefile for USB Core files and filesystem
 #
 
-export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o config.o
+export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o config.o file.o
 
 usbcore-objs	:= usb.o usb-debug.o hub.o hcd.o urb.o message.o \
-			config.o
+			config.o file.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
 endif
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
-	usbcore-objs	+= devio.o inode.o drivers.o devices.o
+	usbcore-objs	+= devio.o inode.o devices.o
 endif
 
 obj-$(CONFIG_USB)	+= usbcore.o
diff -Nru a/drivers/usb/core/file.c b/drivers/usb/core/file.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/file.c	Fri Jul  5 16:43:00 2002
@@ -0,0 +1,182 @@
+/*
+ * drivers/usb/file.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
+ 	more docs, etc)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ *     (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
+EXPORT_SYMBOL(usb_devfs_handle);
+
+#define MAX_USB_MINORS	256
+static struct file_operations *usb_minors[MAX_USB_MINORS];
+static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
+
+static int usb_open(struct inode * inode, struct file * file)
+{
+	int minor = minor(inode->i_rdev);
+	struct file_operations *c;
+	int err = -ENODEV;
+	struct file_operations *old_fops, *new_fops = NULL;
+
+	spin_lock (&minor_lock);
+	c = usb_minors[minor];
+	spin_unlock (&minor_lock);
+
+	if (!c || !(new_fops = fops_get(c)))
+		return err;
+	old_fops = file->f_op;
+	file->f_op = new_fops;
+	/* Curiouser and curiouser... NULL ->open() as "no device" ? */
+	if (file->f_op->open)
+		err = file->f_op->open(inode,file);
+	if (err) {
+		fops_put(file->f_op);
+		file->f_op = fops_get(old_fops);
+	}
+	fops_put(old_fops);
+	return err;
+}
+
+static struct file_operations usb_fops = {
+	owner:		THIS_MODULE,
+	open:		usb_open,
+};
+
+int usb_major_init(void)
+{
+	if (devfs_register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
+		err("unable to get major %d for usb devices", USB_MAJOR);
+		return -EBUSY;
+	}
+
+	usb_devfs_handle = devfs_mk_dir(NULL, "usb", NULL);
+
+	return 0;
+}
+
+void usb_major_cleanup(void)
+{
+	devfs_unregister(usb_devfs_handle);
+	devfs_unregister_chrdev(USB_MAJOR, "usb");
+}
+
+/**
+ * usb_register_dev - register a USB device, and ask for a minor number
+ * @fops: the file operations for this USB device
+ * @minor: the requested starting minor for this device.
+ * @num_minors: number of minor numbers requested for this device
+ * @start_minor: place to put the new starting minor number
+ *
+ * This should be called by all USB drivers that use the USB major number.
+ * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
+ * dynamically allocated out of the list of available ones.  If it is not
+ * enabled, the minor number will be based on the next available free minor,
+ * starting at the requested @minor.
+ *
+ * usb_deregister_dev() must be called when the driver is done with
+ * the minor numbers given out by this function.
+ *
+ * Returns -EINVAL if something bad happens with trying to register a
+ * device, and 0 on success, alone with a value that the driver should
+ * use in start_minor.
+ */
+int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor)
+{
+	int i;
+	int j;
+	int good_spot;
+	int retval = -EINVAL;
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+	/* 
+	 * We don't care what the device tries to start at, we want to start
+	 * at zero to pack the devices into the smallest available space with
+	 * no holes in the minor range.
+	 */
+	minor = 0;
+#endif
+
+	dbg ("asking for %d minors, starting at %d", num_minors, minor);
+
+	if (fops == NULL)
+		goto exit;
+
+	*start_minor = 0; 
+	spin_lock (&minor_lock);
+	for (i = minor; i < MAX_USB_MINORS; ++i) {
+		if (usb_minors[i])
+			continue;
+
+		good_spot = 1;
+		for (j = 1; j <= num_minors-1; ++j)
+			if (usb_minors[i+j]) {
+				good_spot = 0;
+				break;
+			}
+		if (good_spot == 0)
+			continue;
+
+		*start_minor = i;
+		dbg("found a minor chunk free, starting at %d", i);
+		for (i = *start_minor; i < (*start_minor + num_minors); ++i)
+			usb_minors[i] = fops;
+
+		retval = 0;
+		goto exit;
+	}
+exit:
+	spin_unlock (&minor_lock);
+	return retval;
+}
+EXPORT_SYMBOL(usb_register_dev);
+
+/**
+ * usb_deregister_dev - deregister a USB device's dynamic minor.
+ * @num_minors: number of minor numbers to put back.
+ * @start_minor: the starting minor number
+ *
+ * Used in conjunction with usb_register_dev().  This function is called
+ * when the USB driver is finished with the minor numbers gotten from a
+ * call to usb_register_dev() (usually when the device is disconnected
+ * from the system.)
+ * 
+ * This should be called by all drivers that use the USB major number.
+ */
+void usb_deregister_dev (int num_minors, int start_minor)
+{
+	int i;
+
+	dbg ("removing %d minors starting at %d", num_minors, start_minor);
+
+	spin_lock (&minor_lock);
+	for (i = start_minor; i < (start_minor + num_minors); ++i)
+		usb_minors[i] = NULL;
+	spin_unlock (&minor_lock);
+}
+EXPORT_SYMBOL(usb_deregister_dev);
+
+
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/usb/core/inode.c	Fri Jul  5 16:42:56 2002
@@ -48,7 +48,6 @@
 static int mount_count;	/* = 0 */
 
 static struct dentry *devices_dentry;
-static struct dentry *drivers_dentry;
 static int num_buses;	/* = 0 */
 
 static uid_t devuid;	/* = 0 */
@@ -548,16 +547,6 @@
 		return -ENODEV;
 	}
 
-	drivers_dentry = fs_create_file ("drivers",
-					 listmode | S_IFREG,
-					 NULL, NULL,
-					 &usbdevfs_drivers_fops,
-					 listuid, listgid);
-	if (drivers_dentry == NULL) {
-		err ("Unable to create drivers usbfs file");
-		return -ENODEV;
-	}
-
 	return 0;
 }
 
@@ -565,10 +554,7 @@
 {
 	if (devices_dentry)
 		fs_remove_file (devices_dentry);
-	if (drivers_dentry)
-		fs_remove_file (drivers_dentry);
 	devices_dentry = NULL;
-	drivers_dentry = NULL;
 	remove_mount();
 }
 
@@ -577,11 +563,6 @@
 	struct inode *inode;
 
 	if (devices_dentry) {
-		inode = devices_dentry->d_inode;
-		if (inode)
-			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	}
-	if (drivers_dentry) {
 		inode = devices_dentry->d_inode;
 		if (inode)
 			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/core/usb.c	Fri Jul  5 16:43:00 2002
@@ -30,7 +30,6 @@
 #include <linux/interrupt.h>  /* for in_interrupt() */
 #include <linux/kmod.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 
@@ -45,6 +44,8 @@
 
 extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
+extern int usb_major_init(void);
+extern void usb_major_cleanup(void);
 
 /*
  * Prototypes for the device driver probing/loading functions
@@ -58,75 +59,23 @@
  */
 LIST_HEAD(usb_driver_list);
 
-devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
-
-#define MAX_USB_MINORS	256
-static struct usb_driver *usb_minors[MAX_USB_MINORS];
-static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
-
-static int usb_register_minors (struct usb_driver *driver, int num_minors, int start_minor)
-{
-	int i;
-
-	dbg("registering %d minors, starting at %d", num_minors, start_minor);
-
-	if (start_minor + num_minors >= MAX_USB_MINORS)
-		return -EINVAL;
-
-	spin_lock (&minor_lock);
-	for (i = start_minor; i < (start_minor + num_minors); ++i)
-		if (usb_minors[i]) {
-			spin_unlock (&minor_lock);
-			err("minor %d is already in use, error registering %s driver",
-			    i, driver->name);
-			return -EINVAL;
-		}
-		
-	for (i = start_minor; i < (start_minor + num_minors); ++i)
-		usb_minors[i] = driver;
-
-	spin_unlock (&minor_lock);
-	return 0;
-}
-
-static void usb_deregister_minors (struct usb_driver *driver, int num_minors, int start_minor)
-{
-	int i;
-
-	dbg ("%s is removing %d minors starting at %d", driver->name,
-	     num_minors, start_minor);
-
-	spin_lock (&minor_lock);
-	for (i = start_minor; i < (start_minor + num_minors); ++i)
-		usb_minors[i] = NULL;
-	spin_unlock (&minor_lock);
-}
 
 /**
- *	usb_register - register a USB driver
- *	@new_driver: USB operations for the driver
+ * usb_register - register a USB driver
+ * @new_driver: USB operations for the driver
  *
- *	Registers a USB driver with the USB core.  The list of unattached
- *	interfaces will be rescanned whenever a new driver is added, allowing
- *	the new driver to attach to any recognized devices.
- *	Returns a negative error code on failure and 0 on success.
+ * Registers a USB driver with the USB core.  The list of unattached
+ * interfaces will be rescanned whenever a new driver is added, allowing
+ * the new driver to attach to any recognized devices.
+ * Returns a negative error code on failure and 0 on success.
+ * 
+ * NOTE: if you want your driver to use the USB major number, you must call
+ * usb_register_dev() to enable that functionality.  This function no longer
+ * takes care of that.
  */
 int usb_register(struct usb_driver *new_driver)
 {
 	int retval = 0;
-	
-	if ((new_driver->fops) && (new_driver->num_minors == 0)) {
-		err ("%s driver must specify num_minors", new_driver->name);
-		return -EINVAL;
-	}
-
-#ifndef CONFIG_USB_DYNAMIC_MINORS
-	if (new_driver->fops != NULL) {
-		retval = usb_register_minors (new_driver, new_driver->num_minors, new_driver->minor);
-		if (retval)
-			return retval;
-	}
-#endif
 
 	info("registered new driver %s", new_driver->name);
 
@@ -144,92 +93,6 @@
 
 
 /**
- * usb_register_dev - register a USB device, and ask for a minor number
- * @new_driver: USB operations for the driver
- * @num_minors: number of minor numbers requested for this device
- * @start_minor: place to put the new starting minor number
- *
- * Used to ask the USB core for a new minor number for a device that has
- * just showed up.  This is used to dynamically allocate minor numbers
- * from the pool of USB reserved minor numbers.
- *
- * This should be called by all drivers that use the USB major number.
- * This only returns a good value of CONFIG_USB_DYNAMIC_MINORS is
- * selected by the user.
- *
- * usb_deregister_dev() should be called when the driver is done with
- * the minor numbers given out by this function.
- *
- * Returns -ENODEV if CONFIG_USB_DYNAMIC_MINORS is not enabled in this
- * kernel, -EINVAL if something bad happens with trying to register a
- * device, and 0 on success, alone with a value that the driver should
- * use in start_minor.
- */
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-int usb_register_dev (struct usb_driver *new_driver, int num_minors, int *start_minor)
-{
-	int i;
-	int j;
-	int good_spot;
-	int retval = -EINVAL;
-
-	dbg ("%s is asking for %d minors", new_driver->name, num_minors);
-
-	if (new_driver->fops == NULL)
-		goto exit;
-
-	*start_minor = 0; 
-	spin_lock (&minor_lock);
-	for (i = 0; i < MAX_USB_MINORS; ++i) {
-		if (usb_minors[i])
-			continue;
-
-		good_spot = 1;
-		for (j = 1; j <= num_minors-1; ++j)
-			if (usb_minors[i+j]) {
-				good_spot = 0;
-				break;
-			}
-		if (good_spot == 0)
-			continue;
-
-		*start_minor = i;
-		spin_unlock (&minor_lock);
-		retval = usb_register_minors (new_driver, num_minors, *start_minor);
-		if (retval) {
-			/* someone snuck in here, so let's start looking all over again */
-			spin_lock (&minor_lock);
-			i = 0;
-			continue;
-		}
-		goto exit;
-	}
-	spin_unlock (&minor_lock);
-exit:
-	return retval;
-}
-
-/**
- * usb_deregister_dev - deregister a USB device's dynamic minor.
- * @driver: USB operations for the driver
- * @num_minors: number of minor numbers to put back.
- * @start_minor: the starting minor number
- *
- * Used in conjunction with usb_register_dev().  This function is called
- * when the USB driver is finished with the minor numbers gotten from a
- * call to usb_register_dev() (usually when the device is disconnected
- * from the system.)
- * 
- * This should be called by all drivers that use the USB major number.
- */
-void usb_deregister_dev (struct usb_driver *driver, int num_minors, int start_minor)
-{
-	usb_deregister_minors (driver, num_minors, start_minor);
-}
-#endif	/* CONFIG_USB_DYNAMIC_MINORS */
-
-
-/**
  *	usb_scan_devices - scans all unclaimed USB interfaces
  *	Context: !in_interrupt ()
  *
@@ -298,11 +161,15 @@
 }
 
 /**
- *	usb_deregister - unregister a USB driver
- *	@driver: USB operations of the driver to unregister
- *	Context: !in_interrupt ()
+ * usb_deregister - unregister a USB driver
+ * @driver: USB operations of the driver to unregister
+ * Context: !in_interrupt ()
  *
- *	Unlinks the specified driver from the internal USB driver list.
+ * Unlinks the specified driver from the internal USB driver list.
+ * 
+ * NOTE: If you called usb_register_dev(), you still need to call
+ * usb_deregister_dev() to clean up your driver's allocated minor numbers,
+ * this * call will no longer do it for you.
  */
 void usb_deregister(struct usb_driver *driver)
 {
@@ -310,11 +177,6 @@
 
 	info("deregistering driver %s", driver->name);
 
-#ifndef CONFIG_USB_DYNAMIC_MINORS
-	if (driver->fops != NULL)
-		usb_deregister_minors (driver, driver->num_minors, driver->minor);
-#endif
-
 	/*
 	 * first we remove the driver, to be sure it doesn't get used by
 	 * another thread while we are stepping through removing entries
@@ -1357,55 +1219,6 @@
 	return 0;
 }
 
-static int usb_open(struct inode * inode, struct file * file)
-{
-	int minor = minor(inode->i_rdev);
-	struct usb_driver *c;
-	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
-
-	spin_lock (&minor_lock);
-	c = usb_minors[minor];
-	spin_unlock (&minor_lock);
-
-	if (!c || !(new_fops = fops_get(c->fops)))
-		return err;
-	old_fops = file->f_op;
-	file->f_op = new_fops;
-	/* Curiouser and curiouser... NULL ->open() as "no device" ? */
-	if (file->f_op->open)
-		err = file->f_op->open(inode,file);
-	if (err) {
-		fops_put(file->f_op);
-		file->f_op = fops_get(old_fops);
-	}
-	fops_put(old_fops);
-	return err;
-}
-
-static struct file_operations usb_fops = {
-	owner:		THIS_MODULE,
-	open:		usb_open,
-};
-
-int usb_major_init(void)
-{
-	if (devfs_register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
-		err("unable to get major %d for usb devices", USB_MAJOR);
-		return -EBUSY;
-	}
-
-	usb_devfs_handle = devfs_mk_dir(NULL, "usb", NULL);
-
-	return 0;
-}
-
-void usb_major_cleanup(void)
-{
-	devfs_unregister(usb_devfs_handle);
-	devfs_unregister_chrdev(USB_MAJOR, "usb");
-}
-
 
 #ifdef CONFIG_PROC_FS
 struct list_head *usb_driver_get_list(void)
@@ -1463,11 +1276,6 @@
 EXPORT_SYMBOL(usb_deregister);
 EXPORT_SYMBOL(usb_scan_devices);
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-EXPORT_SYMBOL(usb_register_dev);
-EXPORT_SYMBOL(usb_deregister_dev);
-#endif
-
 EXPORT_SYMBOL(usb_alloc_dev);
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_get_dev);
@@ -1489,5 +1297,4 @@
 
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
-EXPORT_SYMBOL(usb_devfs_handle);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/host/Config.help b/drivers/usb/host/Config.help
--- a/drivers/usb/host/Config.help	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/host/Config.help	Fri Jul  5 16:43:00 2002
@@ -36,26 +36,7 @@
   The module will be called ohci-hcd.o. If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_USB_UHCI
-  The Universal Host Controller Interface is a standard by Intel for
-  accessing the USB hardware in the PC (which is also called the USB
-  host controller). If your USB host controller conforms to this
-  standard, you may want to say Y, but see below. All recent boards
-  with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
-  i810, i820) conform to this standard. Also all VIA PCI chipsets
-  (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
-  133).
-
-  Currently there exist two drivers for UHCI host controllers: this
-  one and the so-called JE driver, which you can get from
-  "UHCI alternate (JE) support", below. You need only one.
-
-  This code 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 usb-uhci.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_UHCI_ALT
+CONFIG_USB_UHCI_HCD_ALT
   The Universal Host Controller Interface is a standard by Intel for
   accessing the USB hardware in the PC (which is also called the USB
   host controller). If your USB host controller conforms to this
@@ -65,30 +46,10 @@
   (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
   133). If unsure, say Y.
 
-  Currently there exist two drivers for UHCI host controllers: this
-  so-called JE driver, and the one you get from "UHCI support", above.
-  You need only one.
-
   This code 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 uhci.o. If you want to compile it as a
+  The module will be called uhci-hcd.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_OHCI
-  The Open Host Controller Interface is a standard by
-  Compaq/Microsoft/National for accessing the USB PC hardware (also
-  called USB host controller). If your USB host controller conforms to
-  this standard, say Y. The USB host controllers on most non-Intel
-  architectures and on several x86 compatibles with non-Intel chipsets
-  -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
-  Aladdin Pro..) -- conform to this standard.
-
-  You may want to read <file:Documentation/usb/ohci.txt>.
-
-  This code 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 usb-ohci.o. If you want to compile it
-  as a module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_USB_SL811HS
   Say Y here if you have a SL811HS USB host controller in your system.
diff -Nru a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
--- a/drivers/usb/host/Config.in	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/host/Config.in	Fri Jul  5 16:42:59 2002
@@ -2,23 +2,9 @@
 # USB Host Controller Drivers
 #
 comment 'USB Host Controller Drivers'
-dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_USB_UHCI_HCD_ALT" != "y" ]; then
-   dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-fi
-if [ "$CONFIG_USB_UHCI_HCD" != "y" ]; then
-   dep_tristate '  UHCI HCD Alternate (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
-fi
-#if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-#   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-#fi
-#if [ "$CONFIG_USB_UHCI" != "y" ]; then
-#   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-#else
-#   define_bool CONFIG_USB_UHCI_ALT n
-#fi
-#dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+dep_tristate '  EHCI HCD (USB 2.0) support' CONFIG_USB_EHCI_HCD $CONFIG_USB
+dep_tristate '  OHCI HCD support' CONFIG_USB_OHCI_HCD $CONFIG_USB
+dep_tristate '  UHCI HCD (most Intel and VIA) support' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB
 if [ "$CONFIG_ARM" = "y" ]; then
    dep_tristate '  SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
    dep_tristate '  SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/host/ohci-dbg.c	Fri Jul  5 16:43:00 2002
@@ -190,6 +190,8 @@
 	__u32			temp, ndp, i;
 
 	temp = roothub_a (controller);
+	if (temp == ~(u32)0)
+		return;
 	ndp = (temp & RH_A_NDP);
 
 	if (verbose) {
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/usb/host/ohci-hcd.c	Fri Jul  5 16:42:56 2002
@@ -502,10 +502,18 @@
 	if ((ohci->hcca->done_head != 0)
 			&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
-	} else if ((ints = (readl (&regs->intrstatus)
-			& readl (&regs->intrenable))) == 0) {
+
+	/* cardbus/... hardware gone before remove() */
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", hcd->self.bus_name);
+		return;
+
+	/* interrupt for some other device? */
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
 		return;
 	} 
+
 
 	// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
 
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/host/uhci-hcd.c	Fri Jul  5 16:43:00 2002
@@ -1665,37 +1665,15 @@
 
 	uhci_unlink_generic(uhci, urb);
 
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		urbp->status = urb->status = -ECONNABORTED;
+	spin_lock(&uhci->urb_remove_list_lock);
 
-		spin_lock(&uhci->urb_remove_list_lock);
-
-		/* If we're the first, set the next interrupt bit */
-		if (list_empty(&uhci->urb_remove_list))
-			uhci_set_next_interrupt(uhci);
-			
-		list_add(&urbp->urb_list, &uhci->urb_remove_list);
-
-		spin_unlock(&uhci->urb_remove_list_lock);
-
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-	} else {
-		urb->status = -ENOENT;
-
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		if (in_interrupt()) {	/* wait at least 1 frame */
-			static int errorcount = 10;
-
-			if (errorcount--)
-				dbg("uhci_urb_dequeue called from interrupt for urb %p", urb);
-			udelay(1000);
-		} else
-			schedule_timeout(1+1*HZ/1000); 
-
-		uhci_finish_urb(hcd, urb);
-	}
+	/* If we're the first, set the next interrupt bit */
+	if (list_empty(&uhci->urb_remove_list))
+		uhci_set_next_interrupt(uhci);
+	list_add(&urbp->urb_list, &uhci->urb_remove_list);
 
+	spin_unlock(&uhci->urb_remove_list_lock);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 	return 0;
 }
 
@@ -1788,7 +1766,7 @@
 
 		tmp = tmp->next;
 
-		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+		u->transfer_flags |= USB_TIMEOUT_KILLED;
 		uhci_urb_dequeue(hcd, u);
 	}
 
diff -Nru a/drivers/usb/host/usb-uhci-hcd.c b/drivers/usb/host/usb-uhci-hcd.c
--- a/drivers/usb/host/usb-uhci-hcd.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/host/usb-uhci-hcd.c	Fri Jul  5 16:42:59 2002
@@ -271,21 +271,15 @@
 static int uhci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
 	unsigned long flags=0;
-	struct uhci_hcd *uhci;
+	struct uhci_hcd	*uhci = hcd_to_uhci (hcd);
+	int ret;
 
 	dbg("uhci_urb_dequeue called for %p",urb);
 	
-	uhci = hcd_to_uhci (hcd);
-
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		int ret;
-       		spin_lock_irqsave (&uhci->urb_list_lock, flags);
-		ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
-		spin_unlock_irqrestore (&uhci->urb_list_lock, flags);	
-		return ret;
-	}
-	else
-		return uhci_unlink_urb_sync(uhci, urb);
+	spin_lock_irqsave (&uhci->urb_list_lock, flags);
+	ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
+	spin_unlock_irqrestore (&uhci->urb_list_lock, flags);	
+	return ret;
 }
 /*--------------------------------------------------------------------------*/
 static int uhci_get_frame (struct usb_hcd *hcd)
diff -Nru a/drivers/usb/host/usb-uhci-q.c b/drivers/usb/host/usb-uhci-q.c
--- a/drivers/usb/host/usb-uhci-q.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/usb/host/usb-uhci-q.c	Fri Jul  5 16:42:56 2002
@@ -541,22 +541,6 @@
 	}
 }
 /*-------------------------------------------------------------------*/
-static void uhci_clean_iso_step2(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-	int now=UHCI_GET_CURRENT_FRAME(uhci);
-
-	dbg("uhci_clean_iso_step2");
-	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				list_del (p);
-				INIT_LIST_HEAD(&td->horizontal);
-				list_add_tail (&td->horizontal, &uhci->free_desc_td);
-				td->last_used=now;
-	}
-}
-/*-------------------------------------------------------------------*/
 /* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
          CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
          CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
@@ -759,44 +743,6 @@
 	return 0;  // completion will follow
 }
 /*-------------------------------------------------------------------*/
-// kills an urb by unlinking descriptors and waiting for at least one frame
-static int uhci_unlink_urb_sync (struct uhci_hcd *uhci, struct urb *urb)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	unsigned long flags=0;
-
-	spin_lock_irqsave (&uhci->urb_list_lock, flags);
-//	err("uhci_unlink_urb_sync %p, %i",urb,urb->status);
-
-	// move descriptors out the the running chains, dequeue urb
-	uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_DONT_STORE);
-
-	urb_priv = urb->hcpriv;
-
-	spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-		
-	// cleanup the rest
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_INTERRUPT:
-	case PIPE_ISOCHRONOUS:
-		uhci_wait_ms(1);
-		uhci_clean_iso_step2(uhci, urb_priv);
-		break;
-
-	case PIPE_BULK:
-	case PIPE_CONTROL:
-		qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-		uhci_clean_transfer(uhci, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-		uhci_wait_ms(1);
-	}
-	urb->status = -ENOENT;	// mark urb as killed		
-		
-	finish_urb(uhci,urb);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
 // unlink urbs for specific device or all devices
 static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev, int remove_all)
 {
@@ -816,8 +762,6 @@
 
 //		err("unlink urb: %p, dev %p, ud %p", urb, usb_dev,urb->dev);
 		
-		//urb->transfer_flags |=USB_ASYNC_UNLINK;
-			
 		if (remove_all || (usb_dev == urb->dev)) {
 			spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
 			err("forced removing of queued URB %p due to disconnect",urb);
@@ -850,7 +794,7 @@
 		type = usb_pipetype (urb->pipe);
 
 		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
-			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+			urb->transfer_flags |= USB_TIMEOUT_KILLED;
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
 			uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
 		}
diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
--- a/drivers/usb/image/mdc800.c	Fri Jul  5 16:42:48 2002
+++ b/drivers/usb/image/mdc800.c	Fri Jul  5 16:42:48 2002
@@ -401,6 +401,7 @@
  ***************************************************************************/
 
 static struct usb_driver mdc800_usb_driver;
+static struct file_operations mdc800_device_ops;
 
 /*
  * Callback to search the Mustek MDC800 on the USB Bus
@@ -476,7 +477,7 @@
 
 	down (&mdc800->io_lock);
 
-	retval = usb_register_dev (&mdc800_usb_driver, 1, &mdc800->minor);
+	retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, 1, &mdc800->minor);
 	if (retval && (retval != -ENODEV)) {
 		err ("Not able to get a minor for this device.");
 		return 0;
@@ -537,7 +538,7 @@
 	if (mdc800->state == NOT_CONNECTED)
 		return;
 	
-	usb_deregister_dev (&mdc800_usb_driver, 1, mdc800->minor);
+	usb_deregister_dev (1, mdc800->minor);
 
 	mdc800->state=NOT_CONNECTED;
 
@@ -942,12 +943,10 @@
  */
 static struct usb_driver mdc800_usb_driver =
 {
+	owner:		THIS_MODULE,
 	name:		"mdc800",
 	probe:		mdc800_usb_probe,
 	disconnect:	mdc800_usb_disconnect,
-	fops:		&mdc800_device_ops,
-	minor:		MDC800_DEVICE_MINOR_BASE,
-	num_minors:	1,
 	id_table:	mdc800_table
 };
 
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/image/scanner.c	Fri Jul  5 16:42:59 2002
@@ -971,17 +971,11 @@
 	
 	down(&scn_mutex);
 
-	retval = usb_register_dev(&scanner_driver, 1, &scn_minor);
+	retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, 1, &scn_minor);
 	if (retval) {
-		if (retval != -ENODEV) {
-			err ("Not able to get a minor for this device.");
-			up(&scn_mutex);
-			return NULL;
-		}
-		for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
-			if (!p_scn_table[scn_minor])
-				break;
-		}
+		err ("Not able to get a minor for this device.");
+		up(&scn_mutex);
+		return NULL;
 	}
 
 /* Check to make sure that the last slot isn't already taken */
@@ -1112,7 +1106,7 @@
 
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 	devfs_unregister(scn->devfs);
-	usb_deregister_dev(&scanner_driver, 1, scn->scn_minor);
+	usb_deregister_dev(1, scn->scn_minor);
 	p_scn_table[scn->scn_minor] = NULL;
 	usb_free_urb(scn->scn_irq);
 	up (&(scn->sem));
@@ -1125,9 +1119,6 @@
 	name:		"usbscanner",
 	probe:		probe_scanner,
 	disconnect:	disconnect_scanner,
-	fops:		&usb_scanner_fops,
-	minor:		SCN_BASE_MNR,
-	num_minors:	SCN_MAX_MNR,
 	id_table:	NULL, /* This would be scanner_device_ids, but we
 				 need to check every USB device, in case
 				 we match a user defined vendor/product ID. */
diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
--- a/drivers/usb/input/aiptek.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/input/aiptek.c	Fri Jul  5 16:42:59 2002
@@ -296,9 +296,8 @@
 
 	input_register_device(&aiptek->dev);
 
-	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-	       aiptek->dev.number, aiptek->features->name, dev->bus->busnum,
-	       dev->devnum, ifnum);
+	printk(KERN_INFO "input: %s on usb%d:%d.%d\n",
+	       aiptek->features->name, dev->bus->busnum, dev->devnum, ifnum);
 
 	return aiptek;
 }
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/input/hiddev.c	Fri Jul  5 16:42:59 2002
@@ -193,7 +193,7 @@
 static void hiddev_cleanup(struct hiddev *hiddev)
 {
 	devfs_unregister(hiddev->devfs);
-	usb_deregister_dev(&hiddev_driver, 1, hiddev->minor);
+	usb_deregister_dev(1, hiddev->minor);
 	hiddev_table[hiddev->minor] = NULL;
 	kfree(hiddev);
 }
@@ -626,21 +626,16 @@
 	if (i == hid->maxapplication)
 		return -1;
 
-	retval = usb_register_dev (&hiddev_driver, 1, &minor);
+	retval = usb_register_dev (&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
 	if (retval) {
-		if (retval != -ENODEV) {
-			err ("Not able to get a minor for this device.");
-			return -1;
-		}
-		for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
-		if (minor == HIDDEV_MINORS) {
-			printk(KERN_ERR "hiddev: no more free hiddev devices\n");
-			return -1;
-		}
+		err ("Not able to get a minor for this device.");
+		return -1;
 	}
 
-	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) {
+		usb_deregister_dev (1, minor);
 		return -1;
+	}
 	memset(hiddev, 0, sizeof(struct hiddev));
 
 	init_waitqueue_head(&hiddev->wait);
@@ -708,9 +703,6 @@
 static /* const */ struct usb_driver hiddev_driver = {
 	name:		"hiddev",
 	probe:		hiddev_usbd_probe,
-	fops:		&hiddev_fops,
-	minor:		HIDDEV_MINOR_BASE,
-	num_minors:	HIDDEV_MINORS,
 };
 
 int __init hiddev_init(void)
diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
--- a/drivers/usb/media/dabusb.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/media/dabusb.c	Fri Jul  5 16:43:00 2002
@@ -742,14 +742,9 @@
 	if (ifnum != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
 		return NULL;
 
-	retval = usb_register_dev (&dabusb_driver, 1, &devnum);
-	if (retval) {
-		if (retval != -ENODEV)
-			return NULL;
-		devnum = dabusb_find_struct ();
-		if (devnum == -1)
-			return NULL;
-	}
+	retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, 1, &devnum);
+	if (retval)
+		return NULL;
 
 	s = &dabusb[devnum];
 
@@ -791,7 +786,7 @@
 
 	dbg("dabusb_disconnect");
 
-	usb_deregister_dev (&dabusb_driver, 1, s->devnum);
+	usb_deregister_dev (1, s->devnum);
 	s->remove_pending = 1;
 	wake_up (&s->wait);
 	if (s->state == _started)
@@ -814,9 +809,6 @@
 	name:		"dabusb",
 	probe:		dabusb_probe,
 	disconnect:	dabusb_disconnect,
-	fops:		&dabusb_fops,
-	minor:		DABUSB_MINOR,
-	num_minors:	NRDABUSB,
 	id_table:	dabusb_ids,
 };
 
diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
--- a/drivers/usb/misc/auerswald.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/misc/auerswald.c	Fri Jul  5 16:42:59 2002
@@ -1948,23 +1948,11 @@
 	init_waitqueue_head (&cp->bufferwait);
 
 	down (&dev_table_mutex);
-	ret = usb_register_dev (&auerswald_driver, 1, &dtindex);
+	ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, 1, &dtindex);
 	if (ret) {
-		if (ret != -ENODEV) {
-			err ("Not able to get a minor for this device.");
-			up (&dev_table_mutex);
-			goto pfail;
-		}
-		/* find a free slot in the device table */
-		for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
-			if (dev_table[dtindex] == NULL)
-				break;
-		}
-		if ( dtindex >= AUER_MAX_DEVICES) {
-			err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
-			up (&dev_table_mutex);
-			goto pfail;
-		}
+		err ("Not able to get a minor for this device.");
+		up (&dev_table_mutex);
+		goto pfail;
 	}
 
 	/* Give the device a name */
@@ -2096,7 +2084,7 @@
 	devfs_unregister (cp->devfs);
 
 	/* give back our USB minor number */
-	usb_deregister_dev (&auerswald_driver, 1, cp->dtindex);
+	usb_deregister_dev (1, cp->dtindex);
 
 	/* Stop the interrupt endpoint */
 	auerswald_int_release (cp);
@@ -2153,9 +2141,6 @@
 	name:		"auerswald",
 	probe:		auerswald_probe,
 	disconnect:	auerswald_disconnect,
-	fops:		&auerswald_fops,
-	minor:		AUER_MINOR_BASE,
-	num_minors:	AUER_MAX_DEVICES,
 	id_table:	auerswald_ids,
 };
 
diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
--- a/drivers/usb/misc/brlvger.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/misc/brlvger.c	Fri Jul  5 16:43:00 2002
@@ -246,9 +246,6 @@
 	name:		"brlvger",
 	probe:		brlvger_probe,
 	disconnect:	brlvger_disconnect,
-	fops:		&brlvger_fops,
-	minor:		BRLVGER_MINOR,
-	num_minors:	MAX_NR_BRLVGER_DEVS,
 	id_table:	brlvger_ids,
 };
 
@@ -316,21 +313,10 @@
 
 	down(&reserve_sem);
 
-	retval = usb_register_dev(&brlvger_driver, 1, &i);
+	retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, 1, &i);
 	if (retval) {
-		if (retval != -ENODEV) {
-			err("Not able to get a minor for this device.");
-			goto error;
-		}
-		for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )
-			if( display_table[i] == NULL )
-				break;
-
-		if( i == MAX_NR_BRLVGER_DEVS ) {
-			err( "This driver cannot handle more than %d "
-					"braille displays", MAX_NR_BRLVGER_DEVS);
-			goto error;
-		}
+		err("Not able to get a minor for this device.");
+		goto error;
 	}
 
 	if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){
@@ -431,7 +417,7 @@
 		info("Display %d disconnecting", priv->subminor);
 
 		devfs_unregister(priv->devfs);
-		usb_deregister_dev(&brlvger_driver, 1, priv->subminor);
+		usb_deregister_dev(1, priv->subminor);
 
 		down(&disconnect_sem);
 		display_table[priv->subminor] = NULL;
diff -Nru a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
--- a/drivers/usb/misc/rio500.c	Fri Jul  5 16:42:56 2002
+++ b/drivers/usb/misc/rio500.c	Fri Jul  5 16:42:56 2002
@@ -49,7 +49,11 @@
 #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
 #define DRIVER_DESC "USB Rio 500 driver"
 
-#define RIO_MINOR   64
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+	#define RIO_MINOR	0
+#else
+	#define RIO_MINOR	64
+#endif
 
 /* stall/wait timeout for rio */
 #define NAK_TIMEOUT (HZ)
@@ -65,6 +69,7 @@
         unsigned int ifnum;             /* Interface number of the USB device */
         int isopen;                     /* nz if open */
         int present;                    /* Device is present on the bus */
+	int minor;			/* minor number assigned to us */
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
@@ -449,9 +454,16 @@
 		       const struct usb_device_id *id)
 {
 	struct rio_usb_data *rio = &rio_instance;
+	int retval;
 
 	info("USB Rio found at address %d", dev->devnum);
 
+	retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, 1, &rio->minor);
+	if (retval) {
+		err("Not able to get a minor for this device.");
+		return NULL;
+	}
+
 	rio->present = 1;
 	rio->rio_dev = dev;
 
@@ -486,6 +498,7 @@
 	struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
 
 	devfs_unregister(rio->devfs);
+	usb_deregister_dev(1, rio->minor);
 
 	down(&(rio->lock));
 	if (rio->isopen) {
@@ -515,9 +528,6 @@
 	name:		"rio500",
 	probe:		probe_rio,
 	disconnect:	disconnect_rio,
-	fops:		&usb_rio_fops,
-	minor:		RIO_MINOR,
-	num_minors:	1,
 	id_table:	rio_table,
 };
 
diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
--- a/drivers/usb/net/pegasus.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/net/pegasus.c	Fri Jul  5 16:43:00 2002
@@ -1,46 +1,34 @@
 /*
-**	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
-**
-**	Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
-**	
-**
-**	ChangeLog:
-**		....	Most of the time spend reading sources & docs.
-**		v0.2.x	First official release for the Linux kernel.
-**		v0.3.0	Beutified and structured, some bugs fixed.
-**		v0.3.x	URBifying bulk requests and bugfixing. First relatively
-**			stable release. Still can touch device's registers only
-**			from top-halves.
-**		v0.4.0	Control messages remained unurbified are now URBs.
-**			Now we can touch the HW at any time.
-**		v0.4.9	Control urbs again use process context to wait. Argh...
-**			Some long standing bugs (enable_net_traffic) fixed.
-**			Also nasty trick about resubmiting control urb from
-**			interrupt context used. Please let me know how it
-**			behaves. Pegasus II support added since this version.
-**			TODO: suppressing HCD warnings spewage on disconnect.
-**		v0.4.13	Ethernet address is now set at probe(), not at open()
-**			time as this seems to break dhcpd. 
-**		v0.5.0	branch to 2.5.x kernels
-**		v0.5.1	ethtool support added
-*/
-
-/*
- * 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.
+ *  Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
  *
- * 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  *
- * 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
+ *	ChangeLog:
+ *		....	Most of the time spent on reading sources & docs.
+ *		v0.2.x	First official release for the Linux kernel.
+ *		v0.3.0	Beutified and structured, some bugs fixed.
+ *		v0.3.x	URBifying bulk requests and bugfixing. First relatively
+ *			stable release. Still can touch device's registers only
+ *			from top-halves.
+ *		v0.4.0	Control messages remained unurbified are now URBs.
+ *			Now we can touch the HW at any time.
+ *		v0.4.9	Control urbs again use process context to wait. Argh...
+ *			Some long standing bugs (enable_net_traffic) fixed.
+ *			Also nasty trick about resubmiting control urb from
+ *			interrupt context used. Please let me know how it
+ *			behaves. Pegasus II support added since this version.
+ *			TODO: suppressing HCD warnings spewage on disconnect.
+ *		v0.4.13	Ethernet address is now set at probe(), not at open()
+ *			time as this seems to break dhcpd. 
+ *		v0.5.0	branch to 2.5.x kernels
+ *		v0.5.1	ethtool support added
+ *		v0.5.5	rx socket buffers are in a pool and the their allocation
+ * 			is out of the interrupt routine.
  */
 
+
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -58,14 +46,13 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
+#define DRIVER_VERSION "v0.5.6 (2002/06/23)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
 static const char driver_name[] = "pegasus";
 
-#define	PEGASUS_USE_INTR
-#define	PEGASUS_WRITE_EEPROM
+#undef	PEGASUS_WRITE_EEPROM
 #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
 			BMSR_100FULL | BMSR_ANEGCAPABLE)
 
@@ -499,13 +486,57 @@
 	return 0;
 }
 
+static void fill_skb_pool(pegasus_t *pegasus)
+{
+	int i;
+
+	for (i=0; i < RX_SKBS; i++) {
+		if (pegasus->rx_pool[i])
+			continue;
+		pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);
+		/*
+		** we give up if the allocation fail. the tasklet will be
+		** rescheduled again anyway...
+		*/
+		if (pegasus->rx_pool[i] == NULL)
+			return;
+		pegasus->rx_pool[i]->dev = pegasus->net;
+		skb_reserve(pegasus->rx_pool[i], 2);
+	}
+}
+
+static void free_skb_pool(pegasus_t *pegasus)
+{
+	int i;
+
+	for (i=0; i < RX_SKBS; i++) {
+		if (pegasus->rx_pool[i]) {
+			dev_kfree_skb(pegasus->rx_pool[i]);
+			pegasus->rx_pool[i] = NULL;
+		}
+	}
+}
+
+static inline struct sk_buff *pull_skb(pegasus_t *pegasus)
+{
+	int i;
+	struct sk_buff *skb;
+
+	for (i=0; i < RX_SKBS; i++) {
+		if (likely(pegasus->rx_pool[i] != NULL)) {
+			skb = pegasus->rx_pool[i];
+			pegasus->rx_pool[i] = NULL;
+			return skb;
+		}
+	}
+	return NULL;
+}
+
 static void read_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	int count = urb->actual_length;
-	int rx_status;
-	struct sk_buff *skb;
+	int rx_status, count = urb->actual_length;
 	__u16 pkt_len;
 
 	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
@@ -519,7 +550,7 @@
 	case 0:
 		break;
 	case -ETIMEDOUT:
-		dbg("reset MAC");
+		dbg("%s: reset MAC", net->name);
 		pegasus->flags &= ~PEGASUS_RX_BUSY;
 		break;
 	case -ENOENT:
@@ -546,23 +577,24 @@
 	}
 	pkt_len = (rx_status & 0xfff) - 8;
 
-	if (!pegasus->rx_skb)
-		goto tl_sched;
-
+	if (pegasus->rx_skb == NULL)
+		printk("%s: rx_skb == NULL\n", __FUNCTION__);
+	/*
+	** we are sure at this point pegasus->rx_skb != NULL
+	** so we go ahead and pass up the packet.
+	*/
 	skb_put(pegasus->rx_skb, pkt_len);
 	pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
 	netif_rx(pegasus->rx_skb);
-
-	if (!(skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
-		pegasus->rx_skb = NULL;
-		goto tl_sched;
-	}
-	
-	skb->dev = net;
-	skb_reserve(skb, 2);
-	pegasus->rx_skb = skb;
 	pegasus->stats.rx_packets++;
 	pegasus->stats.rx_bytes += pkt_len;
+	
+	spin_lock(&pegasus->rx_pool_lock);
+	pegasus->rx_skb = pull_skb(pegasus);
+	spin_unlock(&pegasus->rx_pool_lock);
+
+	if (pegasus->rx_skb == NULL)
+		goto tl_sched;
 goon:
 	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
 		      usb_rcvbulkpipe(pegasus->usb, 1),
@@ -587,11 +619,19 @@
 
 	pegasus = (pegasus_t *)data;
 
+	spin_lock_irq(&pegasus->rx_pool_lock);
+	fill_skb_pool(pegasus);
+	spin_unlock_irq(&pegasus->rx_pool_lock);
 	if (pegasus->flags & PEGASUS_RX_URB_FAIL)
 		if (pegasus->rx_skb)
 			goto try_again;
-
-	if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
+	if (pegasus->rx_skb == NULL) {
+		spin_lock_irq(&pegasus->rx_pool_lock);
+		pegasus->rx_skb = pull_skb(pegasus);
+		spin_unlock_irq(&pegasus->rx_pool_lock);
+	}
+	if (pegasus->rx_skb == NULL) {
+		warn("wow, low on memory");
 		tasklet_schedule(&pegasus->rx_tl);
 		return;
 	}
@@ -625,7 +665,6 @@
 	netif_wake_queue(pegasus->net);
 }
 
-#ifdef	PEGASUS_USE_INTR
 static void intr_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
@@ -662,7 +701,6 @@
 		}
 	}
 }
-#endif
 
 static void pegasus_tx_timeout(struct net_device *net)
 {
@@ -748,15 +786,62 @@
 
 }
 
+static void free_all_urbs(pegasus_t *pegasus)
+{
+	usb_free_urb(pegasus->intr_urb);
+	usb_free_urb(pegasus->tx_urb);
+	usb_free_urb(pegasus->rx_urb);
+	usb_free_urb(pegasus->ctrl_urb);
+}
+
+static void unlink_all_urbs(pegasus_t *pegasus)
+{
+	usb_unlink_urb(pegasus->intr_urb);
+	usb_unlink_urb(pegasus->tx_urb);
+	usb_unlink_urb(pegasus->rx_urb);
+	usb_unlink_urb(pegasus->ctrl_urb);
+}
+
+static int alloc_urbs(pegasus_t *pegasus)
+{
+	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pegasus->ctrl_urb) {
+		return 0;
+	}
+	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pegasus->rx_urb) {
+		usb_free_urb(pegasus->ctrl_urb);
+		return 0;
+	}
+	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pegasus->tx_urb) {
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		return 0;
+	}
+	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pegasus->intr_urb) {
+		usb_free_urb(pegasus->tx_urb);
+		usb_free_urb(pegasus->rx_urb);
+		usb_free_urb(pegasus->ctrl_urb);
+		return 0;
+	}
+
+	return 1;
+}
+
 static int pegasus_open(struct net_device *net)
 {
 	pegasus_t *pegasus = (pegasus_t *) net->priv;
 	int res;
 
-	if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2)))
+	if (pegasus->rx_skb == NULL)
+		pegasus->rx_skb = pull_skb(pegasus);
+	/*
+	** Note: no point to free the pool.  it is empty :-)
+	*/
+	if (!pegasus->rx_skb)
 		return -ENOMEM;
-	pegasus->rx_skb->dev = net;
-	skb_reserve(pegasus->rx_skb, 2);
 
 	down(&pegasus->sem);
 	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
@@ -765,19 +850,20 @@
 		      read_bulk_callback, pegasus);
 	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, GFP_KERNEL)))
 		warn("%s: failed intr_urb %d", __FUNCTION__, res);
-#endif
 	netif_start_queue(net);
 	pegasus->flags |= PEGASUS_RUNNING;
 	if ((res = enable_net_traffic(net, pegasus->usb))) {
 		err("can't enable_net_traffic() - %d", res);
 		res = -EIO;
+		usb_unlink_urb(pegasus->rx_urb);
+		usb_unlink_urb(pegasus->intr_urb);
+		free_skb_pool(pegasus);
 		goto exit;
 	}
 	set_carrier(net);
@@ -797,13 +883,7 @@
 	netif_stop_queue(net);
 	if (!(pegasus->flags & PEGASUS_UNPLUG))
 		disable_net_traffic(pegasus);
-
-	usb_unlink_urb(pegasus->rx_urb);
-	usb_unlink_urb(pegasus->tx_urb);
-	usb_unlink_urb(pegasus->ctrl_urb);
-#ifdef	PEGASUS_USE_INTR
-	usb_unlink_urb(pegasus->intr_urb);
-#endif
+	unlink_all_urbs(pegasus);
 	up(&pegasus->sem);
 
 	return 0;
@@ -986,38 +1066,14 @@
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head(&pegasus->ctrl_wait);
 
-	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pegasus->ctrl_urb) {
-		kfree(pegasus);
-		return NULL;
-	}
-	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pegasus->rx_urb) {
-		usb_free_urb(pegasus->ctrl_urb);
-		kfree(pegasus);
-		return NULL;
-	}
-	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pegasus->tx_urb) {
-		usb_free_urb(pegasus->rx_urb);
-		usb_free_urb(pegasus->ctrl_urb);
-		kfree(pegasus);
-		return NULL;
-	}
-	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pegasus->intr_urb) {
-		usb_free_urb(pegasus->tx_urb);
-		usb_free_urb(pegasus->rx_urb);
-		usb_free_urb(pegasus->ctrl_urb);
+	if (!alloc_urbs(pegasus)) {
 		kfree(pegasus);
 		return NULL;
 	}
 
 	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);
+		free_all_urbs(pegasus);
 		kfree(pegasus);
 		return NULL;
 	}
@@ -1039,32 +1095,26 @@
 	net->set_multicast_list = pegasus_set_multicast;
 	net->get_stats = pegasus_netdev_stats;
 	net->mtu = PEGASUS_MTU;
+	spin_lock_init(&pegasus->rx_pool_lock);
 
 	pegasus->features = usb_dev_id[dev_index].private;
-#ifdef	PEGASUS_USE_INTR
 	get_interrupt_interval(pegasus);
-#endif
 	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);
+		free_all_urbs(pegasus);
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		goto exit;
 	}
-
-	info("%s: %s", net->name, usb_dev_id[dev_index].name);
-
 	set_ethernet_addr(pegasus);
-
+	fill_skb_pool(pegasus);
+	printk("%s: %s\n", net->name, usb_dev_id[dev_index].name);
 	if (pegasus->features & PEGASUS_II) {
 		info("setup Pegasus II specific registers");
 		setup_pegasus_II(pegasus);
 	}
-
 	pegasus->phy = mii_phy_probe(pegasus);
 	if (pegasus->phy == 0xff) {
 		warn("can't locate MII phy, using default");
@@ -1087,14 +1137,9 @@
 	pegasus->flags |= PEGASUS_UNPLUG;
 	unregister_netdev(pegasus->net);
 	usb_put_dev(dev);
-	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);
+	unlink_all_urbs(pegasus);
+	free_all_urbs(pegasus);
+	free_skb_pool(pegasus);
 	if (pegasus->rx_skb)
 		dev_kfree_skb(pegasus->rx_skb);
 	kfree(pegasus->net);
diff -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
--- a/drivers/usb/net/pegasus.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/net/pegasus.h	Fri Jul  5 16:43:00 2002
@@ -2,18 +2,8 @@
  * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
  *
  * 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
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
  */
 
 
@@ -23,6 +13,7 @@
 #define	HAS_HOME_PNA		0x40000000
 
 #define	PEGASUS_MTU		1536
+#define	RX_SKBS			4
 
 #define	EPROM_WRITE		0x01
 #define	EPROM_READ		0x02
@@ -100,10 +91,12 @@
 	int			intr_interval;
 	struct tasklet_struct	rx_tl;
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
+	struct sk_buff		*rx_pool[RX_SKBS];
 	struct sk_buff		*rx_skb;
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
+	spinlock_t		rx_pool_lock;
 	unsigned char		intr_buff[8];
 	__u8			tx_buff[PEGASUS_MTU];
 	__u8			eth_regs[4];
diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/net/rtl8150.c	Fri Jul  5 16:43:00 2002
@@ -1,15 +1,14 @@
 /*
- * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
- *
- *	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.
+ *  Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
  *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
  */
 
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -19,7 +18,6 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
-#include <linux/init.h>
 #include <asm/uaccess.h>
 
 /* Version Information */
@@ -106,7 +104,7 @@
 
 static void fill_skb_pool(rtl8150_t *);
 static void free_skb_pool(rtl8150_t *);
-static struct sk_buff *pull_skb(rtl8150_t *);
+static inline struct sk_buff *pull_skb(rtl8150_t *);
 static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
 static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
 			   const struct usb_device_id *id);
@@ -312,7 +310,7 @@
 	case -ENOENT:
 		return;	/* the urb is in unlink state */
 	case -ETIMEDOUT:
-		warn("reset needed may be?..");
+		warn("may be reset is needed?..");
 		goto goon;
 	default:
 		warn("Rx status %d", urb->status);
@@ -331,13 +329,13 @@
 	netif_rx(dev->rx_skb);
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += pkt_len;
-	
+
+	spin_lock(&dev->rx_pool_lock);
 	skb = pull_skb(dev);
+	spin_unlock(&dev->rx_pool_lock);
 	if (!skb)
 		goto resched;
 
-	skb->dev = netdev;
-	skb_reserve(skb, 2);
 	dev->rx_skb = skb;
 goon:
 	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
@@ -361,11 +359,16 @@
 
 	dev = (rtl8150_t *)data;
 
+	spin_lock_irq(&dev->rx_pool_lock);
 	fill_skb_pool(dev);
+	spin_unlock_irq(&dev->rx_pool_lock);
 	if (test_bit(RX_URB_FAIL, &dev->flags))
 		if (dev->rx_skb)
 			goto try_again;
-	if (!(skb = pull_skb(dev)))
+	spin_lock_irq(&dev->rx_pool_lock);
+	skb = pull_skb(dev);
+	spin_unlock_irq(&dev->rx_pool_lock);
+	if (skb == NULL)
 		goto tlsched;
 	dev->rx_skb = skb;
 	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
@@ -426,51 +429,41 @@
 {
 	struct sk_buff *skb;
 	int i;
-	unsigned long flags;
 
-	spin_lock_irqsave(&dev->rx_pool_lock, flags);
 	for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
 		if (dev->rx_skb_pool[i])
 			continue;
 		skb = dev_alloc_skb(RTL8150_MTU + 2);
 		if (!skb) {
-			spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
 			return;
 		}
 		skb->dev = dev->netdev;
 		skb_reserve(skb, 2);
 		dev->rx_skb_pool[i] = skb;
 	}
-	spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
 }
 
 static void free_skb_pool(rtl8150_t *dev)
 {
 	int i;
 
-	spin_lock_irq(&dev->rx_pool_lock);
 	for (i = 0; i < RX_SKB_POOL_SIZE; i++)
 		if (dev->rx_skb_pool[i])
 			dev_kfree_skb(dev->rx_skb_pool[i]);
-	spin_unlock_irq(&dev->rx_pool_lock);
 }
 
-static struct sk_buff *pull_skb(rtl8150_t *dev)
+static inline struct sk_buff *pull_skb(rtl8150_t *dev)
 {
 	struct sk_buff *skb;
 	int i;
-	unsigned long flags;
 
-	spin_lock_irqsave(&dev->rx_pool_lock, flags);
 	for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
 		if (dev->rx_skb_pool[i]) {
 			skb = dev->rx_skb_pool[i];
 			dev->rx_skb_pool[i] = NULL;
-			spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
 			return skb;
 		}
 	}
-	spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
 	return NULL;
 }
 
@@ -578,8 +571,8 @@
 	if (dev == NULL) {
 		return -ENODEV;
 	}
-
-	dev->rx_skb = pull_skb(dev);
+	if (dev->rx_skb == NULL)
+		dev->rx_skb = pull_skb(dev);
 	if (!dev->rx_skb)
 		return -ENOMEM;
 
@@ -816,13 +809,13 @@
 	dev = NULL;
 }
 
-static int __init usb_rtl8150_init(void)
+int __init usb_rtl8150_init(void)
 {
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return usb_register(&rtl8150_driver);
 }
 
-static void __exit usb_rtl8150_exit(void)
+void __exit usb_rtl8150_exit(void)
 {
 	usb_deregister(&rtl8150_driver);
 }
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/storage/transport.c	Fri Jul  5 16:42:59 2002
@@ -428,18 +428,13 @@
 			 void *data, u16 size)
 {
 	int status;
-	struct usb_ctrlrequest *dr;
-
-	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
-	if (!dr)
-		return -ENOMEM;
 
 	/* fill in the devrequest structure */
-	dr->bRequestType = requesttype;
-	dr->bRequest = request;
-	dr->wValue = cpu_to_le16(value);
-	dr->wIndex = cpu_to_le16(index);
-	dr->wLength = cpu_to_le16(size);
+	us->dr->bRequestType = requesttype;
+	us->dr->bRequest = request;
+	us->dr->wValue = cpu_to_le16(value);
+	us->dr->wIndex = cpu_to_le16(index);
+	us->dr->wLength = cpu_to_le16(size);
 
 	/* lock the URB */
 	down(&(us->current_urb_sem));
@@ -452,7 +447,7 @@
 
 	/* fill the URB */
 	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
-			 (unsigned char*) dr, data, size, 
+			 (unsigned char*) us->dr, data, size, 
 			 usb_stor_blocking_completion, NULL);
 
 	/* submit the URB */
@@ -1162,7 +1157,7 @@
 	int pipe;
 
 	/* issue the command -- use usb_control_msg() because
-	 *  the state machine is not yet alive */
+	 * this is not a scsi queued-command */
 	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
 	result = usb_control_msg(us->pusb_dev, pipe,
 				 US_BULK_GET_MAX_LUN, 
@@ -1181,8 +1176,8 @@
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
 
-		/* Use usb_clear_halt() because the state machine
-		 *  is not yet alive */
+		/* Use usb_clear_halt() because this is not a
+		 * scsi queued-command */
 		usb_clear_halt(us->pusb_dev, pipe);
 	}
 
@@ -1356,27 +1351,6 @@
  * Reset routines
  ***********************************************************************/
 
-struct us_timeout {
-	struct us_data *us;
-	spinlock_t timer_lock;
-};
-
-/* The timeout event handler
- */
-static void usb_stor_timeout_handler(unsigned long to__)
-{
-	struct us_timeout *to = (struct us_timeout *) to__;
-	struct us_data *us = to->us;
-
-	US_DEBUGP("Timeout occurred\n");
-
-	/* abort the current request */
-	usb_stor_abort_transport(us);
-
-	/* let the reset routine know we have finished */
-	spin_unlock(&to->timer_lock);
-}
-
 /* This is the common part of the device reset code.
  *
  * It's handy that every transport mechanism uses the control endpoint for
@@ -1385,28 +1359,20 @@
  * Basically, we send a reset with a 20-second timeout, so we don't get
  * jammed attempting to do the reset.
  */
-void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
+static int usb_stor_reset_common(struct us_data *us,
+		u8 request, u8 requesttype,
 		u16 value, u16 index, void *data, u16 size)
 {
 	int result;
-	struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED};
-	struct timer_list timeout_list;
-
-	/* prepare the timeout handler */
-	spin_lock(&timeout_data.timer_lock);
-	init_timer(&timeout_list);
 
 	/* A 20-second timeout may seem rather long, but a LaCie
 	 *  StudioDrive USB2 device takes 16+ seconds to get going
 	 *  following a powerup or USB attach event. */
 
-	timeout_list.expires = jiffies + 20 * HZ;
-	timeout_list.data = (unsigned long) &timeout_data;
-	timeout_list.function = usb_stor_timeout_handler;
-	add_timer(&timeout_list);
-
-	result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
-			 request, requesttype, value, index, data, size);
+	/* Use usb_control_msg() because this is not a queued-command */
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+			request, requesttype, value, index, data, size,
+			20*HZ);
 	if (result < 0)
 		goto Done;
 
@@ -1415,41 +1381,30 @@
 	schedule_timeout(HZ*6);
 	set_current_state(TASK_RUNNING);
 
+	/* Use usb_clear_halt() because this is not a queued-command */
 	US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
-	result = usb_stor_clear_halt(us,
+	result = usb_clear_halt(us->pusb_dev,
 		usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
 	if (result < 0)
 		goto Done;
 
 	US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
-	result = usb_stor_clear_halt(us,
+	result = usb_clear_halt(us->pusb_dev,
 		usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 
 	Done:
 
-	/* prevent the timer from coming back to haunt us */
-	if (!del_timer(&timeout_list)) {
-		/* the handler has already started; wait for it to finish */
-		spin_lock(&timeout_data.timer_lock);
-		/* change the abort into a timeout */
-		if (result == -ENOENT)
-			result = -ETIMEDOUT;
-	}
-
 	/* return a result code based on the result of the control message */
-	if (result >= 0)
-		US_DEBUGP("Soft reset done\n");
-	else
+	if (result < 0) {
 		US_DEBUGP("Soft reset failed: %d\n", result);
-
-	if (result == -ETIMEDOUT)
-		us->srb->result = DID_TIME_OUT << 16;
-	else if (result == -ENOENT)
-		us->srb->result = DID_ABORT << 16;
-	else if (result < 0)
 		us->srb->result = DID_ERROR << 16;
-	else
+		result = FAILED;
+	} else {
+		US_DEBUGP("Soft reset done\n");
 		us->srb->result = GOOD << 1;
+		result = SUCCESS;
+	}
+	return result;
 }
 
 /* This issues a CB[I] Reset to the device in question
@@ -1463,10 +1418,9 @@
 	memset(cmd, 0xFF, sizeof(cmd));
 	cmd[0] = SEND_DIAGNOSTIC;
 	cmd[1] = 4;
-	usb_stor_reset_common(us, US_CBI_ADSC, 
+	return usb_stor_reset_common(us, US_CBI_ADSC, 
 				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 				 0, us->ifnum, cmd, sizeof(cmd));
-	return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
 }
 
 /* This issues a Bulk-only Reset to the device in question, including
@@ -1476,8 +1430,7 @@
 {
 	US_DEBUGP("Bulk reset requested\n");
 
-	usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
+	return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
 				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 				 0, us->ifnum, NULL, 0);
-	return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
 }
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/usb/storage/usb.c	Fri Jul  5 16:42:59 2002
@@ -361,65 +361,42 @@
 
 		BUG_ON(action != US_ACT_COMMAND);
 
+		/* lock the device pointers */
+		down(&(us->dev_semaphore));
+
 		/* reject the command if the direction indicator 
 		 * is UNKNOWN
 		 */
 		if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
 			US_DEBUGP("UNKNOWN data direction\n");
 			us->srb->result = DID_ERROR << 16;
-			scsi_lock(host);
-			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			scsi_unlock(host);
-			continue;
 		}
 
 		/* reject if target != 0 or if LUN is higher than
 		 * the maximum known LUN
 		 */
-		if (us->srb->target && 
+		else if (us->srb->target && 
 				!(us->flags & US_FL_SCM_MULT_TARG)) {
 			US_DEBUGP("Bad target number (%d/%d)\n",
 				  us->srb->target, us->srb->lun);
 			us->srb->result = DID_BAD_TARGET << 16;
-
-			scsi_lock(host);
-			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			scsi_unlock(host);
-			continue;
 		}
 
-		if (us->srb->lun > us->max_lun) {
+		else if (us->srb->lun > us->max_lun) {
 			US_DEBUGP("Bad LUN (%d/%d)\n",
 				  us->srb->target, us->srb->lun);
 			us->srb->result = DID_BAD_TARGET << 16;
-
-			scsi_lock(host);
-			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			scsi_unlock(host);
-			continue;
 		}
 
 		/* handle those devices which can't do a START_STOP */
-		if ((us->srb->cmnd[0] == START_STOP) &&
+		else if ((us->srb->cmnd[0] == START_STOP) &&
 		    (us->flags & US_FL_START_STOP)) {
 			US_DEBUGP("Skipping START_STOP command\n");
 			us->srb->result = GOOD << 1;
-
-			scsi_lock(host);
-			us->srb->scsi_done(us->srb);
-			us->srb = NULL;
-			scsi_unlock(host);
-			continue;
 		}
 
-		/* lock the device pointers */
-		down(&(us->dev_semaphore));
-
 		/* our device has gone - pretend not ready */
-		if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
+		else if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
 			US_DEBUGP("Request is for removed device\n");
 			/* For REQUEST_SENSE, it's the data.  But
 			 * for anything else, it should look like
@@ -443,24 +420,25 @@
 				       sizeof(usb_stor_sense_notready));
 				us->srb->result = CHECK_CONDITION << 1;
 			}
-		} else { /* test_bit(DEV_ATTACHED, &us->bitflags) */
+		}  /* test_bit(DEV_ATTACHED, &us->bitflags) */
 
-			/* Handle those devices which need us to fake 
-			 * their inquiry data */
-			if ((us->srb->cmnd[0] == INQUIRY) &&
+		/* Handle those devices which need us to fake 
+		 * their inquiry data */
+		else if ((us->srb->cmnd[0] == INQUIRY) &&
 			    (us->flags & US_FL_FIX_INQUIRY)) {
-				unsigned char data_ptr[36] = {
-				    0x00, 0x80, 0x02, 0x02,
-				    0x1F, 0x00, 0x00, 0x00};
+			unsigned char data_ptr[36] = {
+			    0x00, 0x80, 0x02, 0x02,
+			    0x1F, 0x00, 0x00, 0x00};
 
-				US_DEBUGP("Faking INQUIRY command\n");
-				fill_inquiry_response(us, data_ptr, 36);
-				us->srb->result = GOOD << 1;
-			} else {
-				/* we've got a command, let's do it! */
-				US_DEBUG(usb_stor_show_command(us->srb));
-				us->proto_handler(us->srb, us);
-			}
+			US_DEBUGP("Faking INQUIRY command\n");
+			fill_inquiry_response(us, data_ptr, 36);
+			us->srb->result = GOOD << 1;
+		}
+
+		/* we've got a command, let's do it! */
+		else {
+			US_DEBUG(usb_stor_show_command(us->srb));
+			us->proto_handler(us->srb, us);
 		}
 
 		/* unlock the device pointers */
@@ -487,54 +465,114 @@
 	return 0;
 }	
 
-/* Set up the IRQ pipe and handler
+/* Set up the URB, the usb_ctrlrequest, and the IRQ pipe and handler.
+ * ss->dev_semaphore should already be locked.
  * Note that this function assumes that all the data in the us_data
  * strucuture is current.  This includes the ep_int field, which gives us
  * the endpoint for the interrupt.
  * Returns non-zero on failure, zero on success
  */ 
-static int usb_stor_allocate_irq(struct us_data *ss)
+static int usb_stor_allocate_urbs(struct us_data *ss)
 {
 	unsigned int pipe;
 	int maxp;
 	int result;
 
-	US_DEBUGP("Allocating IRQ for CBI transport\n");
-
-	/* lock access to the data structure */
-	down(&(ss->irq_urb_sem));
-
-	/* allocate the URB */
-	ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ss->irq_urb) {
-		up(&(ss->irq_urb_sem));
-		US_DEBUGP("couldn't allocate interrupt URB");
+	/* allocate the URB we're going to use */
+	US_DEBUGP("Allocating URB\n");
+	ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ss->current_urb) {
+		US_DEBUGP("allocation failed\n");
 		return 1;
 	}
 
-	/* calculate the pipe and max packet size */
-	pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress & 
-			      USB_ENDPOINT_NUMBER_MASK);
-	maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
-	if (maxp > sizeof(ss->irqbuf))
-		maxp = sizeof(ss->irqbuf);
-
-	/* fill in the URB with our data */
-	FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp, 
-		     usb_stor_CBI_irq, ss, ss->ep_int->bInterval); 
-
-	/* submit the URB for processing */
-	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);
-		up(&(ss->irq_urb_sem));
+	/* allocate the usb_ctrlrequest for control packets */
+	US_DEBUGP("Allocating usb_ctrlrequest\n");
+	ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+	if (!ss->dr) {
+		US_DEBUGP("allocation failed\n");
 		return 2;
 	}
 
-	/* unlock the data structure and return success */
+	/* allocate the IRQ URB, if it is needed */
+	if (ss->protocol == US_PR_CBI) {
+		US_DEBUGP("Allocating IRQ for CBI transport\n");
+
+		/* lock access to the data structure */
+		down(&(ss->irq_urb_sem));
+
+		/* allocate the URB */
+		ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ss->irq_urb) {
+			up(&(ss->irq_urb_sem));
+			US_DEBUGP("couldn't allocate interrupt URB");
+			return 3;
+		}
+
+		/* calculate the pipe and max packet size */
+		pipe = usb_rcvintpipe(ss->pusb_dev,
+		    ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+		maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+		if (maxp > sizeof(ss->irqbuf))
+			maxp = sizeof(ss->irqbuf);
+
+		/* fill in the URB with our data */
+		FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf,
+			maxp, usb_stor_CBI_irq, ss, ss->ep_int->bInterval); 
+
+		/* submit the URB for processing */
+		result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
+		US_DEBUGP("usb_submit_urb() returns %d\n", result);
+		if (result) {
+			up(&(ss->irq_urb_sem));
+			return 4;
+		}
+
+		/* unlock the data structure */
+		up(&(ss->irq_urb_sem));
+
+	} /* ss->protocol == US_PR_CBI */
+
+	return 0;	/* success */
+}
+
+/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
+ * ss->dev_semaphore must already be locked.
+ */
+static void usb_stor_deallocate_urbs(struct us_data *ss)
+{
+	int result;
+
+	/* release the IRQ, if we have one */
+	down(&(ss->irq_urb_sem));
+	if (ss->irq_urb) {
+		US_DEBUGP("-- releasing irq URB\n");
+		result = usb_unlink_urb(ss->irq_urb);
+		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+		usb_free_urb(ss->irq_urb);
+		ss->irq_urb = NULL;
+	}
 	up(&(ss->irq_urb_sem));
-	return 0;
+
+	/* free the usb_ctrlrequest buffer */
+	if (ss->dr) {
+		kfree(ss->dr);
+		ss->dr = NULL;
+	}
+
+	/* free up the main URB for this device */
+	if (ss->current_urb) {
+		US_DEBUGP("-- releasing main URB\n");
+		result = usb_unlink_urb(ss->current_urb);
+		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+		usb_free_urb(ss->current_urb);
+		ss->current_urb = NULL;
+	}
+
+	/* mark the device as gone */
+	clear_bit(DEV_ATTACHED, &ss->bitflags);
+	usb_put_dev(ss->pusb_dev);
+	ss->pusb_dev = NULL;
 }
 
 /* Probe to see if a new device is actually a SCSI device */
@@ -712,13 +750,8 @@
 			USB_ENDPOINT_NUMBER_MASK;
 		ss->ep_int = ep_int;
 
-		/* allocate an IRQ callback if one is needed */
-		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
-			goto BadDevice;
-
-		/* allocate the URB we're going to use */
-		ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!ss->current_urb)
+		/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
+		if (usb_stor_allocate_urbs(ss))
 			goto BadDevice;
 
                 /* Re-Initialize the device if it needs it */
@@ -741,11 +774,6 @@
 		memset(ss, 0, sizeof(struct us_data));
 		new_device = 1;
 
-		/* allocate the URB we're going to use */
-		ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!ss->current_urb)
-			goto BadDevice;
-
 		/* Initialize the mutexes only when the struct is new */
 		init_completion(&(ss->notify));
 		init_MUTEX_LOCKED(&(ss->ip_waitq));
@@ -943,8 +971,8 @@
 		}
 		US_DEBUGP("Protocol: %s\n", ss->protocol_name);
 
-		/* allocate an IRQ callback if one is needed */
-		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+		/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
+		if (usb_stor_allocate_urbs(ss))
 			goto BadDevice;
 
 		/*
@@ -1020,26 +1048,11 @@
 	/* we come here if there are any problems */
 	BadDevice:
 	US_DEBUGP("storage_probe() failed\n");
-	down(&ss->irq_urb_sem);
-	if (ss->irq_urb) {
-		usb_unlink_urb(ss->irq_urb);
-		usb_free_urb(ss->irq_urb);
-		ss->irq_urb = NULL;
-	}
-	up(&ss->irq_urb_sem);
-	if (ss->current_urb) {
-		usb_unlink_urb(ss->current_urb);
-		usb_free_urb(ss->current_urb);
-		ss->current_urb = NULL;
-	}
-
-	clear_bit(DEV_ATTACHED, &ss->bitflags);
-	ss->pusb_dev = NULL;
+	usb_stor_deallocate_urbs(ss);
 	if (new_device)
 		kfree(ss);
 	else
 		up(&ss->dev_semaphore);
-	usb_put_dev(dev);
 	return NULL;
 }
 
@@ -1047,7 +1060,6 @@
 static void storage_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct us_data *ss = ptr;
-	int result;
 
 	US_DEBUGP("storage_disconnect() called\n");
 
@@ -1057,33 +1069,8 @@
 		return;
 	}
 
-	/* lock access to the device data structure */
 	down(&(ss->dev_semaphore));
-
-	/* release the IRQ, if we have one */
-	down(&(ss->irq_urb_sem));
-	if (ss->irq_urb) {
-		US_DEBUGP("-- releasing irq URB\n");
-		result = usb_unlink_urb(ss->irq_urb);
-		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
-		usb_free_urb(ss->irq_urb);
-		ss->irq_urb = NULL;
-	}
-	up(&(ss->irq_urb_sem));
-
-	/* free up the main URB for this device */
-	US_DEBUGP("-- releasing main URB\n");
-	result = usb_unlink_urb(ss->current_urb);
-	US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
-	usb_free_urb(ss->current_urb);
-	ss->current_urb = NULL;
-
-	/* mark the device as gone */
-	usb_put_dev(ss->pusb_dev);
-	ss->pusb_dev = NULL;
-	clear_bit(DEV_ATTACHED, &ss->bitflags);
-
-	/* unlock access to the device data structure */
+	usb_stor_deallocate_urbs(ss);
 	up(&(ss->dev_semaphore));
 }
 
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/storage/usb.h	Fri Jul  5 16:43:00 2002
@@ -185,6 +185,7 @@
 	/* control and bulk communications data */
 	struct semaphore	current_urb_sem; /* to protect irq_urb	 */
 	struct urb		*current_urb;	 /* non-int USB requests */
+	struct usb_ctrlrequest	*dr;		 /* control requests	 */
 
 	/* the semaphore for sleeping the control thread */
 	struct semaphore	sema;		 /* to sleep thread on   */
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/usb/usb-skeleton.c	Fri Jul  5 16:43:00 2002
@@ -189,9 +189,6 @@
 	name:		"skeleton",
 	probe:		skel_probe,
 	disconnect:	skel_disconnect,
-	fops:		&skel_fops,
-	minor:		USB_SKEL_MINOR_BASE,
-	num_minors:	MAX_DEVICES,
 	id_table:	skel_table,
 };
 
@@ -532,29 +529,18 @@
 	}
 
 	down (&minor_table_mutex);
-	retval = usb_register_dev (&skel_driver, 1, &minor);
+	retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, 1, &minor);
 	if (retval) {
-		if (retval != -ENODEV) {
-			/* something prevented us from registering this driver */
-			err ("Not able to get a minor for this device.");
-			goto exit;
-		}
-		/* we could not get a dynamic minor, so lets find one of our own */
-		for (minor = 0; minor < MAX_DEVICES; ++minor) {
-			if (minor_table[minor] == NULL)
-				break;
-		}
-		if (minor >= MAX_DEVICES) {
-			err ("Too many devices plugged in, can not handle this device.");
-			goto exit;
-		}
+		/* something prevented us from registering this driver */
+		err ("Not able to get a minor for this device.");
+		goto exit;
 	}
 
 	/* allocate memory for our device state and intialize it */
 	dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL);
 	if (dev == NULL) {
 		err ("Out of memory");
-		goto exit;
+		goto exit_minor;
 	}
 	memset (dev, 0x00, sizeof (*dev));
 	minor_table[minor] = dev;
@@ -628,6 +614,9 @@
 	skel_delete (dev);
 	dev = NULL;
 
+exit_minor:
+	usb_deregister_dev (1, minor);
+
 exit:
 	up (&minor_table_mutex);
 	return dev;
@@ -655,7 +644,7 @@
 	devfs_unregister (dev->devfs);
 
 	/* give back our dynamic minor */
-	usb_deregister_dev (&skel_driver, 1, minor);
+	usb_deregister_dev (1, minor);
 	
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
diff -Nru a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
--- a/drivers/video/matrox/matroxfb_base.c	Fri Jul  5 16:43:00 2002
+++ b/drivers/video/matrox/matroxfb_base.c	Fri Jul  5 16:43:00 2002
@@ -141,6 +141,19 @@
 
 
 /* --------------------------------------------------------------------- */
+static inline void my_install_cmap(WPMINFO2)
+{
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &ACCESS_FBINFO(currcon_display)->cmap;
+
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, &ACCESS_FBINFO(fbcon));
+	else
+		fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
+			    1, &ACCESS_FBINFO(fbcon));
+}
+
 
 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
 	unsigned int pos;
@@ -869,7 +882,7 @@
 				up_read(&ACCESS_FBINFO(altout.lock));
 			}
 			matrox_cfbX_init(PMINFO display);
-			do_install_cmap(ACCESS_FBINFO(fbcon.currcon),&ACCESS_FBINFO(fbcon));
+			my_install_cmap(PMINFO2);
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 			if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
 				int vmode, cmode;
diff -Nru a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
--- a/drivers/video/matrox/matroxfb_crtc2.c	Fri Jul  5 16:42:59 2002
+++ b/drivers/video/matrox/matroxfb_crtc2.c	Fri Jul  5 16:42:59 2002
@@ -29,7 +29,7 @@
 static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
 		unsigned *blue, unsigned *transp, struct fb_info* info) {
 #define m2info ((struct matroxfb_dh_fb_info*)info)
-	if (regno > 16)
+	if (regno >= 16)
 		return 1;
 	*red = m2info->palette[regno].red;
 	*blue = m2info->palette[regno].blue;
@@ -44,7 +44,7 @@
 #define m2info ((struct matroxfb_dh_fb_info*)info)
 	struct display* p;
 
-	if (regno > 16)
+	if (regno >= 16)
 		return 1;
 	m2info->palette[regno].red = red;
 	m2info->palette[regno].blue = blue;
@@ -84,6 +84,19 @@
 #undef m2info
 }
 
+static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info)
+{
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &m2info->currcon_display->cmap;
+	
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, &m2info->fbcon);
+	else
+		fb_set_cmap(fb_default_cmap(16), 1, &m2info->fbcon);
+}
+
+
 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
 		struct my_timming* mt,
 		struct display* p,
@@ -439,7 +452,7 @@
 			up_read(&ACCESS_FBINFO(altout.lock));
 		}
 		matroxfb_dh_cfbX_init(m2info, p);
-		do_install_cmap(ACCESS_FBINFO(fbcon.currcon), &ACCESS_FBINFO(fbcon));
+		my_install_cmap(m2info);
 	}
 	return 0;
 #undef m2info
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Fri Jul  5 16:42:50 2002
+++ b/fs/Makefile	Fri Jul  5 16:42:50 2002
@@ -40,6 +40,7 @@
 obj-$(CONFIG_PROC_FS)		+= proc/
 obj-y				+= partitions/
 obj-y				+= driverfs/
+obj-y				+= devpts/
 
 # Do not add any filesystems before this line
 obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3
@@ -81,7 +82,6 @@
 obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
 obj-$(CONFIG_ADFS_FS)		+= adfs/
 obj-$(CONFIG_REISERFS_FS)	+= reiserfs/
-obj-$(CONFIG_DEVPTS_FS)		+= devpts/
 obj-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs/
 obj-$(CONFIG_JFS_FS)		+= jfs/
 
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Fri Jul  5 16:42:59 2002
+++ b/fs/binfmt_elf.c	Fri Jul  5 16:42:59 2002
@@ -954,7 +954,7 @@
 	int sz;
 
 	sz = sizeof(struct elf_note);
-	sz += roundup(strlen(en->name), 4);
+	sz += roundup(strlen(en->name) + 1, 4);
 	sz += roundup(en->datasz, 4);
 
 	return sz;
@@ -989,7 +989,7 @@
 {
 	struct elf_note en;
 
-	en.n_namesz = strlen(men->name);
+	en.n_namesz = strlen(men->name) + 1;
 	en.n_descsz = men->datasz;
 	en.n_type = men->type;
 
@@ -1124,14 +1124,10 @@
 	psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
 	psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
 	psinfo.pr_sid = prstatus.pr_sid = current->session;
-	prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
-	prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
-	prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
-	prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
-	prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
-	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
-	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
-	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
+	jiffies_to_timeval(current->utime, &prstatus.pr_utime);
+	jiffies_to_timeval(current->stime, &prstatus.pr_stime);
+	jiffies_to_timeval(current->cutime, &prstatus.pr_cutime);
+	jiffies_to_timeval(current->cstime, &prstatus.pr_cstime);
 
 #ifdef DEBUG
 	dump_regs("Passed in regs", (elf_greg_t *)regs);
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Fri Jul  5 16:42:53 2002
+++ b/fs/bio.c	Fri Jul  5 16:42:53 2002
@@ -135,21 +135,26 @@
  **/
 struct bio *bio_alloc(int gfp_mask, int nr_iovecs)
 {
-	struct bio *bio = mempool_alloc(bio_pool, gfp_mask);
+	struct bio *bio;
 	struct bio_vec *bvl = NULL;
 
+	current->flags |= PF_NOWARN;
+	bio = mempool_alloc(bio_pool, gfp_mask);
 	if (unlikely(!bio))
-		return NULL;
+		goto out;
 
 	if (!nr_iovecs || (bvl = bvec_alloc(gfp_mask,nr_iovecs,&bio->bi_max))) {
 		bio_init(bio);
 		bio->bi_destructor = bio_destructor;
 		bio->bi_io_vec = bvl;
-		return bio;
+		goto out;
 	}
 
 	mempool_free(bio, bio_pool);
-	return NULL;
+	bio = NULL;
+out:
+	current->flags &= ~PF_NOWARN;
+	return bio;
 }
 
 /**
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Fri Jul  5 16:43:00 2002
+++ b/fs/block_dev.c	Fri Jul  5 16:43:00 2002
@@ -23,8 +23,6 @@
 
 #include <asm/uaccess.h>
 
-#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
-
 static unsigned long max_block(struct block_device *bdev)
 {
 	unsigned int retval = ~0U;
@@ -299,7 +297,6 @@
 			new_bdev->bd_inode = inode;
 			inode->i_mode = S_IFBLK;
 			inode->i_rdev = kdev;
-			inode->i_dev = kdev;
 			inode->i_bdev = new_bdev;
 			inode->i_data.a_ops = &def_blk_aops;
 			inode->i_data.gfp_mask = GFP_USER;
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Fri Jul  5 16:42:50 2002
+++ b/fs/buffer.c	Fri Jul  5 16:42:50 2002
@@ -36,6 +36,8 @@
 #include <linux/buffer_head.h>
 #include <asm/bitops.h>
 
+static void invalidate_bh_lrus(void);
+
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
 
 /*
@@ -244,22 +246,6 @@
 }
 
 /*
- * Write out and wait upon all dirty data associated with this
- * kdev_t.   Filesystem data as well as the underlying block
- * device.  Takes the superblock lock.
- */
-int fsync_dev(kdev_t dev)
-{
-	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
-	if (bdev) {
-		int res = fsync_bdev(bdev);
-		bdput(bdev);
-		return res;
-	}
-	return 0;
-}
-
-/*
  * sync everything.
  */
 asmlinkage long sys_sync(void)
@@ -389,7 +375,7 @@
  * private_lock is contended then so is mapping->page_lock).
  */
 struct buffer_head *
-__find_get_block(struct block_device *bdev, sector_t block, int unused)
+__find_get_block_slow(struct block_device *bdev, sector_t block, int unused)
 {
 	struct inode *bd_inode = bdev->bd_inode;
 	struct address_space *bd_mapping = bd_inode->i_mapping;
@@ -459,12 +445,15 @@
    pass does the actual I/O. */
 void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
 {
+	invalidate_bh_lrus();
 	/*
 	 * FIXME: what about destroy_dirty_buffers?
 	 * We really want to use invalidate_inode_pages2() for
 	 * that, but not until that's cleaned up.
 	 */
+	current->flags |= PF_INVALIDATE;
 	invalidate_inode_pages(bdev->bd_inode);
+	current->flags &= ~PF_INVALIDATE;
 }
 
 void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
@@ -489,7 +478,6 @@
 	wakeup_bdflush();
 	try_to_free_pages(zone, GFP_NOFS, 0);
 	blk_run_queues();
-	__set_current_state(TASK_RUNNING);
 	yield();
 }
 
@@ -961,7 +949,9 @@
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
+		current->flags |= PF_NOWARN;
 		bh = alloc_buffer_head();
+		current->flags &= ~PF_NOWARN;
 		if (!bh)
 			goto no_grow;
 
@@ -1159,7 +1149,7 @@
  * attempt is failing.  FIXME, perhaps?
  */
 struct buffer_head *
-__getblk(struct block_device *bdev, sector_t block, int size)
+__getblk_slow(struct block_device *bdev, sector_t block, int size)
 {
 	for (;;) {
 		struct buffer_head * bh;
@@ -1259,7 +1249,8 @@
  *  Reads a specified block, and returns buffer head that contains it.
  *  It returns NULL if the block was unreadable.
  */
-struct buffer_head * __bread(struct block_device *bdev, int block, int size)
+struct buffer_head *
+__bread_slow(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *bh = __getblk(bdev, block, size);
 
@@ -1283,6 +1274,165 @@
 	return NULL;
 }
 
+/*
+ * Per-cpu buffer LRU implementation.  To reduce the cost of __find_get_block().
+ * The bhs[] array is sorted - newest buffer is at bhs[0].  Buffers have their
+ * refcount elevated by one when they're in an LRU.  A buffer can only appear
+ * once in a particular CPU's LRU.  A single buffer can be present in multiple
+ * CPU's LRUs at the same time.
+ *
+ * This is a transparent caching front-end to sb_bread(), sb_getblk() and
+ * sb_find_get_block().
+ */
+
+#define BH_LRU_SIZE	7
+
+static struct bh_lru {
+	spinlock_t lock;
+	struct buffer_head *bhs[BH_LRU_SIZE];
+} ____cacheline_aligned_in_smp bh_lrus[NR_CPUS];
+
+/*
+ * The LRU management algorithm is dopey-but-simple.  Sorry.
+ */
+static void bh_lru_install(struct buffer_head *bh)
+{
+	struct buffer_head *evictee = NULL;
+	struct bh_lru *lru;
+
+	if (bh == NULL)
+		return;
+
+	lru = &bh_lrus[get_cpu()];
+	spin_lock(&lru->lock);
+	if (lru->bhs[0] != bh) {
+		struct buffer_head *bhs[BH_LRU_SIZE];
+		int in;
+		int out = 0;
+
+		get_bh(bh);
+		bhs[out++] = bh;
+		for (in = 0; in < BH_LRU_SIZE; in++) {
+			struct buffer_head *bh2 = lru->bhs[in];
+
+			if (bh2 == bh) {
+				__brelse(bh2);
+			} else {
+				if (out >= BH_LRU_SIZE) {
+					BUG_ON(evictee != NULL);
+					evictee = bh2;
+				} else {
+					bhs[out++] = bh2;
+				}
+			}
+		}
+		while (out < BH_LRU_SIZE)
+			bhs[out++] = NULL;
+		memcpy(lru->bhs, bhs, sizeof(bhs));
+	}
+	spin_unlock(&lru->lock);
+	put_cpu();
+
+	if (evictee) {
+		touch_buffer(evictee);
+		__brelse(evictee);
+	}
+}
+
+static inline struct buffer_head *
+lookup_bh(struct block_device *bdev, sector_t block, int size)
+{
+	struct buffer_head *ret = NULL;
+	struct bh_lru *lru;
+	int i;
+
+	lru = &bh_lrus[get_cpu()];
+	spin_lock(&lru->lock);
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		struct buffer_head *bh = lru->bhs[i];
+
+		if (bh && bh->b_bdev == bdev &&
+				bh->b_blocknr == block && bh->b_size == size) {
+			if (i) {
+				while (i) {
+					lru->bhs[i] = lru->bhs[i - 1];
+					i--;
+				}
+				lru->bhs[0] = bh;
+			}
+			get_bh(bh);
+			ret = bh;
+			break;
+		}
+	}
+	spin_unlock(&lru->lock);
+	put_cpu();
+	return ret;
+}
+
+struct buffer_head *
+__find_get_block(struct block_device *bdev, sector_t block, int size)
+{
+	struct buffer_head *bh = lookup_bh(bdev, block, size);
+
+	if (bh == NULL) {
+		bh = __find_get_block_slow(bdev, block, size);
+		bh_lru_install(bh);
+	}
+	return bh;
+}
+EXPORT_SYMBOL(__find_get_block);
+
+struct buffer_head *
+__getblk(struct block_device *bdev, sector_t block, int size)
+{
+	struct buffer_head *bh = __find_get_block(bdev, block, size);
+
+	if (bh == NULL) {
+		bh = __getblk_slow(bdev, block, size);
+		bh_lru_install(bh);
+	}
+	return bh;
+}
+EXPORT_SYMBOL(__getblk);
+
+struct buffer_head *
+__bread(struct block_device *bdev, sector_t block, int size)
+{
+	struct buffer_head *bh = __getblk(bdev, block, size);
+
+	if (bh) {
+		if (buffer_uptodate(bh))
+			return bh;
+		__brelse(bh);
+	}
+	bh = __bread_slow(bdev, block, size);
+	bh_lru_install(bh);
+	return bh;
+}
+EXPORT_SYMBOL(__bread);
+
+/*
+ * This is called rarely - at unmount.
+ */
+static void invalidate_bh_lrus(void)
+{
+	int cpu_idx;
+
+	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++)
+		spin_lock(&bh_lrus[cpu_idx].lock);
+	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++) {
+		int i;
+
+		for (i = 0; i < BH_LRU_SIZE; i++) {
+			brelse(bh_lrus[cpu_idx].bhs[i]);
+			bh_lrus[cpu_idx].bhs[i] = NULL;
+		}
+	}
+	for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++)
+		spin_unlock(&bh_lrus[cpu_idx].lock);
+}
+
 void set_bh_page(struct buffer_head *bh,
 		struct page *page, unsigned long offset)
 {
@@ -2306,7 +2456,8 @@
 		(bh->b_state & ((1 << BH_Dirty) | (1 << BH_Lock)));
 }
 
-static /*inline*/ int drop_buffers(struct page *page)
+static inline int
+drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
 {
 	struct buffer_head *head = page_buffers(page);
 	struct buffer_head *bh;
@@ -2330,9 +2481,9 @@
 
 		if (!list_empty(&bh->b_assoc_buffers))
 			__remove_assoc_queue(bh);
-		free_buffer_head(bh);
 		bh = next;
 	} while (bh != head);
+	*buffers_to_free = head;
 	__clear_page_buffers(page);
 	return 1;
 failed:
@@ -2342,17 +2493,20 @@
 int try_to_free_buffers(struct page *page)
 {
 	struct address_space * const mapping = page->mapping;
+	struct buffer_head *buffers_to_free = NULL;
 	int ret = 0;
 
 	BUG_ON(!PageLocked(page));
 	if (PageWriteback(page))
 		return 0;
 
-	if (mapping == NULL)		/* swapped-in anon page */
-		return drop_buffers(page);
+	if (mapping == NULL) {		/* swapped-in anon page */
+		ret = drop_buffers(page, &buffers_to_free);
+		goto out;
+	}
 
 	spin_lock(&mapping->private_lock);
-	ret = drop_buffers(page);
+	ret = drop_buffers(page, &buffers_to_free);
 	if (ret && !PageSwapCache(page)) {
 		/*
 		 * If the filesystem writes its buffers by hand (eg ext3)
@@ -2365,6 +2519,16 @@
 		ClearPageDirty(page);
 	}
 	spin_unlock(&mapping->private_lock);
+out:
+	if (buffers_to_free) {
+		struct buffer_head *bh = buffers_to_free;
+
+		do {
+			struct buffer_head *next = bh->b_this_page;
+			free_buffer_head(bh);
+			bh = next;
+		} while (bh != buffers_to_free);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(try_to_free_buffers);
@@ -2434,6 +2598,9 @@
 void __init buffer_init(void)
 {
 	int i;
+
+	for (i = 0; i < NR_CPUS; i++)
+		spin_lock_init(&bh_lrus[i].lock);
 
 	bh_cachep = kmem_cache_create("buffer_head",
 			sizeof(struct buffer_head), 0,
diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c
--- a/fs/coda/inode.c	Fri Jul  5 16:43:00 2002
+++ b/fs/coda/inode.c	Fri Jul  5 16:43:00 2002
@@ -281,8 +281,12 @@
 static int coda_statfs(struct super_block *sb, struct statfs *buf)
 {
 	int error;
+	
+	lock_kernel();
 
 	error = venus_statfs(sb, buf);
+
+	unlock_kernel();
 
 	if (error) {
 		/* fake something like AFS does */
diff -Nru a/fs/devpts/Makefile b/fs/devpts/Makefile
--- a/fs/devpts/Makefile	Fri Jul  5 16:43:00 2002
+++ b/fs/devpts/Makefile	Fri Jul  5 16:43:00 2002
@@ -4,6 +4,6 @@
 
 obj-$(CONFIG_DEVPTS_FS) += devpts.o
 
-devpts-objs := root.o inode.o
+devpts-objs := inode.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/devpts/devpts_i.h b/fs/devpts/devpts_i.h
--- a/fs/devpts/devpts_i.h	Fri Jul  5 16:43:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
- *
- * linux/fs/devpts/devpts_i.h
- *
- *  Copyright 1998 H. Peter Anvin -- All Rights Reserved
- *
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
- * ------------------------------------------------------------------------- */
-
-#include <linux/fs.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-
-#define BUILDING_DEVPTS 1
-#include <linux/devpts_fs.h>
-
-struct devpts_sb_info {
-	u32 magic;
-	int setuid;
-	int setgid;
-	uid_t   uid;
-	gid_t   gid;
-	umode_t mode;
-
-	unsigned int max_ptys;
-	struct inode **inodes;
-};
-
-#define DEVPTS_SUPER_MAGIC 0x1cd1
-#define DEVPTS_SBI_MAGIC   0x01da1d02
-
-extern inline struct devpts_sb_info *SBI(struct super_block *sb)
-{
-	return (struct devpts_sb_info *)(sb->u.generic_sbp);
-}
-
-extern struct inode_operations devpts_root_inode_operations;
-extern struct file_operations devpts_root_operations;
diff -Nru a/fs/devpts/inode.c b/fs/devpts/inode.c
--- a/fs/devpts/inode.c	Fri Jul  5 16:42:59 2002
+++ b/fs/devpts/inode.c	Fri Jul  5 16:42:59 2002
@@ -11,135 +11,70 @@
  * ------------------------------------------------------------------------- */
 
 #include <linux/module.h>
-
-#include <linux/string.h>
-#include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/tty.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/namei.h>
 
-#include "devpts_i.h"
+#define DEVPTS_SUPER_MAGIC 0x1cd1
 
 static struct vfsmount *devpts_mnt;
+static struct dentry *devpts_root;
 
-static void devpts_put_super(struct super_block *sb)
-{
-	struct devpts_sb_info *sbi = SBI(sb);
-	struct inode *inode;
-	int i;
-
-	for ( i = 0 ; i < sbi->max_ptys ; i++ ) {
-		if ( (inode = sbi->inodes[i]) ) {
-			if ( atomic_read(&inode->i_count) != 1 )
-				printk("devpts_put_super: badness: entry %d count %d\n",
-				       i, atomic_read(&inode->i_count));
-			inode->i_nlink--;
-			iput(inode);
-		}
-	}
-	kfree(sbi->inodes);
-	kfree(sbi);
-}
-
-static int devpts_remount (struct super_block * sb, int * flags, char * data);
-
-static struct super_operations devpts_sops = {
-	put_super:	devpts_put_super,
-	statfs:		simple_statfs,
-	remount_fs:	devpts_remount,
-};
+static struct {
+	int setuid;
+	int setgid;
+	uid_t   uid;
+	gid_t   gid;
+	umode_t mode;
+} config = {mode: 0600};
 
-static int devpts_parse_options(char *options, struct devpts_sb_info *sbi)
+static int devpts_remount(struct super_block *sb, int *flags, char *data)
 {
 	int setuid = 0;
 	int setgid = 0;
 	uid_t uid = 0;
 	gid_t gid = 0;
 	umode_t mode = 0600;
-	char *this_char, *value;
+	char *this_char;
 
 	this_char = NULL;
-	while ((this_char = strsep(&options, ",")) != NULL) {
+	while ((this_char = strsep(&data, ",")) != NULL) {
+		int n;
+		char dummy;
 		if (!*this_char)
 			continue;
-		if ((value = strchr(this_char,'=')) != NULL)
-			*value++ = 0;
-		if (!strcmp(this_char,"uid")) {
-			if (!value || !*value)
-				return 1;
-			uid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 1;
+		if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
 			setuid = 1;
-		}
-		else if (!strcmp(this_char,"gid")) {
-			if (!value || !*value)
-				return 1;
-			gid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 1;
+			uid = n;
+		} else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
 			setgid = 1;
+			gid = n;
+		} else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
+			mode = n & ~S_IFMT;
+		else {
+			printk("devpts: called with bogus options\n");
+			return -EINVAL;
 		}
-		else if (!strcmp(this_char,"mode")) {
-			if (!value || !*value)
-				return 1;
-			mode = simple_strtoul(value,&value,8);
-			if (*value)
-				return 1;
-		}
-		else
-			return 1;
 	}
-	sbi->setuid  = setuid;
-	sbi->setgid  = setgid;
-	sbi->uid     = uid;
-	sbi->gid     = gid;
-	sbi->mode    = mode & ~S_IFMT;
+	config.setuid  = setuid;
+	config.setgid  = setgid;
+	config.uid     = uid;
+	config.gid     = gid;
+	config.mode    = mode;
 
 	return 0;
 }
 
-static int devpts_remount(struct super_block * sb, int * flags, char * data)
-{
-	struct devpts_sb_info *sbi = sb->u.generic_sbp;
-	int res = devpts_parse_options(data,sbi);
-	if (res) {
-		printk("devpts: called with bogus options\n");
-		return -EINVAL;
-	}
-	return 0;
-}
+static struct super_operations devpts_sops = {
+	statfs:		simple_statfs,
+	remount_fs:	devpts_remount,
+};
 
 static int devpts_fill_super(struct super_block *s, void *data, int silent)
 {
-	int error = -ENOMEM;
 	struct inode * inode;
-	struct devpts_sb_info *sbi;
-
-	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
-	if ( !sbi )
-		goto fail;
-	memset(sbi, 0, sizeof(*sbi));
 
-	sbi->magic  = DEVPTS_SBI_MAGIC;
-	sbi->max_ptys = unix98_max_ptys;
-	sbi->inodes = kmalloc(sizeof(struct inode *) * sbi->max_ptys, GFP_KERNEL);
-	if ( !sbi->inodes )
-		goto fail_free;
-	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;
-	}
-	s->u.generic_sbp = (void *) sbi;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = DEVPTS_SUPER_MAGIC;
@@ -147,27 +82,25 @@
 
 	inode = new_inode(s);
 	if (!inode)
-		goto fail_free;
+		goto fail;
 	inode->i_ino = 1;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = 0;
 	inode->i_blksize = 1024;
 	inode->i_uid = inode->i_gid = 0;
 	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
-	inode->i_op = &devpts_root_inode_operations;
-	inode->i_fop = &devpts_root_operations;
+	inode->i_op = &simple_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
 	inode->i_nlink = 2;
 
-	s->s_root = d_alloc_root(inode);
+	devpts_root = s->s_root = d_alloc_root(inode);
 	if (s->s_root)
 		return 0;
 	
 	printk("devpts: get root dentry failed\n");
 	iput(inode);
-fail_free:
-	kfree(sbi);
 fail:
-	return error;
+	return -ENOMEM;
 }
 
 static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
@@ -183,44 +116,52 @@
 	kill_sb:	kill_anon_super,
 };
 
-void devpts_pty_new(int number, kdev_t device)
+/*
+ * The normal naming convention is simply /dev/pts/<number>; this conforms
+ * to the System V naming convention
+ */
+
+static struct dentry *get_node(int num)
+{
+	char s[10];
+	struct dentry *root = devpts_root;
+	down(&root->d_inode->i_sem);
+	return lookup_one_len(s, root, sprintf(s, "%d", num));
+}
+
+void devpts_pty_new(int number, dev_t device)
 {
-	struct super_block *sb = devpts_mnt->mnt_sb;
-	struct devpts_sb_info *sbi = SBI(sb);
-	struct inode *inode;
-		
-	if ( sbi->inodes[number] )
-		return; /* Already registered, this does happen */
-		
-	inode = new_inode(sb);
+	struct dentry *dentry;
+	struct inode *inode = new_inode(devpts_mnt->mnt_sb);
 	if (!inode)
 		return;
 	inode->i_ino = number+2;
-	inode->i_blocks = 0;
 	inode->i_blksize = 1024;
-	inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
-	inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
+	inode->i_uid = config.setuid ? config.uid : current->fsuid;
+	inode->i_gid = config.setgid ? config.gid : current->fsgid;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	init_special_inode(inode, S_IFCHR|sbi->mode, kdev_t_to_nr(device));
+	init_special_inode(inode, S_IFCHR|config.mode, device);
 
-	if ( sbi->inodes[number] ) {
-		iput(inode);
-		return;
-	}
-	sbi->inodes[number] = inode;
+	dentry = get_node(number);
+	if (!IS_ERR(dentry) && !dentry->d_inode)
+		d_instantiate(dentry, inode);
+	up(&devpts_root->d_inode->i_sem);
 }
 
 void devpts_pty_kill(int number)
 {
-	struct super_block *sb = devpts_mnt->mnt_sb;
-	struct devpts_sb_info *sbi = SBI(sb);
-	struct inode *inode = sbi->inodes[number];
-
-	if ( inode ) {
-		sbi->inodes[number] = NULL;
-		inode->i_nlink--;
-		iput(inode);
+	struct dentry *dentry = get_node(number);
+
+	if (!IS_ERR(dentry)) {
+		struct inode *inode = dentry->d_inode;
+		if (inode) {
+			inode->i_nlink--;
+			d_delete(dentry);
+			dput(dentry);
+		}
+		dput(dentry);
 	}
+	up(&devpts_root->d_inode->i_sem);
 }
 
 static int __init init_devpts_fs(void)
@@ -231,22 +172,12 @@
 		err = PTR_ERR(devpts_mnt);
 		if (!IS_ERR(devpts_mnt))
 			err = 0;
-#ifdef MODULE
-		if ( !err ) {
-			devpts_upcall_new  = devpts_pty_new;
-			devpts_upcall_kill = devpts_pty_kill;
-		}
-#endif
 	}
 	return err;
 }
 
 static void __exit exit_devpts_fs(void)
 {
-#ifdef MODULE
-	devpts_upcall_new  = NULL;
-	devpts_upcall_kill = NULL;
-#endif
 	unregister_filesystem(&devpts_fs_type);
 	kern_umount(devpts_mnt);
 }
@@ -254,4 +185,3 @@
 module_init(init_devpts_fs)
 module_exit(exit_devpts_fs)
 MODULE_LICENSE("GPL");
-
diff -Nru a/fs/devpts/root.c b/fs/devpts/root.c
--- a/fs/devpts/root.c	Fri Jul  5 16:42:50 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,142 +0,0 @@
-/* -*- linux-c -*- --------------------------------------------------------- *
- *
- * linux/fs/devpts/root.c
- *
- *  Copyright 1998 H. Peter Anvin -- All Rights Reserved
- *
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
- * ------------------------------------------------------------------------- */
-
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/smp_lock.h>
-#include "devpts_i.h"
-
-static int devpts_root_readdir(struct file *,void *,filldir_t);
-static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
-static int devpts_revalidate(struct dentry *, int);
-
-struct file_operations devpts_root_operations = {
-	read:		generic_read_dir,
-	readdir:	devpts_root_readdir,
-};
-
-struct inode_operations devpts_root_inode_operations = {
-	lookup:		devpts_root_lookup,
-};
-
-static struct dentry_operations devpts_dentry_operations = {
-	d_revalidate:	devpts_revalidate,
-};
-
-/*
- * The normal naming convention is simply /dev/pts/<number>; this conforms
- * to the System V naming convention
- */
-
-#define genptsname(buf,num) sprintf(buf, "%d", num)
-
-static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
-	struct inode * inode = filp->f_dentry->d_inode;
-	struct devpts_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
-	off_t nr;
-	char numbuf[16];
-
-	lock_kernel();
-
-	nr = filp->f_pos;
-
-	switch(nr)
-	{
-	case 0:
-		if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
-			goto out;
-		filp->f_pos = ++nr;
-		/* fall through */
-	case 1:
-		if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
-			goto out;
-		filp->f_pos = ++nr;
-		/* fall through */
-	default:
-		while ( nr - 2 < sbi->max_ptys ) {
-			int ptynr = nr - 2;
-			if ( sbi->inodes[ptynr] ) {
-				genptsname(numbuf, ptynr);
-				if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 )
-					goto out;
-			}
-			filp->f_pos = ++nr;
-		}
-		break;
-	}
-
-out:
-	unlock_kernel();
-	return 0;
-}
-
-/*
- * Revalidate is called on every cache lookup.  We use it to check that
- * the pty really does still exist.  Never revalidate negative dentries;
- * for simplicity (fix later?)
- */
-static int devpts_revalidate(struct dentry * dentry, int flags)
-{
-	struct devpts_sb_info *sbi;
-
-	if ( !dentry->d_inode )
-		return 0;
-
-	sbi = SBI(dentry->d_inode->i_sb);
-
-	return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode );
-}
-
-static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * dentry)
-{
-	struct devpts_sb_info *sbi = SBI(dir->i_sb);
-	unsigned int entry;
-	int i;
-	const char *p;
-
-	dentry->d_op    = &devpts_dentry_operations;
-
-	if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
-		entry = 0;
-	} else if ( dentry->d_name.len < 1 ) {
-		return NULL;
-	} else {
-		p = dentry->d_name.name;
-		if ( *p < '1' || *p > '9' )
-			return NULL;
-		entry = *p++ - '0';
-
-		for ( i = dentry->d_name.len-1 ; i ; i-- ) {
-			unsigned int nentry = *p++ - '0';
-			if ( nentry > 9 )
-				return NULL;
-			if ( entry >= ~0U/10 )
-				return NULL;
-			entry = nentry + entry * 10;
-		}
-	}
-
-	if ( entry >= sbi->max_ptys )
-		return NULL;
-
-	lock_kernel();
-	if ( sbi->inodes[entry] )
-		atomic_inc(&sbi->inodes[entry]->i_count);
-	
-	d_add(dentry, sbi->inodes[entry]);
-	unlock_kernel();
-
-	return NULL;
-}
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Fri Jul  5 16:42:56 2002
+++ b/fs/driverfs/inode.c	Fri Jul  5 16:42:59 2002
@@ -149,6 +149,10 @@
 	lock_kernel();
 	dentry->d_op = &driverfs_dentry_dir_ops;
  	res = driverfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+ 	if (!res) {
+ 		dir->i_nlink++;
+ 		dentry->d_inode->i_nlink++;
+ 	}
 	unlock_kernel();
 	return res;
 }
@@ -206,21 +210,27 @@
 
 static int driverfs_unlink(struct inode *dir, struct dentry *dentry)
 {
+	struct inode *inode = dentry->d_inode;
+
+	lock_kernel();
+	inode->i_nlink--;
+	unlock_kernel();
+	dput(dentry);
+	return 0;
+}
+
+static int driverfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
 	int error = -ENOTEMPTY;
 
 	if (driverfs_empty(dentry)) {
-		struct inode *inode = dentry->d_inode;
-
-		lock_kernel();
-		inode->i_nlink--;
-		unlock_kernel();
-		dput(dentry);
+		dentry->d_inode->i_nlink--;
+		driverfs_unlink(dir, dentry);
+		dir->i_nlink--;
 		error = 0;
 	}
 	return error;
 }
-
-#define driverfs_rmdir driverfs_unlink
 
 /**
  * driverfs_read_file - "read" data from a file.
diff -Nru a/fs/ext2/balloc.c b/fs/ext2/balloc.c
--- a/fs/ext2/balloc.c	Fri Jul  5 16:42:59 2002
+++ b/fs/ext2/balloc.c	Fri Jul  5 16:42:59 2002
@@ -75,9 +75,8 @@
  *
  * Return buffer_head on success or NULL in case of failure.
  */
-
-static struct buffer_head *read_block_bitmap(struct super_block *sb,
-						unsigned int block_group)
+static struct buffer_head *
+read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
 	struct ext2_group_desc * desc;
 	struct buffer_head * bh = NULL;
@@ -95,78 +94,6 @@
 	return bh;
 }
 
-/*
- * load_block_bitmap loads the block bitmap for a blocks group
- *
- * It maintains a cache for the last bitmaps loaded.  This cache is managed
- * with a LRU algorithm.
- *
- * Notes:
- * 1/ There is one cache per mounted file system.
- * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
- *    this function reads the bitmap without maintaining a LRU cache.
- * 
- * Return the buffer_head of the bitmap or ERR_PTR(-ve).
- */
-static struct buffer_head *load_block_bitmap(struct super_block * sb,
-						unsigned int block_group)
-{
-	struct ext2_sb_info *sbi = EXT2_SB(sb);
-	int i, slot = 0;
-	struct buffer_head *bh = sbi->s_block_bitmap[0];
-
-	if (block_group >= sbi->s_groups_count)
-		ext2_panic (sb, "load_block_bitmap",
-			    "block_group >= groups_count - "
-			    "block_group = %d, groups_count = %lu",
-			    block_group, sbi->s_groups_count);
-	
-	/*
-	 * Do the lookup for the slot.  First of all, check if we're asking
-	 * for the same slot as last time, and did we succeed that last time?
-	 */
-	if (sbi->s_loaded_block_bitmaps > 0 &&
-	    sbi->s_block_bitmap_number[0] == block_group && bh)
-		goto found;
-
-	if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-		slot = block_group;
-		bh = sbi->s_block_bitmap[slot];
-		if (!bh)
-			goto read_it;
-		if (sbi->s_block_bitmap_number[slot] == slot)
-			goto found;
-		ext2_panic (sb, "load_block_bitmap",
-			    "block_group != block_bitmap_number");
-	}
-
-	bh = NULL;
-	for (i = 0; i < sbi->s_loaded_block_bitmaps &&
-		    sbi->s_block_bitmap_number[i] != block_group; i++)
-		;
-	if (i < sbi->s_loaded_block_bitmaps)
-		bh = sbi->s_block_bitmap[i];
-	else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
-		sbi->s_loaded_block_bitmaps++;
-	else
-		brelse (sbi->s_block_bitmap[--i]);
-
-	while (i--) {
-		sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
-		sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
-	}
-
-read_it:
-	if (!bh)
-		bh = read_block_bitmap(sb, block_group);
-	sbi->s_block_bitmap_number[slot] = block_group;
-	sbi->s_block_bitmap[slot] = bh;
-	if (!bh)
-		return ERR_PTR(-EIO);
-found:
-	return bh;
-}
-
 static inline int reserve_blocks(struct super_block *sb, int count)
 {
 	struct ext2_sb_info * sbi = EXT2_SB(sb);
@@ -238,7 +165,7 @@
 void ext2_free_blocks (struct inode * inode, unsigned long block,
 		       unsigned long count)
 {
-	struct buffer_head * bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head * bh2;
 	unsigned long block_group;
 	unsigned long bit;
@@ -275,8 +202,9 @@
 		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
 		count -= overflow;
 	}
-	bh = load_block_bitmap (sb, block_group);
-	if (IS_ERR(bh))
+	brelse(bitmap_bh);
+	bitmap_bh = read_block_bitmap(sb, block_group);
+	if (!bitmap_bh)
 		goto error_return;
 
 	desc = ext2_get_group_desc (sb, block_group, &bh2);
@@ -295,7 +223,7 @@
 			    block, count);
 
 	for (i = 0, group_freed = 0; i < count; i++) {
-		if (!ext2_clear_bit (bit + i, bh->b_data))
+		if (!ext2_clear_bit(bit + i, bitmap_bh->b_data))
 			ext2_error (sb, "ext2_free_blocks",
 				      "bit already cleared for block %lu",
 				      block + i);
@@ -303,10 +231,10 @@
 			group_freed++;
 	}
 
-	mark_buffer_dirty(bh);
+	mark_buffer_dirty(bitmap_bh);
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		ll_rw_block(WRITE, 1, &bitmap_bh);
+		wait_on_buffer(bitmap_bh);
 	}
 
 	group_release_blocks(desc, bh2, group_freed);
@@ -318,6 +246,7 @@
 		goto do_more;
 	}
 error_return:
+	brelse(bitmap_bh);
 	release_blocks(sb, freed);
 	unlock_super (sb);
 	DQUOT_FREE_BLOCK(inode, freed);
@@ -384,7 +313,7 @@
 int ext2_new_block (struct inode * inode, unsigned long goal,
     u32 * prealloc_count, u32 * prealloc_block, int * err)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *bh2;
 	struct ext2_group_desc *desc;
 	int i, j, k, tmp;
@@ -431,13 +360,14 @@
 	group_alloc = group_reserve_blocks(desc, bh2, es_alloc);
 	if (group_alloc) {
 		j = ((goal - le32_to_cpu(es->s_first_data_block)) % group_size);
-		bh = load_block_bitmap (sb, i);
-		if (IS_ERR(bh))
+		brelse(bitmap_bh);
+		bitmap_bh = read_block_bitmap(sb, i);
+		if (!bitmap_bh)
 			goto io_error;
 		
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
-		j = grab_block(bh->b_data, group_size, j);
+		j = grab_block(bitmap_bh->b_data, group_size, j);
 		if (j >= 0)
 			goto got_block;
 		group_release_blocks(desc, bh2, group_alloc);
@@ -461,11 +391,12 @@
 	}
 	if (k >= sbi->s_groups_count)
 		goto out_release;
-	bh = load_block_bitmap (sb, i);
-	if (IS_ERR(bh))
+	brelse(bitmap_bh);
+	bitmap_bh = read_block_bitmap(sb, i);
+	if (!bitmap_bh)
 		goto io_error;
 	
-	j = grab_block(bh->b_data, group_size, 0);
+	j = grab_block(bitmap_bh->b_data, group_size, 0);
 	if (j < 0) {
 		ext2_error (sb, "ext2_new_block",
 			    "Free blocks count corrupted for block group %d", i);
@@ -510,7 +441,7 @@
 		unsigned n;
 
 		for (n = 0; n < group_alloc && ++j < group_size; n++) {
-			if (ext2_set_bit (j, bh->b_data))
+			if (ext2_set_bit(j, bitmap_bh->b_data))
  				break;
 		}
 		*prealloc_block = block + 1;
@@ -521,10 +452,10 @@
 	}
 	write_unlock(&EXT2_I(inode)->i_meta_lock);
 
-	mark_buffer_dirty(bh);
+	mark_buffer_dirty(bitmap_bh);
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		ll_rw_block(WRITE, 1, &bitmap_bh);
+		wait_on_buffer(bitmap_bh);
 	}
 
 	ext2_debug ("allocating block %d. ", block);
@@ -537,6 +468,7 @@
 	unlock_super (sb);
 	DQUOT_FREE_BLOCK(inode, dq_alloc);
 out:
+	brelse(bitmap_bh);
 	return block;
 
 io_error:
@@ -558,19 +490,20 @@
 	bitmap_count = 0;
 	desc = NULL;
 	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-		struct buffer_head *bh;
+		struct buffer_head *bitmap_bh;
 		desc = ext2_get_group_desc (sb, i, NULL);
 		if (!desc)
 			continue;
 		desc_count += le16_to_cpu(desc->bg_free_blocks_count);
-		bh = load_block_bitmap (sb, i);
-		if (IS_ERR(bh))
+		bitmap_bh = read_block_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 		
-		x = ext2_count_free (bh, sb->s_blocksize);
+		x = ext2_count_free(bitmap_bh, sb->s_blocksize);
 		printk ("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(desc->bg_free_blocks_count), x);
 		bitmap_count += x;
+		brelse(bitmap_bh);
 	}
 	printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
 	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
@@ -645,7 +578,7 @@
 /* Called at mount-time, super-block is locked */
 void ext2_check_blocks_bitmap (struct super_block * sb)
 {
-	struct buffer_head * bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x, j;
 	unsigned long desc_blocks;
@@ -661,38 +594,43 @@
 		if (!desc)
 			continue;
 		desc_count += le16_to_cpu(desc->bg_free_blocks_count);
-		bh = load_block_bitmap (sb, i);
-		if (IS_ERR(bh))
+		brelse(bitmap_bh);
+		bitmap_bh = read_block_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 
-		if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
+		if (ext2_bg_has_super(sb, i) &&
+				!ext2_test_bit(0, bitmap_bh->b_data))
 			ext2_error(sb, __FUNCTION__,
 				   "Superblock in group %d is marked free", i);
 
 		desc_blocks = ext2_bg_num_gdb(sb, i);
 		for (j = 0; j < desc_blocks; j++)
-			if (!ext2_test_bit(j + 1, bh->b_data))
+			if (!ext2_test_bit(j + 1, bitmap_bh->b_data))
 				ext2_error(sb, __FUNCTION__,
 					   "Descriptor block #%ld in group "
 					   "%d is marked free", j, i);
 
-		if (!block_in_use (le32_to_cpu(desc->bg_block_bitmap), sb, bh->b_data))
-			ext2_error (sb, "ext2_check_blocks_bitmap",
+		if (!block_in_use(le32_to_cpu(desc->bg_block_bitmap),
+					sb, bitmap_bh->b_data))
+			ext2_error(sb, "ext2_check_blocks_bitmap",
 				    "Block bitmap for group %d is marked free",
 				    i);
 
-		if (!block_in_use (le32_to_cpu(desc->bg_inode_bitmap), sb, bh->b_data))
-			ext2_error (sb, "ext2_check_blocks_bitmap",
+		if (!block_in_use(le32_to_cpu(desc->bg_inode_bitmap),
+					sb, bitmap_bh->b_data))
+			ext2_error(sb, "ext2_check_blocks_bitmap",
 				    "Inode bitmap for group %d is marked free",
 				    i);
 
 		for (j = 0; j < EXT2_SB(sb)->s_itb_per_group; j++)
-			if (!block_in_use (le32_to_cpu(desc->bg_inode_table) + j, sb, bh->b_data))
+			if (!block_in_use(le32_to_cpu(desc->bg_inode_table) + j,
+						sb, bitmap_bh->b_data))
 				ext2_error (sb, "ext2_check_blocks_bitmap",
 					    "Block #%ld of the inode table in "
 					    "group %d is marked free", j, i);
 
-		x = ext2_count_free (bh, sb->s_blocksize);
+		x = ext2_count_free(bitmap_bh, sb->s_blocksize);
 		if (le16_to_cpu(desc->bg_free_blocks_count) != x)
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Wrong free blocks count for group %d, "
@@ -702,8 +640,10 @@
 	}
 	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
 		ext2_error (sb, "ext2_check_blocks_bitmap",
-			    "Wrong free blocks count in super block, "
-			    "stored = %lu, counted = %lu",
-			    (unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
+			"Wrong free blocks count in super block, "
+			"stored = %lu, counted = %lu",
+			(unsigned long)le32_to_cpu(es->s_free_blocks_count),
+			bitmap_count);
+	brelse(bitmap_bh);
 }
 #endif
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
--- a/fs/ext2/ialloc.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ext2/ialloc.c	Fri Jul  5 16:43:00 2002
@@ -30,8 +30,7 @@
  *
  * The file system contains group descriptors which are located after the
  * super block.  Each descriptor contains the number of the bitmap block and
- * the free blocks count in the block.  The descriptors are loaded in memory
- * when a file system is mounted (see ext2_read_super).
+ * the free blocks count in the block.
  */
 
 
@@ -41,8 +40,8 @@
  *
  * Return buffer_head of bitmap on success or NULL.
  */
-static struct buffer_head *read_inode_bitmap (struct super_block * sb,
-					       unsigned long block_group)
+static struct buffer_head *
+read_inode_bitmap(struct super_block * sb, unsigned long block_group)
 {
 	struct ext2_group_desc *desc;
 	struct buffer_head *bh = NULL;
@@ -53,7 +52,7 @@
 
 	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
 	if (!bh)
-		ext2_error (sb, "read_inode_bitmap",
+		ext2_error(sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
 			    "block_group = %lu, inode_bitmap = %lu",
 			    block_group, (unsigned long) desc->bg_inode_bitmap);
@@ -62,75 +61,6 @@
 }
 
 /*
- * load_inode_bitmap loads the inode bitmap for a blocks group
- *
- * It maintains a cache for the last bitmaps loaded.  This cache is managed
- * with a LRU algorithm.
- *
- * Notes:
- * 1/ There is one cache per mounted file system.
- * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
- *    this function reads the bitmap without maintaining a LRU cache.
- * 
- * Return the buffer_head of the bitmap or the ERR_PTR(error)
- */
-static struct buffer_head *load_inode_bitmap (struct super_block * sb,
-					      unsigned int block_group)
-{
-	int i, slot = 0;
-	struct ext2_sb_info *sbi = EXT2_SB(sb);
-	struct buffer_head *bh = sbi->s_inode_bitmap[0];
-
-	if (block_group >= sbi->s_groups_count)
-		ext2_panic (sb, "load_inode_bitmap",
-			    "block_group >= groups_count - "
-			    "block_group = %d, groups_count = %lu",
-			     block_group, sbi->s_groups_count);
-
-	if (sbi->s_loaded_inode_bitmaps > 0 &&
-	    sbi->s_inode_bitmap_number[0] == block_group && bh)
-		goto found;
-
-	if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-		slot = block_group;
-		bh = sbi->s_inode_bitmap[slot];
-		if (!bh)
-			goto read_it;
-		if (sbi->s_inode_bitmap_number[slot] == slot)
-			goto found;
-		ext2_panic (sb, "load_inode_bitmap",
-			    "block_group != inode_bitmap_number");
-	}
-
-	bh = NULL;
-	for (i = 0; i < sbi->s_loaded_inode_bitmaps &&
-		    sbi->s_inode_bitmap_number[i] != block_group;
-	     i++)
-		;
-	if (i < sbi->s_loaded_inode_bitmaps)
-		bh = sbi->s_inode_bitmap[i];
-	else if (sbi->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
-		sbi->s_loaded_inode_bitmaps++;
-	else
-		brelse (sbi->s_inode_bitmap[--i]);
-
-	while (i--) {
-		sbi->s_inode_bitmap_number[i+1] = sbi->s_inode_bitmap_number[i];
-		sbi->s_inode_bitmap[i+1] = sbi->s_inode_bitmap[i];
-	}
-
-read_it:
-	if (!bh)
-		bh = read_inode_bitmap (sb, block_group);
-	sbi->s_inode_bitmap_number[slot] = block_group;
-	sbi->s_inode_bitmap[slot] = bh;
-	if (!bh)
-		return ERR_PTR(-EIO);
-found:
-	return bh;
-}
-
-/*
  * NOTE! When we get the inode, we're the only people
  * that have access to it, and as such there are no
  * race conditions we have to worry about. The inode
@@ -151,8 +81,8 @@
 	struct super_block * sb = inode->i_sb;
 	int is_directory;
 	unsigned long ino;
-	struct buffer_head * bh;
-	struct buffer_head * bh2;
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *bh2;
 	unsigned long block_group;
 	unsigned long bit;
 	struct ext2_group_desc * desc;
@@ -186,12 +116,13 @@
 	}
 	block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
 	bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
-	bh = load_inode_bitmap (sb, block_group);
-	if (IS_ERR(bh))
+	brelse(bitmap_bh);
+	bitmap_bh = read_inode_bitmap(sb, block_group);
+	if (!bitmap_bh)
 		goto error_return;
 
 	/* Ok, now we can actually update the inode bitmaps.. */
-	if (!ext2_clear_bit (bit, bh->b_data))
+	if (!ext2_clear_bit(bit, bitmap_bh->b_data))
 		ext2_error (sb, "ext2_free_inode",
 			      "bit already cleared for inode %lu", ino);
 	else {
@@ -208,13 +139,14 @@
 			cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
 		mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
 	}
-	mark_buffer_dirty(bh);
+	mark_buffer_dirty(bitmap_bh);
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		ll_rw_block(WRITE, 1, &bitmap_bh);
+		wait_on_buffer(bitmap_bh);
 	}
 	sb->s_dirt = 1;
 error_return:
+	brelse(bitmap_bh);
 	unlock_super (sb);
 }
 
@@ -351,9 +283,9 @@
 
 struct inode * ext2_new_inode(struct inode * dir, int mode)
 {
-	struct super_block * sb;
-	struct buffer_head * bh;
-	struct buffer_head * bh2;
+	struct super_block *sb;
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *bh2;
 	int group, i;
 	ino_t ino;
 	struct inode * inode;
@@ -361,6 +293,7 @@
 	struct ext2_super_block * es;
 	struct ext2_inode_info *ei;
 	int err;
+	struct inode *ret;
 
 	sb = dir->i_sb;
 	inode = new_inode(sb);
@@ -381,20 +314,21 @@
 		goto fail;
 
 	err = -EIO;
-	bh = load_inode_bitmap (sb, group);
-	if (IS_ERR(bh))
+	brelse(bitmap_bh);
+	bitmap_bh = read_inode_bitmap(sb, group);
+	if (!bitmap_bh)
 		goto fail2;
 
-	i = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
+	i = ext2_find_first_zero_bit((unsigned long *)bitmap_bh->b_data,
 				      EXT2_INODES_PER_GROUP(sb));
 	if (i >= EXT2_INODES_PER_GROUP(sb))
 		goto bad_count;
-	ext2_set_bit (i, bh->b_data);
+	ext2_set_bit(i, bitmap_bh->b_data);
 
-	mark_buffer_dirty(bh);
+	mark_buffer_dirty(bitmap_bh);
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ll_rw_block (WRITE, 1, &bh);
-		wait_on_buffer (bh);
+		ll_rw_block(WRITE, 1, &bitmap_bh);
+		wait_on_buffer(bitmap_bh);
 	}
 
 	ino = group * EXT2_INODES_PER_GROUP(sb) + i + 1;
@@ -452,17 +386,19 @@
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
-	unlock_super (sb);
+	unlock_super(sb);
+	ret = inode;
 	if(DQUOT_ALLOC_INODE(inode)) {
 		DQUOT_DROP(inode);
 		inode->i_flags |= S_NOQUOTA;
 		inode->i_nlink = 0;
 		iput(inode);
-		return ERR_PTR(-EDQUOT);
+		ret = ERR_PTR(-EDQUOT);
+	} else {
+		ext2_debug("allocating inode %lu\n", inode->i_ino);
+		ext2_preread_inode(inode);
 	}
-	ext2_debug ("allocating inode %lu\n", inode->i_ino);
-	ext2_preread_inode(inode);
-	return inode;
+	goto out;
 
 fail2:
 	desc = ext2_get_group_desc (sb, group, &bh2);
@@ -476,7 +412,8 @@
 	unlock_super(sb);
 	make_bad_inode(inode);
 	iput(inode);
-	return ERR_PTR(err);
+	ret = ERR_PTR(err);
+	goto out;
 
 bad_count:
 	ext2_error (sb, "ext2_new_inode",
@@ -491,6 +428,9 @@
 	desc->bg_free_inodes_count = 0;
 	mark_buffer_dirty(bh2);
 	goto repeat;
+out:
+	brelse(bitmap_bh);
+	return ret;
 }
 
 unsigned long ext2_count_free_inodes (struct super_block * sb)
@@ -498,30 +438,33 @@
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count = 0, bitmap_count = 0;
+	struct buffer_head *bitmap_bh = NULL;
 	int i;
 
 	lock_super (sb);
 	es = EXT2_SB(sb)->s_es;
 	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-		struct ext2_group_desc *desc = ext2_get_group_desc (sb, i, NULL);
-		struct buffer_head *bh;
+		struct ext2_group_desc *desc;
 		unsigned x;
 
+		desc = ext2_get_group_desc (sb, i, NULL);
 		if (!desc)
 			continue;
 		desc_count += le16_to_cpu(desc->bg_free_inodes_count);
-		bh = load_inode_bitmap (sb, i);
-		if (IS_ERR(bh))
+		brelse(bitmap_bh);
+		bitmap_bh = read_inode_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 
-		x = ext2_count_free (bh, EXT2_INODES_PER_GROUP(sb) / 8);
+		x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8);
 		printk ("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(desc->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
 		le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
-	unlock_super (sb);
+	unlock_super(sb);
 	return desc_count;
 #else
 	return le32_to_cpu(EXT2_SB(sb)->s_es->s_free_inodes_count);
@@ -534,21 +477,23 @@
 {
 	struct ext2_super_block * es = EXT2_SB(sb)->s_es;
 	unsigned long desc_count = 0, bitmap_count = 0;
+	struct buffer_head *bitmap_bh = NULL;
 	int i;
 
 	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-		struct ext2_group_desc *desc = ext2_get_group_desc(sb, i, NULL);
-		struct buffer_head *bh;
+		struct ext2_group_desc *desc;
 		unsigned x;
 
+		desc = ext2_get_group_desc(sb, i, NULL);
 		if (!desc)
 			continue;
 		desc_count += le16_to_cpu(desc->bg_free_inodes_count);
-		bh = load_inode_bitmap (sb, i);
-		if (IS_ERR(bh))
+		brelse(bitmap_bh);
+		bitmap_bh = read_inode_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 		
-		x = ext2_count_free (bh, EXT2_INODES_PER_GROUP(sb) / 8);
+		x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8);
 		if (le16_to_cpu(desc->bg_free_inodes_count) != x)
 			ext2_error (sb, "ext2_check_inodes_bitmap",
 				    "Wrong free inodes count in group %d, "
@@ -556,8 +501,9 @@
 				    le16_to_cpu(desc->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
-		ext2_error (sb, "ext2_check_inodes_bitmap",
+		ext2_error(sb, "ext2_check_inodes_bitmap",
 			    "Wrong free inodes count in super block, "
 			    "stored = %lu, counted = %lu",
 			    (unsigned long)le32_to_cpu(es->s_free_inodes_count),
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ext2/super.c	Fri Jul  5 16:43:00 2002
@@ -142,12 +142,6 @@
 		if (sbi->s_group_desc[i])
 			brelse (sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
-	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
-		if (sbi->s_inode_bitmap[i])
-			brelse (sbi->s_inode_bitmap[i]);
-	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
-		if (sbi->s_block_bitmap[i])
-			brelse (sbi->s_block_bitmap[i]);
 	brelse (sbi->s_sbh);
 	sb->u.generic_sbp = NULL;
 	kfree(sbi);
@@ -686,14 +680,6 @@
 		db_count = i;
 		goto failed_mount2;
 	}
-	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
-		sbi->s_inode_bitmap_number[i] = 0;
-		sbi->s_inode_bitmap[i] = NULL;
-		sbi->s_block_bitmap_number[i] = 0;
-		sbi->s_block_bitmap[i] = NULL;
-	}
-	sbi->s_loaded_inode_bitmaps = 0;
-	sbi->s_loaded_block_bitmaps = 0;
 	sbi->s_gdb_count = db_count;
 	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 	/*
diff -Nru a/fs/ext3/balloc.c b/fs/ext3/balloc.c
--- a/fs/ext3/balloc.c	Fri Jul  5 16:42:56 2002
+++ b/fs/ext3/balloc.c	Fri Jul  5 16:42:56 2002
@@ -76,192 +76,36 @@
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
  */
-
-static int read_block_bitmap (struct super_block * sb,
-			       unsigned int block_group,
-			       unsigned long bitmap_nr)
+static struct buffer_head *
+read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
-	struct ext3_group_desc * gdp;
+	struct ext3_group_desc * desc;
 	struct buffer_head * bh = NULL;
-	int retval = -EIO;
 	
-	gdp = ext3_get_group_desc (sb, block_group, NULL);
-	if (!gdp)
+	desc = ext3_get_group_desc (sb, block_group, NULL);
+	if (!desc)
 		goto error_out;
-	retval = 0;
-	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
-	if (!bh) {
+	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
+	if (!bh)
 		ext3_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
 			    "block_group = %d, block_bitmap = %lu",
-			    block_group, (unsigned long) gdp->bg_block_bitmap);
-		retval = -EIO;
-	}
-	/*
-	 * On IO error, just leave a zero in the superblock's block pointer for
-	 * this group.  The IO will be retried next time.
-	 */
+			    block_group, (unsigned long) desc->bg_block_bitmap);
 error_out:
-	sb->u.ext3_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-	sb->u.ext3_sb.s_block_bitmap[bitmap_nr] = bh;
-	return retval;
-}
-
-/*
- * load_block_bitmap loads the block bitmap for a blocks group
- *
- * It maintains a cache for the last bitmaps loaded.  This cache is managed
- * with a LRU algorithm.
- *
- * Notes:
- * 1/ There is one cache per mounted file system.
- * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups,
- *    this function reads the bitmap without maintaining a LRU cache.
- * 
- * Return the slot used to store the bitmap, or a -ve error code.
- */
-static int __load_block_bitmap (struct super_block * sb,
-			        unsigned int block_group)
-{
-	int i, j, retval = 0;
-	unsigned long block_bitmap_number;
-	struct buffer_head * block_bitmap;
-
-	if (block_group >= sb->u.ext3_sb.s_groups_count)
-		ext3_panic (sb, "load_block_bitmap",
-			    "block_group >= groups_count - "
-			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext3_sb.s_groups_count);
-
-	if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED) {
-		if (sb->u.ext3_sb.s_block_bitmap[block_group]) {
-			if (sb->u.ext3_sb.s_block_bitmap_number[block_group] ==
-			    block_group)
-				return block_group;
-			ext3_error (sb, "__load_block_bitmap",
-				    "block_group != block_bitmap_number");
-		}
-		retval = read_block_bitmap (sb, block_group, block_group);
-		if (retval < 0)
-			return retval;
-		return block_group;
-	}
-
-	for (i = 0; i < sb->u.ext3_sb.s_loaded_block_bitmaps &&
-		    sb->u.ext3_sb.s_block_bitmap_number[i] != block_group; i++)
-		;
-	if (i < sb->u.ext3_sb.s_loaded_block_bitmaps &&
-  	    sb->u.ext3_sb.s_block_bitmap_number[i] == block_group) {
-		block_bitmap_number = sb->u.ext3_sb.s_block_bitmap_number[i];
-		block_bitmap = sb->u.ext3_sb.s_block_bitmap[i];
-		for (j = i; j > 0; j--) {
-			sb->u.ext3_sb.s_block_bitmap_number[j] =
-				sb->u.ext3_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext3_sb.s_block_bitmap[j] =
-				sb->u.ext3_sb.s_block_bitmap[j - 1];
-		}
-		sb->u.ext3_sb.s_block_bitmap_number[0] = block_bitmap_number;
-		sb->u.ext3_sb.s_block_bitmap[0] = block_bitmap;
-
-		/*
-		 * There's still one special case here --- if block_bitmap == 0
-		 * then our last attempt to read the bitmap failed and we have
-		 * just ended up caching that failure.  Try again to read it.
-		 */
-		if (!block_bitmap)
-			retval = read_block_bitmap (sb, block_group, 0);
-	} else {
-		if (sb->u.ext3_sb.s_loaded_block_bitmaps<EXT3_MAX_GROUP_LOADED)
-			sb->u.ext3_sb.s_loaded_block_bitmaps++;
-		else
-			brelse (sb->u.ext3_sb.s_block_bitmap
-					[EXT3_MAX_GROUP_LOADED - 1]);
-		for (j = sb->u.ext3_sb.s_loaded_block_bitmaps - 1;
-					j > 0;  j--) {
-			sb->u.ext3_sb.s_block_bitmap_number[j] =
-				sb->u.ext3_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext3_sb.s_block_bitmap[j] =
-				sb->u.ext3_sb.s_block_bitmap[j - 1];
-		}
-		retval = read_block_bitmap (sb, block_group, 0);
-	}
-	return retval;
-}
-
-/*
- * Load the block bitmap for a given block group.  First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT3_MAX_GROUP_LOADED, then we have no way of 
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
-				     unsigned int block_group)
-{
-	int slot;
-	
-	/*
-	 * Do the lookup for the slot.  First of all, check if we're asking
-	 * for the same slot as last time, and did we succeed that last time?
-	 */
-	if (sb->u.ext3_sb.s_loaded_block_bitmaps > 0 &&
-	    sb->u.ext3_sb.s_block_bitmap_number[0] == block_group &&
-	    sb->u.ext3_sb.s_block_bitmap[0]) {
-		return 0;
-	}
-	/*
-	 * Or can we do a fast lookup based on a loaded group on a filesystem
-	 * small enough to be mapped directly into the superblock?
-	 */
-	else if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED && 
-		 sb->u.ext3_sb.s_block_bitmap_number[block_group]==block_group
-			&& sb->u.ext3_sb.s_block_bitmap[block_group]) {
-		slot = block_group;
-	}
-	/*
-	 * If not, then do a full lookup for this block group.
-	 */
-	else {
-		slot = __load_block_bitmap (sb, block_group);
-	}
-
-	/*
-	 * <0 means we just got an error
-	 */
-	if (slot < 0)
-		return slot;
-	
-	/*
-	 * If it's a valid slot, we may still have cached a previous IO error,
-	 * in which case the bh in the superblock cache will be zero.
-	 */
-	if (!sb->u.ext3_sb.s_block_bitmap[slot])
-		return -EIO;
-	
-	/*
-	 * Must have been read in OK to get this far.
-	 */
-	return slot;
+	return bh;
 }
 
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks (handle_t *handle, struct inode * inode,
 			unsigned long block, unsigned long count)
 {
-	struct buffer_head *bitmap_bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *gd_bh;
 	unsigned long block_group;
 	unsigned long bit;
 	unsigned long i;
-	int bitmap_nr;
 	unsigned long overflow;
 	struct super_block * sb;
 	struct ext3_group_desc * gdp;
@@ -300,11 +144,10 @@
 		overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb);
 		count -= overflow;
 	}
-	bitmap_nr = load_block_bitmap (sb, block_group);
-	if (bitmap_nr < 0)
+	brelse(bitmap_bh);
+	bitmap_bh = read_block_bitmap(sb, block_group);
+	if (!bitmap_bh)
 		goto error_return;
-	
-	bitmap_bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
 	gdp = ext3_get_group_desc (sb, block_group, &gd_bh);
 	if (!gdp)
 		goto error_return;
@@ -421,6 +264,7 @@
 	}
 	sb->s_dirt = 1;
 error_return:
+	brelse(bitmap_bh);
 	ext3_std_error(sb, err);
 	unlock_super(sb);
 	if (dquot_freed_blocks)
@@ -530,29 +374,28 @@
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int ext3_new_block (handle_t *handle, struct inode * inode,
-		unsigned long goal, u32 * prealloc_count,
-		u32 * prealloc_block, int * errp)
-{
-	struct buffer_head * bh, *bhtmp;
-	struct buffer_head * bh2;
-#if 0
-	char * p, * r;
-#endif
-	int i, j, k, tmp, alloctmp;
-	int bitmap_nr;
+int
+ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal,
+		u32 *prealloc_count, u32 *prealloc_block, int *errp)
+{
+	struct buffer_head *bitmap_bh = NULL;	/* bh */
+	struct buffer_head *gdp_bh;		/* bh2 */
+	int group_no;				/* i */
+	int ret_block;				/* j */
+	int bit;				/* k */
+	int target_block;			/* tmp */
 	int fatal = 0, err;
 	int performed_allocation = 0;
-	struct super_block * sb;
-	struct ext3_group_desc * gdp;
-	struct ext3_super_block * es;
+	struct super_block *sb;
+	struct ext3_group_desc *gdp;
+	struct ext3_super_block *es;
 #ifdef EXT3FS_DEBUG
 	static int goal_hits = 0, goal_attempts = 0;
 #endif
 	*errp = -ENOSPC;
 	sb = inode->i_sb;
 	if (!sb) {
-		printk ("ext3_new_block: nonexistent device");
+		printk("ext3_new_block: nonexistent device");
 		return 0;
 	}
 
@@ -564,17 +407,17 @@
 		return 0;
 	}
 
-	lock_super (sb);
+	lock_super(sb);
 	es = sb->u.ext3_sb.s_es;
 	if (le32_to_cpu(es->s_free_blocks_count) <=
 			le32_to_cpu(es->s_r_blocks_count) &&
 	    ((sb->u.ext3_sb.s_resuid != current->fsuid) &&
 	     (sb->u.ext3_sb.s_resgid == 0 ||
-	      !in_group_p (sb->u.ext3_sb.s_resgid)) && 
+	      !in_group_p(sb->u.ext3_sb.s_resgid)) && 
 	     !capable(CAP_SYS_RESOURCE)))
 		goto out;
 
-	ext3_debug ("goal=%lu.\n", goal);
+	ext3_debug("goal=%lu.\n", goal);
 
 	/*
 	 * First, test whether the goal block is free.
@@ -582,64 +425,62 @@
 	if (goal < le32_to_cpu(es->s_first_data_block) ||
 	    goal >= le32_to_cpu(es->s_blocks_count))
 		goal = le32_to_cpu(es->s_first_data_block);
-	i = (goal - le32_to_cpu(es->s_first_data_block)) /
+	group_no = (goal - le32_to_cpu(es->s_first_data_block)) /
 			EXT3_BLOCKS_PER_GROUP(sb);
-	gdp = ext3_get_group_desc (sb, i, &bh2);
+	gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);
 	if (!gdp)
 		goto io_error;
 
 	if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
-		j = ((goal - le32_to_cpu(es->s_first_data_block)) %
+		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
 				EXT3_BLOCKS_PER_GROUP(sb));
 #ifdef EXT3FS_DEBUG
-		if (j)
+		if (ret_block)
 			goal_attempts++;
 #endif
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bitmap_bh = read_block_bitmap(sb, group_no);
+		if (!bitmap_bh)
 			goto io_error;
-		
-		bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
 
-		ext3_debug ("goal is at %d:%d.\n", i, j);
+		ext3_debug("goal is at %d:%d.\n", group_no, ret_block);
 
-		if (ext3_test_allocatable(j, bh)) {
+		if (ext3_test_allocatable(ret_block, bitmap_bh)) {
 #ifdef EXT3FS_DEBUG
 			goal_hits++;
-			ext3_debug ("goal bit allocated.\n");
+			ext3_debug("goal bit allocated.\n");
 #endif
 			goto got_block;
 		}
 
-		j = find_next_usable_block(j, bh, EXT3_BLOCKS_PER_GROUP(sb));
-		if (j >= 0)
+		ret_block = find_next_usable_block(ret_block, bitmap_bh,
+				EXT3_BLOCKS_PER_GROUP(sb));
+		if (ret_block >= 0)
 			goto search_back;
 	}
 
-	ext3_debug ("Bit not found in block group %d.\n", i);
+	ext3_debug("Bit not found in block group %d.\n", group_no);
 
 	/*
 	 * Now search the rest of the groups.  We assume that 
 	 * i and gdp correctly point to the last group visited.
 	 */
-	for (k = 0; k < sb->u.ext3_sb.s_groups_count; k++) {
-		i++;
-		if (i >= sb->u.ext3_sb.s_groups_count)
-			i = 0;
-		gdp = ext3_get_group_desc (sb, i, &bh2);
+	for (bit = 0; bit < sb->u.ext3_sb.s_groups_count; bit++) {
+		group_no++;
+		if (group_no >= sb->u.ext3_sb.s_groups_count)
+			group_no = 0;
+		gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);
 		if (!gdp) {
 			*errp = -EIO;
 			goto out;
 		}
 		if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
-			bitmap_nr = load_block_bitmap (sb, i);
-			if (bitmap_nr < 0)
+			brelse(bitmap_bh);
+			bitmap_bh = read_block_bitmap(sb, group_no);
+			if (!bitmap_bh)
 				goto io_error;
-	
-			bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
-			j = find_next_usable_block(-1, bh, 
+			ret_block = find_next_usable_block(-1, bitmap_bh, 
 						   EXT3_BLOCKS_PER_GROUP(sb));
-			if (j >= 0) 
+			if (ret_block >= 0) 
 				goto search_back;
 		}
 	}
@@ -653,47 +494,51 @@
 	 * bitmap.  Now search backwards up to 7 bits to find the
 	 * start of this group of free blocks.
 	 */
-	for (	k = 0;
-		k < 7 && j > 0 && ext3_test_allocatable(j - 1, bh);
-		k++, j--)
+	for (	bit = 0;
+		bit < 7 && ret_block > 0 &&
+			ext3_test_allocatable(ret_block - 1, bitmap_bh);
+		bit++, ret_block--)
 		;
 	
 got_block:
 
-	ext3_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
+	ext3_debug("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
 
 	/* Make sure we use undo access for the bitmap, because it is
            critical that we do the frozen_data COW on bitmap buffers in
            all cases even if the buffer is in BJ_Forget state in the
            committing transaction.  */
-	BUFFER_TRACE(bh, "get undo access for marking new block");
-	fatal = ext3_journal_get_undo_access(handle, bh);
-	if (fatal) goto out;
-	
-	BUFFER_TRACE(bh2, "get_write_access");
-	fatal = ext3_journal_get_write_access(handle, bh2);
-	if (fatal) goto out;
+	BUFFER_TRACE(bitmap_bh, "get undo access for marking new block");
+	fatal = ext3_journal_get_undo_access(handle, bitmap_bh);
+	if (fatal)
+		goto out;
+	
+	BUFFER_TRACE(gdp_bh, "get_write_access");
+	fatal = ext3_journal_get_write_access(handle, gdp_bh);
+	if (fatal)
+		goto out;
 
 	BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access");
 	fatal = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
-	if (fatal) goto out;
+	if (fatal)
+		goto out;
 
-	tmp = j + i * EXT3_BLOCKS_PER_GROUP(sb)
+	target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)
 				+ le32_to_cpu(es->s_first_data_block);
 
-	if (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
-	    tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
-	    in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
+	if (target_block == le32_to_cpu(gdp->bg_block_bitmap) ||
+	    target_block == le32_to_cpu(gdp->bg_inode_bitmap) ||
+	    in_range(target_block, le32_to_cpu(gdp->bg_inode_table),
 		      sb->u.ext3_sb.s_itb_per_group))
-		ext3_error (sb, "ext3_new_block",
+		ext3_error(sb, "ext3_new_block",
 			    "Allocating block in system zone - "
-			    "block = %u", tmp);
+			    "block = %u", target_block);
 
 	/* The superblock lock should guard against anybody else beating
 	 * us to this point! */
-	J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data));
-	BUFFER_TRACE(bh, "setting bitmap bit");
-	ext3_set_bit(j, bh->b_data);
+	J_ASSERT_BH(bitmap_bh, !ext3_test_bit(ret_block, bitmap_bh->b_data));
+	BUFFER_TRACE(bitmap_bh, "setting bitmap bit");
+	ext3_set_bit(ret_block, bitmap_bh->b_data);
 	performed_allocation = 1;
 
 #ifdef CONFIG_JBD_DEBUG
@@ -701,80 +546,33 @@
 		struct buffer_head *debug_bh;
 
 		/* Record bitmap buffer state in the newly allocated block */
-		debug_bh = sb_find_get_block(sb, tmp);
+		debug_bh = sb_find_get_block(sb, target_block);
 		if (debug_bh) {
 			BUFFER_TRACE(debug_bh, "state when allocated");
-			BUFFER_TRACE2(debug_bh, bh, "bitmap state");
+			BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
 			brelse(debug_bh);
 		}
 	}
 #endif
-	if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data)
-		J_ASSERT_BH(bh, !ext3_test_bit(j, bh2jh(bh)->b_committed_data));
-	bhtmp = bh;
-	alloctmp = j;
-
-	ext3_debug ("found bit %d\n", j);
-
-	/*
-	 * Do block preallocation now if required.
-	 */
-#ifdef EXT3_PREALLOCATE
-	/*
-	 * akpm: this is not enabled for ext3.  Need to use
-	 * ext3_test_allocatable()
-	 */
-	/* Writer: ->i_prealloc* */
-	if (prealloc_count && !*prealloc_count) {
-		int	prealloc_goal;
-		unsigned long next_block = tmp + 1;
-
-		prealloc_goal = es->s_prealloc_blocks ?
-			es->s_prealloc_blocks : EXT3_DEFAULT_PREALLOC_BLOCKS;
-
-		*prealloc_block = next_block;
-		/* Writer: end */
-		for (k = 1;
-		     k < prealloc_goal && (j + k) < EXT3_BLOCKS_PER_GROUP(sb);
-		     k++, next_block++) {
-			if (DQUOT_PREALLOC_BLOCK(inode, 1))
-				break;
-			/* Writer: ->i_prealloc* */
-			if (*prealloc_block + *prealloc_count != next_block ||
-			    ext3_set_bit (j + k, bh->b_data)) {
-				/* Writer: end */
-				DQUOT_FREE_BLOCK(inode, 1);
- 				break;
-			}
-			(*prealloc_count)++;
-			/* Writer: end */
-		}	
-		/*
-		 * As soon as we go for per-group spinlocks we'll need these
-		 * done inside the loop above.
-		 */
-		gdp->bg_free_blocks_count =
-			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
-			       (k - 1));
-		es->s_free_blocks_count =
-			cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
-			       (k - 1));
-		ext3_debug ("Preallocated a further %lu bits.\n",
-			       (k - 1));
-	}
-#endif
+	if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data)
+		J_ASSERT_BH(bitmap_bh,
+			!ext3_test_bit(ret_block,
+					bh2jh(bitmap_bh)->b_committed_data));
+	ext3_debug("found bit %d\n", ret_block);
 
-	j = tmp;
+	/* ret_block was blockgroup-relative.  Now it becomes fs-relative */
+	ret_block = target_block;
 
-	BUFFER_TRACE(bh, "journal_dirty_metadata for bitmap block");
-	err = ext3_journal_dirty_metadata(handle, bh);
-	if (!fatal) fatal = err;
+	BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block");
+	err = ext3_journal_dirty_metadata(handle, bitmap_bh);
+	if (!fatal)
+		fatal = err;
 	
-	if (j >= le32_to_cpu(es->s_blocks_count)) {
-		ext3_error (sb, "ext3_new_block",
+	if (ret_block >= le32_to_cpu(es->s_blocks_count)) {
+		ext3_error(sb, "ext3_new_block",
 			    "block(%d) >= blocks count(%d) - "
-			    "block_group = %d, es == %p ",j,
-			le32_to_cpu(es->s_blocks_count), i, es);
+			    "block_group = %d, es == %p ", ret_block,
+			le32_to_cpu(es->s_blocks_count), group_no, es);
 		goto out;
 	}
 
@@ -783,30 +581,33 @@
 	 * list of some description.  We don't know in advance whether
 	 * the caller wants to use it as metadata or data.
 	 */
-
-	ext3_debug ("allocating block %d. "
-		    "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
+	ext3_debug("allocating block %d. Goal hits %d of %d.\n",
+			ret_block, goal_hits, goal_attempts);
 
 	gdp->bg_free_blocks_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
 	es->s_free_blocks_count =
 			cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1);
 
-	BUFFER_TRACE(bh2, "journal_dirty_metadata for group descriptor");
-	err = ext3_journal_dirty_metadata(handle, bh2);
-	if (!fatal) fatal = err;
-	
-	BUFFER_TRACE(bh, "journal_dirty_metadata for superblock");
+	BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
+	err = ext3_journal_dirty_metadata(handle, gdp_bh);
+	if (!fatal)
+		fatal = err;
+
+	BUFFER_TRACE(sb->u.ext3_sb.s_sbh,
+			"journal_dirty_metadata for superblock");
 	err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
-	if (!fatal) fatal = err;
+	if (!fatal)
+		fatal = err;
 
 	sb->s_dirt = 1;
 	if (fatal)
 		goto out;
 
-	unlock_super (sb);
+	unlock_super(sb);
 	*errp = 0;
-	return j;
+	brelse(bitmap_bh);
+	return ret_block;
 	
 io_error:
 	*errp = -EIO;
@@ -815,55 +616,57 @@
 		*errp = fatal;
 		ext3_std_error(sb, fatal);
 	}
-	unlock_super (sb);
+	unlock_super(sb);
 	/*
 	 * Undo the block allocation
 	 */
 	if (!performed_allocation)
 		DQUOT_FREE_BLOCK(inode, 1);
+	brelse(bitmap_bh);
 	return 0;
 	
 }
 
-unsigned long ext3_count_free_blocks (struct super_block * sb)
+unsigned long ext3_count_free_blocks(struct super_block *sb)
 {
 #ifdef EXT3FS_DEBUG
-	struct ext3_super_block * es;
+	struct ext3_super_block *es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
-	struct ext3_group_desc * gdp;
+	struct buffer_head *bitmap_bh = NULL;
+	struct ext3_group_desc *gdp;
 	int i;
 	
-	lock_super (sb);
+	lock_super(sb);
 	es = sb->u.ext3_sb.s_es;
 	desc_count = 0;
 	bitmap_count = 0;
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) {
-		gdp = ext3_get_group_desc (sb, i, NULL);
+		gdp = ext3_get_group_desc(sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		brelse(bitmap_bh);
+		bitmap_bh = read_block_bitmap(sb, i);
+		if (bitmap_bh == NULL)
 			continue;
 		
-		x = ext3_count_free (sb->u.ext3_sb.s_block_bitmap[bitmap_nr],
-				     sb->s_blocksize);
-		printk ("group %d: stored = %d, counted = %lu\n",
+		x = ext3_count_free(bitmap_bh, sb->s_blocksize);
+		printk("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	printk("ext3_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
 	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
-	unlock_super (sb);
+	unlock_super(sb);
 	return bitmap_count;
 #else
 	return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count);
 #endif
 }
 
-static inline int block_in_use (unsigned long block,
+static inline int block_in_use(unsigned long block,
 				struct super_block * sb,
 				unsigned char * map)
 {
@@ -928,12 +731,11 @@
 /* Called at mount-time, super-block is locked */
 void ext3_check_blocks_bitmap (struct super_block * sb)
 {
-	struct buffer_head * bh;
-	struct ext3_super_block * es;
+	struct ext3_super_block *es;
 	unsigned long desc_count, bitmap_count, x, j;
 	unsigned long desc_blocks;
-	int bitmap_nr;
-	struct ext3_group_desc * gdp;
+	struct buffer_head *bitmap_bh = NULL;
+	struct ext3_group_desc *gdp;
 	int i;
 
 	es = sb->u.ext3_sb.s_es;
@@ -945,43 +747,43 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		brelse(bitmap_bh);
+		bitmap_bh = read_block_bitmap(sb, i);
+		if (bitmap_bh == NULL)
 			continue;
 
-		bh = EXT3_SB(sb)->s_block_bitmap[bitmap_nr];
-
-		if (ext3_bg_has_super(sb, i) && !ext3_test_bit(0, bh->b_data))
+		if (ext3_bg_has_super(sb, i) &&
+				!ext3_test_bit(0, bitmap_bh->b_data))
 			ext3_error(sb, __FUNCTION__,
 				   "Superblock in group %d is marked free", i);
 
 		desc_blocks = ext3_bg_num_gdb(sb, i);
 		for (j = 0; j < desc_blocks; j++)
-			if (!ext3_test_bit(j + 1, bh->b_data))
+			if (!ext3_test_bit(j + 1, bitmap_bh->b_data))
 				ext3_error(sb, __FUNCTION__,
 					   "Descriptor block #%ld in group "
 					   "%d is marked free", j, i);
 
 		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap),
-						sb, bh->b_data))
+						sb, bitmap_bh->b_data))
 			ext3_error (sb, "ext3_check_blocks_bitmap",
 				    "Block bitmap for group %d is marked free",
 				    i);
 
 		if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap),
-						sb, bh->b_data))
+						sb, bitmap_bh->b_data))
 			ext3_error (sb, "ext3_check_blocks_bitmap",
 				    "Inode bitmap for group %d is marked free",
 				    i);
 
 		for (j = 0; j < sb->u.ext3_sb.s_itb_per_group; j++)
 			if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j,
-							sb, bh->b_data))
+							sb, bitmap_bh->b_data))
 				ext3_error (sb, "ext3_check_blocks_bitmap",
 					    "Block #%d of the inode table in "
 					    "group %d is marked free", j, i);
 
-		x = ext3_count_free (bh, sb->s_blocksize);
+		x = ext3_count_free(bitmap_bh, sb->s_blocksize);
 		if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
 			ext3_error (sb, "ext3_check_blocks_bitmap",
 				    "Wrong free blocks count for group %d, "
@@ -989,6 +791,7 @@
 				    le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
 		ext3_error (sb, "ext3_check_blocks_bitmap",
 			"Wrong free blocks count in super block, "
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ext3/ialloc.c	Fri Jul  5 16:43:00 2002
@@ -36,8 +36,7 @@
  *
  * The file system contains group descriptors which are located after the
  * super block.  Each descriptor contains the number of the bitmap block and
- * the free blocks count in the block.  The descriptors are loaded in memory
- * when a file system is mounted (see ext3_read_super).
+ * the free blocks count in the block.
  */
 
 
@@ -45,118 +44,26 @@
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head of bitmap on success or NULL.
  */
-static int read_inode_bitmap (struct super_block * sb,
-			       unsigned long block_group,
-			       unsigned int bitmap_nr)
+static struct buffer_head *
+read_inode_bitmap(struct super_block * sb, unsigned long block_group)
 {
-	struct ext3_group_desc * gdp;
-	struct buffer_head * bh = NULL;
-	int retval = 0;
+	struct ext3_group_desc *desc;
+	struct buffer_head *bh = NULL;
 
-	gdp = ext3_get_group_desc (sb, block_group, NULL);
-	if (!gdp) {
-		retval = -EIO;
+	desc = ext3_get_group_desc(sb, block_group, NULL);
+	if (!desc)
 		goto error_out;
-	}
-	bh = sb_bread(sb, le32_to_cpu(gdp->bg_inode_bitmap));
-	if (!bh) {
-		ext3_error (sb, "read_inode_bitmap",
+
+	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
+	if (!bh)
+		ext3_error(sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
 			    "block_group = %lu, inode_bitmap = %lu",
-			    block_group, (unsigned long) gdp->bg_inode_bitmap);
-		retval = -EIO;
-	}
-	/*
-	 * On IO error, just leave a zero in the superblock's block pointer for
-	 * this group.  The IO will be retried next time.
-	 */
+			    block_group, (unsigned long) desc->bg_inode_bitmap);
 error_out:
-	sb->u.ext3_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
-	sb->u.ext3_sb.s_inode_bitmap[bitmap_nr] = bh;
-	return retval;
-}
-
-/*
- * load_inode_bitmap loads the inode bitmap for a blocks group
- *
- * It maintains a cache for the last bitmaps loaded.  This cache is managed
- * with a LRU algorithm.
- *
- * Notes:
- * 1/ There is one cache per mounted file system.
- * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups,
- *    this function reads the bitmap without maintaining a LRU cache.
- *
- * Return the slot used to store the bitmap, or a -ve error code.
- */
-static int load_inode_bitmap (struct super_block * sb,
-			      unsigned int block_group)
-{
-	struct ext3_sb_info *sbi = EXT3_SB(sb);
-	unsigned long inode_bitmap_number;
-	struct buffer_head * inode_bitmap;
-	int i, j, retval = 0;
-
-	if (block_group >= sbi->s_groups_count)
-		ext3_panic (sb, "load_inode_bitmap",
-			    "block_group >= groups_count - "
-			    "block_group = %d, groups_count = %lu",
-			    block_group, sbi->s_groups_count);
-	if (sbi->s_loaded_inode_bitmaps > 0 &&
-	    sbi->s_inode_bitmap_number[0] == block_group &&
-	    sbi->s_inode_bitmap[0] != NULL)
-		return 0;
-	if (sbi->s_groups_count <= EXT3_MAX_GROUP_LOADED) {
-		if (sbi->s_inode_bitmap[block_group]) {
-			if (sbi->s_inode_bitmap_number[block_group] !=
-						block_group)
-				ext3_panic(sb, "load_inode_bitmap",
-					"block_group != inode_bitmap_number");
-			return block_group;
-		}
-		retval = read_inode_bitmap(sb, block_group, block_group);
-		if (retval < 0)
-			return retval;
-		return block_group;
-	}
-
-	for (i = 0; i < sbi->s_loaded_inode_bitmaps &&
-		    sbi->s_inode_bitmap_number[i] != block_group; i++)
-		/* do nothing */;
-	if (i < sbi->s_loaded_inode_bitmaps &&
-	    sbi->s_inode_bitmap_number[i] == block_group) {
-		inode_bitmap_number = sbi->s_inode_bitmap_number[i];
-		inode_bitmap = sbi->s_inode_bitmap[i];
-		for (j = i; j > 0; j--) {
-			sbi->s_inode_bitmap_number[j] =
-				sbi->s_inode_bitmap_number[j - 1];
-			sbi->s_inode_bitmap[j] = sbi->s_inode_bitmap[j - 1];
-		}
-		sbi->s_inode_bitmap_number[0] = inode_bitmap_number;
-		sbi->s_inode_bitmap[0] = inode_bitmap;
-
-		/*
-		 * There's still one special case here --- if inode_bitmap == 0
-		 * then our last attempt to read the bitmap failed and we have
-		 * just ended up caching that failure.  Try again to read it.
-		 */
-		if (!inode_bitmap)
-			retval = read_inode_bitmap (sb, block_group, 0);
-	} else {
-		if (sbi->s_loaded_inode_bitmaps < EXT3_MAX_GROUP_LOADED)
-			sbi->s_loaded_inode_bitmaps++;
-		else
-			brelse(sbi->s_inode_bitmap[EXT3_MAX_GROUP_LOADED - 1]);
-		for (j = sbi->s_loaded_inode_bitmaps - 1; j > 0; j--) {
-			sbi->s_inode_bitmap_number[j] =
-				sbi->s_inode_bitmap_number[j - 1];
-			sbi->s_inode_bitmap[j] = sbi->s_inode_bitmap[j - 1];
-		}
-		retval = read_inode_bitmap (sb, block_group, 0);
-	}
-	return retval;
+	return bh;
 }
 
 /*
@@ -180,11 +87,10 @@
 	struct super_block * sb = inode->i_sb;
 	int is_directory;
 	unsigned long ino;
-	struct buffer_head * bh;
-	struct buffer_head * bh2;
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *bh2;
 	unsigned long block_group;
 	unsigned long bit;
-	int bitmap_nr;
 	struct ext3_group_desc * gdp;
 	struct ext3_super_block * es;
 	int fatal = 0, err;
@@ -229,19 +135,17 @@
 	}
 	block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
 	bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb);
-	bitmap_nr = load_inode_bitmap (sb, block_group);
-	if (bitmap_nr < 0)
+	bitmap_bh = read_inode_bitmap(sb, block_group);
+	if (!bitmap_bh)
 		goto error_return;
 
-	bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
-
-	BUFFER_TRACE(bh, "get_write_access");
-	fatal = ext3_journal_get_write_access(handle, bh);
+	BUFFER_TRACE(bitmap_bh, "get_write_access");
+	fatal = ext3_journal_get_write_access(handle, bitmap_bh);
 	if (fatal)
 		goto error_return;
 
 	/* Ok, now we can actually update the inode bitmaps.. */
-	if (!ext3_clear_bit (bit, bh->b_data))
+	if (!ext3_clear_bit(bit, bitmap_bh->b_data))
 		ext3_error (sb, "ext3_free_inode",
 			      "bit already cleared for inode %lu", ino);
 	else {
@@ -272,12 +176,13 @@
 		err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
 		if (!fatal) fatal = err;
 	}
-	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
-	err = ext3_journal_dirty_metadata(handle, bh);
+	BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata");
+	err = ext3_journal_dirty_metadata(handle, bitmap_bh);
 	if (!fatal)
 		fatal = err;
 	sb->s_dirt = 1;
 error_return:
+	brelse(bitmap_bh);
 	ext3_std_error(sb, fatal);
 	unlock_super(sb);
 }
@@ -292,20 +197,19 @@
  * For other inodes, search forward from the parent directory's block
  * group to find a free inode.
  */
-struct inode * ext3_new_inode (handle_t *handle,
-				struct inode * dir, int mode)
+struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
 {
-	struct super_block * sb;
-	struct buffer_head * bh;
-	struct buffer_head * bh2;
+	struct super_block *sb;
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *bh2;
 	int i, j, avefreei;
 	struct inode * inode;
-	int bitmap_nr;
 	struct ext3_group_desc * gdp;
 	struct ext3_group_desc * tmp;
 	struct ext3_super_block * es;
 	struct ext3_inode_info *ei;
 	int err = 0;
+	struct inode *ret;
 
 	/* Cannot create files in a deleted directory */
 	if (!dir || !dir->i_nlink)
@@ -392,26 +296,25 @@
 		goto out;
 
 	err = -EIO;
-	bitmap_nr = load_inode_bitmap (sb, i);
-	if (bitmap_nr < 0)
+	brelse(bitmap_bh);
+	bitmap_bh = read_inode_bitmap(sb, i);
+	if (!bitmap_bh)
 		goto fail;
 
-	bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
-
-	if ((j = ext3_find_first_zero_bit ((unsigned long *) bh->b_data,
+	if ((j = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data,
 				      EXT3_INODES_PER_GROUP(sb))) <
 	    EXT3_INODES_PER_GROUP(sb)) {
-		BUFFER_TRACE(bh, "get_write_access");
-		err = ext3_journal_get_write_access(handle, bh);
+		BUFFER_TRACE(bitmap_bh, "get_write_access");
+		err = ext3_journal_get_write_access(handle, bitmap_bh);
 		if (err) goto fail;
 		
-		if (ext3_set_bit (j, bh->b_data)) {
+		if (ext3_set_bit(j, bitmap_bh->b_data)) {
 			ext3_error (sb, "ext3_new_inode",
 				      "bit already set for inode %d", j);
 			goto repeat;
 		}
-		BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
-		err = ext3_journal_dirty_metadata(handle, bh);
+		BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata");
+		err = ext3_journal_dirty_metadata(handle, bitmap_bh);
 		if (err) goto fail;
 	} else {
 		if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
@@ -520,23 +423,27 @@
 	err = ext3_mark_inode_dirty(handle, inode);
 	if (err) goto fail;
 	
-	unlock_super (sb);
+	unlock_super(sb);
+	ret = inode;
 	if(DQUOT_ALLOC_INODE(inode)) {
 		DQUOT_DROP(inode);
 		inode->i_flags |= S_NOQUOTA;
 		inode->i_nlink = 0;
 		iput(inode);
-		return ERR_PTR(-EDQUOT);
+		ret = ERR_PTR(-EDQUOT);
+	} else {
+		ext3_debug("allocating inode %lu\n", inode->i_ino);
 	}
-	ext3_debug ("allocating inode %lu\n", inode->i_ino);
-	return inode;
-
+	goto really_out;
 fail:
 	ext3_std_error(sb, err);
 out:
 	unlock_super(sb);
 	iput(inode);
-	return ERR_PTR(err);
+	ret = ERR_PTR(err);
+really_out:
+	brelse(bitmap_bh);
+	return ret;
 }
 
 /* Verify that we are loading a valid orphan from disk */
@@ -545,36 +452,37 @@
 	ino_t max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
 	unsigned long block_group;
 	int bit;
-	int bitmap_nr;
-	struct buffer_head *bh;
+	struct buffer_head *bitmap_bh = NULL;
 	struct inode *inode = NULL;
 	
 	/* Error cases - e2fsck has already cleaned up for us */
 	if (ino > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
 			     "bad orphan ino %ld!  e2fsck was run?\n", ino);
-		return NULL;
+		goto out;
 	}
 
 	block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
 	bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb);
-	if ((bitmap_nr = load_inode_bitmap(sb, block_group)) < 0 ||
-	    !(bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr])) {
+	bitmap_bh = read_inode_bitmap(sb, block_group);
+	if (!bitmap_bh) {
 		ext3_warning(sb, __FUNCTION__,
 			     "inode bitmap error for orphan %ld\n", ino);
-		return NULL;
+		goto out;
 	}
 
 	/* Having the inode bit set should be a 100% indicator that this
 	 * is a valid orphan (no e2fsck run on fs).  Orphans also include
 	 * inodes that were being truncated, so we can't check i_nlink==0.
 	 */
-	if (!ext3_test_bit(bit, bh->b_data) || !(inode = iget(sb, ino)) ||
-	    is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) {
+	if (!ext3_test_bit(bit, bitmap_bh->b_data) ||
+			!(inode = iget(sb, ino)) || is_bad_inode(inode) ||
+			NEXT_ORPHAN(inode) > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
 			     "bad orphan inode %ld!  e2fsck was run?\n", ino);
 		printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%ld) = %d\n",
-		       bit, bh->b_blocknr, ext3_test_bit(bit, bh->b_data));
+			bit, bitmap_bh->b_blocknr,
+			ext3_test_bit(bit, bitmap_bh->b_data));
 		printk(KERN_NOTICE "inode=%p\n", inode);
 		if (inode) {
 			printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
@@ -587,19 +495,20 @@
 		if (inode && inode->i_nlink == 0)
 			inode->i_blocks = 0;
 		iput(inode);
-		return NULL;
+		inode = NULL;
 	}
-
+out:
+	brelse(bitmap_bh);
 	return inode;
 }
 
 unsigned long ext3_count_free_inodes (struct super_block * sb)
 {
 #ifdef EXT3FS_DEBUG
-	struct ext3_super_block * es;
+	struct ext3_super_block *es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
-	struct ext3_group_desc * gdp;
+	struct ext3_group_desc *gdp;
+	struct buffer_head *bitmap_bh = NULL;
 	int i;
 
 	lock_super (sb);
@@ -612,19 +521,20 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-		bitmap_nr = load_inode_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		brelse(bitmap_bh);
+		bitmap_bh = read_inode_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 
-		x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr],
-				     EXT3_INODES_PER_GROUP(sb) / 8);
-		printk ("group %d: stored = %d, counted = %lu\n",
+		x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8);
+		printk("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(gdp->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	printk("ext3_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
 		le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
-	unlock_super (sb);
+	unlock_super(sb);
 	return desc_count;
 #else
 	return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_inodes_count);
@@ -637,7 +547,7 @@
 {
 	struct ext3_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
+	struct buffer_head *bitmap_bh = NULL;
 	struct ext3_group_desc * gdp;
 	int i;
 
@@ -650,12 +560,12 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-		bitmap_nr = load_inode_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		brelse(bitmap_bh);
+		bitmap_bh = read_inode_bitmap(sb, i);
+		if (!bitmap_bh)
 			continue;
 
-		x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr],
-				     EXT3_INODES_PER_GROUP(sb) / 8);
+		x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8);
 		if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
 			ext3_error (sb, "ext3_check_inodes_bitmap",
 				    "Wrong free inodes count in group %d, "
@@ -663,6 +573,7 @@
 				    le16_to_cpu(gdp->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
+	brelse(bitmap_bh);
 	if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
 		ext3_error (sb, "ext3_check_inodes_bitmap",
 			    "Wrong free inodes count in super block, "
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ext3/inode.c	Fri Jul  5 16:43:00 2002
@@ -1632,8 +1632,10 @@
 		}
 		ext3_mark_inode_dirty(handle, inode);
 		ext3_journal_test_restart(handle, inode);
-		BUFFER_TRACE(bh, "get_write_access");
-		ext3_journal_get_write_access(handle, bh);
+		if (bh) {
+			BUFFER_TRACE(bh, "retaking write access");
+			ext3_journal_get_write_access(handle, bh);
+		}
 	}
 
 	/*
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ext3/super.c	Fri Jul  5 16:43:00 2002
@@ -417,10 +417,6 @@
 	for (i = 0; i < sbi->s_gdb_count; i++)
 		brelse(sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
-	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
-		brelse(sbi->s_inode_bitmap[i]);
-	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
-		brelse(sbi->s_block_bitmap[i]);
 	brelse(sbi->s_sbh);
 
 	/* Debugging code just in case the in-memory inode orphan list
@@ -504,7 +500,7 @@
 	write_super:	ext3_write_super,	/* BKL not held. We take it. Needed? */
 	write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */
 	unlockfs:	ext3_unlockfs,		/* BKL not held.  We take it */
-	statfs:		ext3_statfs,		/* BKL held */
+	statfs:		ext3_statfs,		/* BKL not held. */
 	remount_fs:	ext3_remount,		/* BKL held */
 };
 
@@ -1150,14 +1146,6 @@
 		printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
 		goto failed_mount2;
 	}
-	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) {
-		sbi->s_inode_bitmap_number[i] = 0;
-		sbi->s_inode_bitmap[i] = NULL;
-		sbi->s_block_bitmap_number[i] = 0;
-		sbi->s_block_bitmap[i] = NULL;
-	}
-	sbi->s_loaded_inode_bitmaps = 0;
-	sbi->s_loaded_block_bitmaps = 0;
 	sbi->s_gdb_count = db_count;
 	/*
 	 * set up enough so that it can read an inode
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Fri Jul  5 16:42:56 2002
+++ b/fs/fcntl.c	Fri Jul  5 16:42:56 2002
@@ -245,6 +245,11 @@
 	}
 
 	if (arg & O_DIRECT) {
+		if (inode->i_mapping && inode->i_mapping->a_ops) {
+			if (!inode->i_mapping->a_ops->direct_IO)
+				return -EINVAL;
+		}
+
 		/*
 		 * alloc_kiovec() can sleep and we are only serialized by
 		 * the big kernel lock here, so abuse the i_sem to serialize
diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
--- a/fs/freevxfs/vxfs_super.c	Fri Jul  5 16:42:59 2002
+++ b/fs/freevxfs/vxfs_super.c	Fri Jul  5 16:42:59 2002
@@ -98,7 +98,7 @@
  *   Zero.
  *
  * Locking:
- *   We are under bkl and @sbp->s_lock.
+ *   No locks held.
  *
  * Notes:
  *   This is everything but complete...
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Fri Jul  5 16:43:00 2002
+++ b/fs/fs-writeback.c	Fri Jul  5 16:43:00 2002
@@ -220,8 +220,7 @@
 	struct list_head *head;
 	const unsigned long start = jiffies;	/* livelock avoidance */
 
-	list_splice(&sb->s_dirty, &sb->s_io);
-	INIT_LIST_HEAD(&sb->s_dirty);
+	list_splice_init(&sb->s_dirty, &sb->s_io);
 	head = &sb->s_io;
 	while ((tmp = head->prev) != head) {
 		struct inode *inode = list_entry(tmp, struct inode, i_list);
@@ -262,13 +261,10 @@
 			break;
 	}
 out:
-	if (!list_empty(&sb->s_io)) {
-		/*
-		 * Put the rest back, in the correct order.
-		 */
-		list_splice(&sb->s_io, sb->s_dirty.prev);
-		INIT_LIST_HEAD(&sb->s_io);
-	}
+	/*
+	 * Put the rest back, in the correct order.
+	 */
+	list_splice_init(&sb->s_io, sb->s_dirty.prev);
 	return;
 }
 
@@ -287,8 +283,9 @@
  *
  * This is a "memory cleansing" operation, not a "data integrity" operation.
  */
-void writeback_unlocked_inodes(int *nr_to_write, int sync_mode,
-				unsigned long *older_than_this)
+void writeback_unlocked_inodes(int *nr_to_write,
+			       enum writeback_sync_modes sync_mode,
+			       unsigned long *older_than_this)
 {
 	struct super_block *sb;
 
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Fri Jul  5 16:43:00 2002
+++ b/fs/hpfs/super.c	Fri Jul  5 16:43:00 2002
@@ -134,6 +134,8 @@
 
 int hpfs_statfs(struct super_block *s, struct statfs *buf)
 {
+	lock_kernel();
+
 	/*if (s->s_hpfs_n_free == -1) {*/
 		s->s_hpfs_n_free = count_bitmaps(s);
 		s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
@@ -146,6 +148,9 @@
 	buf->f_files = s->s_hpfs_dirband_size / 4;
 	buf->f_ffree = s->s_hpfs_n_free_dnodes;
 	buf->f_namelen = 254;
+
+	unlock_kernel();
+
 	return 0;
 }
 
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Fri Jul  5 16:43:00 2002
+++ b/fs/inode.c	Fri Jul  5 16:43:00 2002
@@ -101,7 +101,7 @@
 		struct address_space * const mapping = &inode->i_data;
 
 		inode->i_sb = sb;
-		inode->i_dev = to_kdev_t(sb->s_dev);
+		inode->i_dev = sb->s_dev;
 		inode->i_blkbits = sb->s_blocksize_bits;
 		inode->i_flags = 0;
 		atomic_set(&inode->i_count, 1);
diff -Nru a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
--- a/fs/jbd/checkpoint.c	Fri Jul  5 16:42:59 2002
+++ b/fs/jbd/checkpoint.c	Fri Jul  5 16:42:59 2002
@@ -592,7 +592,8 @@
 	J_ASSERT (transaction->t_log_list == NULL);
 	J_ASSERT (transaction->t_checkpoint_list == NULL);
 	J_ASSERT (transaction->t_updates == 0);
-	
+	J_ASSERT (list_empty(&transaction->t_jcb));
+
 	J_ASSERT (transaction->t_journal->j_committing_transaction !=
 					transaction);
 	
diff -Nru a/fs/jbd/commit.c b/fs/jbd/commit.c
--- a/fs/jbd/commit.c	Fri Jul  5 16:42:59 2002
+++ b/fs/jbd/commit.c	Fri Jul  5 16:42:59 2002
@@ -471,7 +471,7 @@
            transaction's t_log_list queue, and metadata buffers are on
            the t_iobuf_list queue.
 
-	   Wait for the transactions in reverse order.  That way we are
+	   Wait for the buffers in reverse order.  That way we are
 	   less likely to be woken up until all IOs have completed, and
 	   so we incur less scheduling load.
 	*/
@@ -563,8 +563,10 @@
 
 	jbd_debug(3, "JBD: commit phase 6\n");
 
-	if (is_journal_aborted(journal))
+	if (is_journal_aborted(journal)) {
+		unlock_journal(journal);
 		goto skip_commit;
+	}
 
 	/* Done it all: now write the commit record.  We should have
 	 * cleaned up our previous buffers by now, so if we are in abort
@@ -574,9 +576,10 @@
 	descriptor = journal_get_descriptor_buffer(journal);
 	if (!descriptor) {
 		__journal_abort_hard(journal);
+		unlock_journal(journal);
 		goto skip_commit;
 	}
-	
+
 	/* AKPM: buglet - add `i' to tmp! */
 	for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) {
 		journal_header_t *tmp =
@@ -596,14 +599,32 @@
 		__brelse(bh);		/* One for getblk() */
 		journal_unlock_journal_head(descriptor);
 	}
-	lock_journal(journal);
 
 	/* End of a transaction!  Finally, we can do checkpoint
            processing: any buffers committed as a result of this
            transaction can be removed from any checkpoint list it was on
            before. */
 
-skip_commit:
+skip_commit: /* The journal should be unlocked by now. */
+
+	/* Call any callbacks that had been registered for handles in this
+	 * transaction.  It is up to the callback to free any allocated
+	 * memory.
+	 */
+	if (!list_empty(&commit_transaction->t_jcb)) {
+		struct list_head *p, *n;
+		int error = is_journal_aborted(journal);
+
+		list_for_each_safe(p, n, &commit_transaction->t_jcb) {
+			struct journal_callback *jcb;
+
+			jcb = list_entry(p, struct journal_callback, jcb_list);
+			list_del(p);
+			jcb->jcb_func(jcb, error);
+		}
+	}
+
+	lock_journal(journal);
 
 	jbd_debug(3, "JBD: commit phase 7\n");
 
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Fri Jul  5 16:42:59 2002
+++ b/fs/jbd/journal.c	Fri Jul  5 16:42:59 2002
@@ -58,6 +58,7 @@
 #endif
 EXPORT_SYMBOL(journal_flush);
 EXPORT_SYMBOL(journal_revoke);
+EXPORT_SYMBOL(journal_callback_set);
 
 EXPORT_SYMBOL(journal_init_dev);
 EXPORT_SYMBOL(journal_init_inode);
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c	Fri Jul  5 16:42:59 2002
+++ b/fs/jbd/transaction.c	Fri Jul  5 16:42:59 2002
@@ -57,6 +57,7 @@
 	transaction->t_state = T_RUNNING;
 	transaction->t_tid = journal->j_transaction_sequence++;
 	transaction->t_expires = jiffies + journal->j_commit_interval;
+	INIT_LIST_HEAD(&transaction->t_jcb);
 
 	/* Set up the commit timer for the new transaction. */
 	J_ASSERT (!journal->j_commit_timer_active);
@@ -90,7 +91,14 @@
 	transaction_t *transaction;
 	int needed;
 	int nblocks = handle->h_buffer_credits;
-	
+
+	if (nblocks > journal->j_max_transaction_buffers) {
+		printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
+		       current->comm, nblocks,
+		       journal->j_max_transaction_buffers);
+		return -ENOSPC;
+	}
+
 	jbd_debug(3, "New handle %p going live.\n", handle);
 
 repeat:
@@ -200,6 +208,20 @@
 	return 0;
 }
 
+/* Allocate a new handle.  This should probably be in a slab... */
+static handle_t *new_handle(int nblocks)
+{
+	handle_t *handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+	if (!handle)
+		return NULL;
+	memset(handle, 0, sizeof (handle_t));
+	handle->h_buffer_credits = nblocks;
+	handle->h_ref = 1;
+	INIT_LIST_HEAD(&handle->h_jcb);
+
+	return handle;
+}
+
 /*
  * Obtain a new handle.  
  *
@@ -226,14 +248,11 @@
 		handle->h_ref++;
 		return handle;
 	}
-	
-	handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+
+	handle = new_handle(nblocks);
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
-	memset (handle, 0, sizeof (handle_t));
 
-	handle->h_buffer_credits = nblocks;
-	handle->h_ref = 1;
 	current->journal_info = handle;
 
 	err = start_this_handle(journal, handle);
@@ -332,14 +351,11 @@
 	
 	if (is_journal_aborted(journal))
 		return ERR_PTR(-EIO);
-	
-	handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS);
+
+	handle = new_handle(nblocks);
 	if (!handle)
 		return ERR_PTR(-ENOMEM);
-	memset (handle, 0, sizeof (handle_t));
 
-	handle->h_buffer_credits = nblocks;
-	handle->h_ref = 1;
 	current->journal_info = handle;
 
 	err = try_start_this_handle(journal, handle);
@@ -1348,6 +1364,28 @@
 #endif
 
 /*
+ * Register a callback function for this handle.  The function will be
+ * called when the transaction that this handle is part of has been
+ * committed to disk with the original callback data struct and the
+ * error status of the journal as parameters.  There is no guarantee of
+ * ordering between handles within a single transaction, nor between
+ * callbacks registered on the same handle.
+ *
+ * The caller is responsible for allocating the journal_callback struct.
+ * This is to allow the caller to add as much extra data to the callback
+ * as needed, but reduce the overhead of multiple allocations.  The caller
+ * allocated struct must start with a struct journal_callback at offset 0,
+ * and has the caller-specific data afterwards.
+ */
+void journal_callback_set(handle_t *handle,
+			  void (*func)(struct journal_callback *jcb, int error),
+			  struct journal_callback *jcb)
+{
+	list_add_tail(&jcb->jcb_list, &handle->h_jcb);
+	jcb->jcb_func = func;
+}
+
+/*
  * All done for a particular handle.
  *
  * There is not much action needed here.  We just return any remaining
@@ -1411,7 +1449,10 @@
 			wake_up(&journal->j_wait_transaction_locked);
 	}
 
-	/* 
+	/* Move callbacks from the handle to the transaction. */
+	list_splice(&handle->h_jcb, &transaction->t_jcb);
+
+	/*
 	 * If the handle is marked SYNC, we need to set another commit
 	 * going!  We also want to force a commit if the current
 	 * transaction is occupying too much of the log, or if the
diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c	Fri Jul  5 16:43:00 2002
+++ b/fs/jffs/inode-v23.c	Fri Jul  5 16:43:00 2002
@@ -383,7 +383,11 @@
 jffs_statfs(struct super_block *sb, struct statfs *buf)
 {
 	struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
-	struct jffs_fmcontrol *fmc = c->fmc;
+	struct jffs_fmcontrol *fmc;
+
+	lock_kernel();
+
+	fmc = c->fmc;
 
 	D2(printk("jffs_statfs()\n"));
 
@@ -401,6 +405,9 @@
 	buf->f_ffree = buf->f_bfree;
 	/* buf->f_fsid = 0; */
 	buf->f_namelen = JFFS_MAX_NAME_LEN;
+
+	unlock_kernel();
+
 	return 0;
 }
 
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	Fri Jul  5 16:42:56 2002
+++ b/fs/jfs/jfs_incore.h	Fri Jul  5 16:42:56 2002
@@ -122,7 +122,7 @@
 	short		nbperpage;	/* 2: blocks per page		*/
 	short		l2nbperpage;	/* 2: log2 blocks per page	*/
 	short		l2niperblk;	/* 2: log2 inodes per page	*/
-	kdev_t		logdev;		/* 2: external log device	*/
+	u32		logdev;		/* 2: external log device	*/
 	uint		aggregate;	/* volume identifier in log record */
 	pxd_t		logpxd;		/* 8: pxd describing log	*/
 	pxd_t		ait2;		/* 8: pxd describing AIT copy	*/
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Fri Jul  5 16:43:00 2002
+++ b/fs/jfs/jfs_logmgr.c	Fri Jul  5 16:43:00 2002
@@ -1102,7 +1102,7 @@
 	 */
       externalLog:
 
-	if (!(bdev = bdget(kdev_t_to_nr(JFS_SBI(sb)->logdev)))) {
+	if (!(bdev = bdget(JFS_SBI(sb)->logdev))) {
 		rc = ENODEV;
 		goto free;
 	}
diff -Nru a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
--- a/fs/jfs/jfs_mount.c	Fri Jul  5 16:42:59 2002
+++ b/fs/jfs/jfs_mount.c	Fri Jul  5 16:42:59 2002
@@ -406,7 +406,7 @@
 	if (sbi->mntflag & JFS_INLINELOG)
 		sbi->logpxd = j_sb->s_logpxd;
 	else {
-		sbi->logdev = to_kdev_t(le32_to_cpu(j_sb->s_logdev));
+		sbi->logdev = le32_to_cpu(j_sb->s_logdev);
 		memcpy(sbi->uuid, j_sb->s_uuid, sizeof(sbi->uuid));
 		memcpy(sbi->loguuid, j_sb->s_loguuid, sizeof(sbi->uuid));
 	}
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Fri Jul  5 16:42:53 2002
+++ b/fs/jfs/jfs_txnmgr.c	Fri Jul  5 16:42:53 2002
@@ -2975,10 +2975,7 @@
 			}
 		}
 		/* Add anon_list2 back to anon_list */
-		if (!list_empty(&TxAnchor.anon_list2)) {
-			list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list);
-			INIT_LIST_HEAD(&TxAnchor.anon_list2);
-		}
+		list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
 		add_wait_queue(&jfs_sync_thread_wait, &wq);
 		set_current_state(TASK_INTERRUPTIBLE);
 		TXN_UNLOCK();
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Fri Jul  5 16:42:50 2002
+++ b/fs/libfs.c	Fri Jul  5 16:42:50 2002
@@ -83,6 +83,12 @@
 	return offset;
 }
 
+/* Relationship between i_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct inode *inode)
+{
+	return (inode->i_mode >> 12) & 15;
+}
+
 /*
  * Directory is locked and all positive dentries in it are safe, since
  * for ramfs-type trees they can't go away without unlink() or rmdir(),
@@ -125,7 +131,7 @@
 					continue;
 
 				spin_unlock(&dcache_lock);
-				if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, DT_UNKNOWN) < 0)
+				if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
 					return 0;
 				spin_lock(&dcache_lock);
 				/* next is still alive */
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Fri Jul  5 16:43:00 2002
+++ b/fs/locks.c	Fri Jul  5 16:43:00 2002
@@ -1751,9 +1751,12 @@
 			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
 			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
 	}
+	/*
+	 *	NOTE: it should be inode->i_sb->s_id, not kdevname(...).
+	 */
 	out += sprintf(out, "%d %s:%ld ",
 		     fl->fl_pid,
-		     inode ? kdevname(inode->i_dev) : "<none>",
+		     inode ? kdevname(to_kdev_t(inode->i_dev)) : "<none>",
 		     inode ? inode->i_ino : 0);
 	out += sprintf(out, "%Ld ", fl->fl_start);
 	if (fl->fl_end == OFFSET_MAX)
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Fri Jul  5 16:42:59 2002
+++ b/fs/mpage.c	Fri Jul  5 16:42:59 2002
@@ -431,7 +431,7 @@
 		unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE;
 
 		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
-					nr_bvecs, GFP_NOFS);
+					nr_bvecs, GFP_NOFS|__GFP_HIGH);
 		if (bio == NULL)
 			goto confused;
 	}
@@ -475,9 +475,44 @@
 	return bio;
 }
 
-/*
- * This is a cut-n-paste of generic_writepages().  We _could_
- * generalise that function.  It'd get a bit messy.  We'll see.
+/**
+ * mpage_writepages - walk the list of dirty pages of the given
+ * address space and writepage() all of them.
+ * 
+ * @mapping: address space structure to write
+ * @nr_to_write: subtract the number of written pages from *@nr_to_write
+ * @get_block: the filesystem's block mapper function.
+ *             If this is NULL then use a_ops->writepage.  Otherwise, go
+ *             direct-to-BIO.
+ *
+ * This is a library function, which implements the writepages()
+ * address_space_operation.
+ *
+ * (The next two paragraphs refer to code which isn't here yet, but they
+ *  explain the presence of address_space.io_pages)
+ *
+ * Pages can be moved from clean_pages or locked_pages onto dirty_pages
+ * at any time - it's not possible to lock against that.  So pages which
+ * have already been added to a BIO may magically reappear on the dirty_pages
+ * list.  And generic_writepages() will again try to lock those pages.
+ * But I/O has not yet been started against the page.  Thus deadlock.
+ *
+ * To avoid this, the entire contents of the dirty_pages list are moved
+ * onto io_pages up-front.  We then walk io_pages, locking the
+ * pages and submitting them for I/O, moving them to locked_pages.
+ *
+ * This has the added benefit of preventing a livelock which would otherwise
+ * occur if pages are being dirtied faster than we can write them out.
+ *
+ * If a page is already under I/O, generic_writepages() skips it, even
+ * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
+ * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
+ * and msync() need to guarentee that all the data which was dirty at the time
+ * the call was made get new I/O started against them.  The way to do this is
+ * to run filemap_fdatawait() before calling filemap_fdatawrite().
+ *
+ * It's fairly rare for PageWriteback pages to be on ->dirty_pages.  It
+ * means that someone redirtied the page while it was under I/O.
  */
 int
 mpage_writepages(struct address_space *mapping,
@@ -487,11 +522,15 @@
 	sector_t last_block_in_bio = 0;
 	int ret = 0;
 	int done = 0;
+	int (*writepage)(struct page *);
+
+	writepage = NULL;
+	if (get_block == NULL)
+		writepage = mapping->a_ops->writepage;
 
 	write_lock(&mapping->page_lock);
 
-	list_splice(&mapping->dirty_pages, &mapping->io_pages);
-	INIT_LIST_HEAD(&mapping->dirty_pages);
+	list_splice_init(&mapping->dirty_pages, &mapping->io_pages);
 
         while (!list_empty(&mapping->io_pages) && !done) {
 		struct page *page = list_entry(mapping->io_pages.prev,
@@ -516,8 +555,8 @@
 
 		lock_page(page);
 
-		if (page->mapping && TestClearPageDirty(page) &&
-					!PageWriteback(page)) {
+		if (page->mapping && !PageWriteback(page) &&
+					TestClearPageDirty(page)) {
 			/* FIXME: batch this up */
 			if (!PageActive(page) && PageLRU(page)) {
 				spin_lock(&pagemap_lru_lock);
@@ -527,8 +566,13 @@
 				}
 				spin_unlock(&pagemap_lru_lock);
 			}
-			bio = mpage_writepage(bio, page, get_block,
-					&last_block_in_bio, &ret);
+
+			if (writepage) {
+				ret = (*writepage)(page);
+			} else {
+				bio = mpage_writepage(bio, page, get_block,
+						&last_block_in_bio, &ret);
+			}
 			if (ret || (nr_to_write && --(*nr_to_write) <= 0))
 				done = 1;
 		} else {
@@ -538,13 +582,10 @@
 		page_cache_release(page);
 		write_lock(&mapping->page_lock);
 	}
-	if (!list_empty(&mapping->io_pages)) {
-		/*
-		 * Put the rest back, in the correct order.
-		 */
-		list_splice(&mapping->io_pages, mapping->dirty_pages.prev);
-		INIT_LIST_HEAD(&mapping->io_pages);
-	}
+	/*
+	 * Put the rest back, in the correct order.
+	 */
+	list_splice_init(&mapping->io_pages, mapping->dirty_pages.prev);
 	write_unlock(&mapping->page_lock);
 	if (bio)
 		mpage_bio_submit(WRITE, bio);
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Fri Jul  5 16:43:00 2002
+++ b/fs/nfs/inode.c	Fri Jul  5 16:43:00 2002
@@ -474,6 +474,8 @@
 	struct nfs_fsinfo res;
 	int error;
 
+	lock_kernel();
+
 	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
 	buf->f_type = NFS_SUPER_MAGIC;
 	if (error < 0)
@@ -491,11 +493,17 @@
 	if (res.namelen == 0 || res.namelen > server->namelen)
 		res.namelen = server->namelen;
 	buf->f_namelen = res.namelen;
+
+ out:
+	unlock_kernel();
+
 	return 0;
+
  out_err:
-	printk("nfs_statfs: statfs error = %d\n", -error);
+	printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error);
 	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
-	return 0;
+	goto out;
+
 }
 
 static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Fri Jul  5 16:42:59 2002
+++ b/fs/nfs/write.c	Fri Jul  5 16:42:59 2002
@@ -1110,8 +1110,7 @@
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	list_splice(head, &data->pages);
-	INIT_LIST_HEAD(head);
+	list_splice_init(head, &data->pages);
 	first = nfs_list_entry(data->pages.next);
 	last = nfs_list_entry(data->pages.prev);
 	inode = first->wb_inode;
diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c	Fri Jul  5 16:43:00 2002
+++ b/fs/nfsd/export.c	Fri Jul  5 16:43:00 2002
@@ -68,17 +68,17 @@
  * Find the client's export entry matching xdev/xino.
  */
 svc_export *
-exp_get(svc_client *clp, kdev_t dev, ino_t ino)
+exp_get(svc_client *clp, dev_t dev, ino_t ino)
 {
 	struct list_head *head, *p;
 	
 	if (!clp)
 		return NULL;
 
-	head = &clp->cl_export[EXPORT_HASH(kdev_t_to_nr(dev))];
+	head = &clp->cl_export[EXPORT_HASH(dev)];
 	list_for_each(p, head) {
 		svc_export *exp = list_entry(p, svc_export, ex_hash);
-		if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
+		if (exp->ex_ino == ino && exp->ex_dev ==  dev)
 			return exp;
 	}
 	return NULL;
@@ -250,7 +250,7 @@
 	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		err;
-	kdev_t		dev;
+	dev_t		dev;
 	ino_t		ino;
 
 	/* Consistency check */
@@ -276,7 +276,7 @@
 	if (err)
 		goto out_unlock;
 	inode = nd.dentry->d_inode;
-	dev = inode->i_dev;
+	dev = inode->i_sb->s_dev;
 	ino = inode->i_ino;
 	err = -EINVAL;
 
@@ -364,7 +364,7 @@
 	if (parent)
 		exp_change_parents(clp, parent, exp);
 
-	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(kdev_t_to_nr(dev)));
+	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
 	list_add_tail(&exp->ex_list, &clp->cl_list);
 
 	exp_fsid_hash(clp, exp);
@@ -398,7 +398,7 @@
 	dentry = unexp->ex_dentry;
 	mnt = unexp->ex_mnt;
 	inode = dentry->d_inode;
-	if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino)
+	if (unexp->ex_dev != inode->i_sb->s_dev || unexp->ex_ino != inode->i_ino)
 		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
 	dput(dentry);
 	mntput(mnt);
@@ -440,8 +440,7 @@
 	err = -EINVAL;
 	clp = exp_getclientbyname(nxp->ex_client);
 	if (clp) {
-		kdev_t ex_dev = to_kdev_t(nxp->ex_dev);
-		svc_export *exp = exp_get(clp, ex_dev, nxp->ex_ino);
+		svc_export *exp = exp_get(clp, nxp->ex_dev, nxp->ex_ino);
 		if (exp) {
 			exp_do_unexport(exp);
 			err = 0;
diff -Nru a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
--- a/fs/nfsd/nfs3xdr.c	Fri Jul  5 16:42:41 2002
+++ b/fs/nfsd/nfs3xdr.c	Fri Jul  5 16:42:41 2002
@@ -219,7 +219,7 @@
 	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
 		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
 	else
-		p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev));
+		p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c	Fri Jul  5 16:42:59 2002
+++ b/fs/nfsd/nfsfh.c	Fri Jul  5 16:42:59 2002
@@ -97,7 +97,7 @@
 	rqstp->rq_reffh = fh;
 
 	if (!fhp->fh_dentry) {
-		kdev_t xdev = NODEV;
+		dev_t xdev = 0;
 		ino_t xino = 0;
 		__u32 *datap=NULL;
 		__u32 tfh[3];		/* filehandle fragment for oldstyle filehandles */
@@ -122,7 +122,7 @@
 			case 0:
 				if ((data_left-=2)<0) goto out;
 				nfsdev = ntohl(*datap++);
-				xdev = mk_kdev(nfsdev>>16, nfsdev&0xFFFF);
+				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
 				xino = *datap++;
 				break;
 			case 1:
@@ -136,7 +136,7 @@
 			if (fh->fh_size != NFS_FHSIZE)
 				goto out;
 			/* assume old filehandle format */
-			xdev = u32_to_kdev_t(fh->ofh_xdev);
+			xdev = u32_to_dev_t(fh->ofh_xdev);
 			xino = u32_to_ino_t(fh->ofh_xino);
 		}
 
@@ -308,7 +308,7 @@
 	__u32 *datap;
 
 	dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
-		major(exp->ex_dev), minor(exp->ex_dev), (long) exp->ex_ino,
+		MAJOR(exp->ex_dev), MINOR(exp->ex_dev), (long) exp->ex_ino,
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
@@ -329,7 +329,7 @@
 		memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 		fhp->fh_handle.fh_size = NFS_FHSIZE;
 		fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
-		fhp->fh_handle.ofh_dev =  htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
+		fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
 		fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
 		fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
 		fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
@@ -348,7 +348,7 @@
 		} else {
 			fhp->fh_handle.fh_fsid_type = 0;
 			/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-			*datap++ = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
+			*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
 			*datap++ = ino_t_to_u32(exp->ex_ino);
 			fhp->fh_handle.fh_size = 3*4;
 		}
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Fri Jul  5 16:42:59 2002
+++ b/fs/nfsd/vfs.c	Fri Jul  5 16:42:59 2002
@@ -66,7 +66,7 @@
 	struct raparms		*p_next;
 	unsigned int		p_count;
 	ino_t			p_ino;
-	kdev_t			p_dev;
+	dev_t			p_dev;
 	struct file_ra_state	p_ra;
 };
 
@@ -527,14 +527,14 @@
 static spinlock_t ra_lock = SPIN_LOCK_UNLOCKED;
 
 static inline struct raparms *
-nfsd_get_raparms(kdev_t dev, ino_t ino)
+nfsd_get_raparms(dev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 	int depth = 0;
 
 	spin_lock(&ra_lock);
 	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
-		if (ra->p_ino == ino && kdev_same(ra->p_dev, dev))
+		if (ra->p_ino == ino && ra->p_dev == dev)
 			goto found;
 		depth++;
 		if (ra->p_count == 0)
@@ -691,8 +691,8 @@
 	}
 
 	if (err >= 0 && stable) {
-		static unsigned long	last_ino;
-		static kdev_t		last_dev = NODEV;
+		static ino_t	last_ino;
+		static dev_t	last_dev = 0;
 
 		/*
 		 * Gathered writes: If another process is currently
@@ -708,7 +708,7 @@
 		 */
 		if (EX_WGATHER(exp)) {
 			if (atomic_read(&inode->i_writecount) > 1
-			    || (last_ino == inode->i_ino && kdev_same(last_dev, inode->i_dev))) {
+			    || (last_ino == inode->i_ino && last_dev == inode->i_dev)) {
 				dprintk("nfsd: write defer %d\n", current->pid);
 				set_current_state(TASK_UNINTERRUPTIBLE);
 				schedule_timeout((HZ+99)/100);
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Fri Jul  5 16:42:59 2002
+++ b/fs/ntfs/ChangeLog	Fri Jul  5 16:42:59 2002
@@ -6,7 +6,7 @@
 	  user open()s a file with i_size > s_maxbytes? Should read_inode()
 	  truncate the visible i_size? Will the user just get -E2BIG (or
 	  whatever) on open()? Or will (s)he be able to open() but lseek() and
-	  read() will fail when s_maxbytes is reached? -> Investigate this!
+	  read() will fail when s_maxbytes is reached? -> Investigate this.
 	- Implement/allow non-resident index bitmaps in dir.c::ntfs_readdir()
 	  and then also consider initialized_size w.r.t. the bitmaps, etc.
 	- vcn_to_lcn() should somehow return the correct pointer within the
@@ -17,11 +17,78 @@
 	- Consider if ntfs_file_read_compressed_block() shouldn't be coping
 	  with initialized_size < data_size. I don't think it can happen but
 	  it requires more careful consideration.
-	- CLEANUP: Modularise and reuse code in aops.c. At the moment we have
-	  several copies of almost identicall functions and the functions are
-	  quite big. Modularising them a bit, e.g. a-la get_block(), will make
-	  them cleaner and make code reuse easier.
-	- Want to use dummy inodes for address space i/o.
+	- CLEANUP: At the moment we have two copies of almost identical
+	  functions in aops.c, can merge them once fake inode address space
+	  based attribute i/o is further developed.
+	- CLEANUP: Modularising code in aops.c a bit, e.g. a-la get_block(),
+	  will be cleaner and make code reuse easier.
+	- Modify ntfs_read_locked_inode() to return an error code and update
+	  callers, i.e. ntfs_iget(), to pass that error code up instead of just
+	  using -EIO.
+	- Enable NFS exporting of NTFS.
+	- Use fake inodes for address space i/o.
+
+2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
+
+	- Change fs/ntfs/super.c::ntfs_statfs() to not rely on BKL by moving
+	  the locking out of super.c::get_nr_free_mft_records() and taking and
+	  dropping the mftbmp_lock rw_semaphore in ntfs_statfs() itself.
+	- Bring attribute run list merging code (fs/ntfs/attrib.c) in sync with
+	  current userspace ntfs library code. This means that if a merge
+	  fails the original run lists are always left unmodified instead of
+	  being silently corrupted.
+	- Misc typo fixes.
+
+2.0.13 - Use iget5_locked() in preparation for fake inodes and small cleanups.
+
+	- Remove nr_mft_bits and the now superfluous union with nr_mft_records
+	  from ntfs_volume structure.
+	- Remove nr_lcn_bits and the now superfluous union with nr_clusters
+	  from ntfs_volume structure.
+	- Use iget5_locked() and friends instead of conventional iget(). Wrap
+	  the call in fs/ntfs/inode.c::ntfs_iget() and update callers of iget()
+	  to use ntfs_iget(). Leave only one iget() call at mount time so we
+	  don't need an ntfs_iget_mount().
+	- Change fs/ntfs/inode.c::ntfs_new_extent_inode() to take mft_no as an
+	  additional argument.
+
+2.0.12 - Initial cleanup of address space operations following 2.0.11 changes.
+
+	- Merge fs/ntfs/aops.c::end_buffer_read_mst_async() and
+	  fs/ntfs/aops.c::end_buffer_read_file_async() into one function
+	  fs/ntfs/aops.c::end_buffer_read_attr_async() using NInoMstProtected()
+	  to determine whether to apply mst fixups or not.
+	- Above change allows merging fs/ntfs/aops.c::ntfs_file_read_block()
+	  and fs/ntfs/aops.c::ntfs_mst_readpage() into one function
+	  fs/ntfs/aops.c::ntfs_attr_read_block(). Also, create a tiny wrapper
+	  fs/ntfs/aops.c::ntfs_mst_readpage() to transform the parameters from
+	  the VFS readpage function prototype to the ntfs_attr_read_block()
+	  function prototype.
+
+2.0.11 - Initial preparations for fake inode based attribute i/o.
+
+	- Move definition of ntfs_inode_state_bits to fs/ntfs/inode.h and
+	  do some macro magic (adapted from include/linux/buffer_head.h) to
+	  expand all the helper functions NInoFoo(), NInoSetFoo(), and
+	  NInoClearFoo().
+	- Add new flag to ntfs_inode_state_bits: NI_Sparse.
+	- Add new fields to ntfs_inode structure to allow use of fake inodes
+	  for attribute i/o: type, name, name_len. Also add new state bits:
+	  NI_Attr, which, if set, indicates the inode is a fake inode, and
+	  NI_MstProtected, which, if set, indicates the attribute uses multi
+	  sector transfer protection, i.e. fixups need to be applied after
+	  reads and before/after writes.
+	- Rename fs/ntfs/inode.c::ntfs_{new,clear,destroy}_inode() to
+	  ntfs_{new,clear,destroy}_extent_inode() and update callers.
+	- Use ntfs_clear_extent_inode() in fs/ntfs/inode.c::__ntfs_clear_inode()
+	  instead of ntfs_destroy_extent_inode().
+	- Cleanup memory deallocations in {__,}ntfs_clear_{,big_}inode().
+	- Make all operations on ntfs inode state bits use the NIno* functions.
+	- Set up the new ntfs inode fields and state bits in
+	  fs/ntfs/inode.c::ntfs_read_inode() and add appropriate cleanup of
+	  allocated memory to __ntfs_clear_inode().
+	- Cleanup ntfs_inode structure a bit for better ordering of elements
+	  w.r.t. their size to allow better packing of the structure in memory.
 
 2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume.
 
@@ -38,7 +105,10 @@
 
 	- Change decompression engine to use a single buffer protected by a
 	  spin lock instead of per-CPU buffers. (Rusty Russell)
-	- Switch to using the new KM_BIO_SRC_IRQ for atomic kmaps. (Andrew
+	- Do not update cb_pos when handling a partial final page during
+	  decompression of a sparse compression block, as the value is later
+	  reset without being read/used. (Rusty Russell)
+	- Switch to using the new KM_BIO_SRC_IRQ for atomic kmap()s. (Andrew
 	  Morton)
 	- Change buffer size in ntfs_readdir()/ntfs_filldir() to use
 	  NLS_MAX_CHARSET_SIZE which makes the buffers almost 1kiB each but
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Fri Jul  5 16:42:50 2002
+++ b/fs/ntfs/Makefile	Fri Jul  5 16:42:50 2002
@@ -5,7 +5,7 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.10\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.14\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ntfs/aops.c	Fri Jul  5 16:43:00 2002
@@ -3,7 +3,7 @@
  * 	    Part of the Linux-NTFS project.
  *
  * Copyright (c) 2001,2002 Anton Altaparmakov.
- * Copyright (C) 2002 Richard Russon.
+ * Copyright (c) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -30,31 +30,43 @@
 #include "ntfs.h"
 
 /**
- * end_buffer_read_file_async -
+ * end_buffer_read_attr_async - async io completion for reading attributes
+ * @bh:		buffer head on which io is completed
+ * @uptodate:	whether @bh is now uptodate or not
  *
- * Async io completion handler for accessing files. Adapted from
- * end_buffer_read_mst_async().
+ * Asynchronous I/O completion handler for reading pages belonging to the
+ * attribute address space of an inode. The inodes can either be files or
+ * directories or they can be fake inodes describing some attribute.
+ *
+ * If NInoMstProtected(), perform the post read mst fixups when all IO on the
+ * page has been completed and mark the page uptodate or set the error bit on
+ * the page. To determine the size of the records that need fixing up, we cheat
+ * a little bit by setting the index_block_size in ntfs_inode to the ntfs
+ * record size, and index_block_size_bits, to the log(base 2) of the ntfs
+ * record size.
  */
-static void end_buffer_read_file_async(struct buffer_head *bh, int uptodate)
+static void end_buffer_read_attr_async(struct buffer_head *bh, int uptodate)
 {
 	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
 	unsigned long flags;
 	struct buffer_head *tmp;
 	struct page *page;
+	ntfs_inode *ni;
 
-	if (uptodate)
+	if (likely(uptodate))
 		set_buffer_uptodate(bh);
 	else
 		clear_buffer_uptodate(bh);
 
 	page = bh->b_page;
 
+	ni = NTFS_I(page->mapping->host);
+
 	if (likely(uptodate)) {
 		s64 file_ofs;
 
-		ntfs_inode *ni = NTFS_I(page->mapping->host);
-
 		file_ofs = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
+		/* Check for the current buffer head overflowing. */
 		if (file_ofs + bh->b_size > ni->initialized_size) {
 			char *addr;
 			int ofs = 0;
@@ -82,10 +94,47 @@
 			SetPageError(page);
 		tmp = tmp->b_this_page;
 	}
-
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	if (!PageError(page))
-		SetPageUptodate(page);
+	/*
+	 * If none of the buffers had errors then we can set the page uptodate,
+	 * but we first have to perform the post read mst fixups, if the
+	 * attribute is mst protected, i.e. if NInoMstProteced(ni) is true.
+	 */
+	if (!NInoMstProtected(ni)) {
+		if (likely(!PageError(page)))
+			SetPageUptodate(page);
+		unlock_page(page);
+		return;
+	} else {
+		char *addr;
+		unsigned int i, recs, nr_err;
+		u32 rec_size;
+
+		rec_size = ni->_IDM(index_block_size);
+		recs = PAGE_CACHE_SIZE / rec_size;
+		addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
+		for (i = nr_err = 0; i < recs; i++) {
+			if (likely(!post_read_mst_fixup((NTFS_RECORD*)(addr +
+					i * rec_size), rec_size)))
+				continue;
+			nr_err++;
+			ntfs_error(ni->vol->sb, "post_read_mst_fixup() failed, "
+					"corrupt %s record 0x%Lx. Run chkdsk.",
+					ni->mft_no ? "index" : "mft",
+					(long long)(((s64)page->index <<
+					PAGE_CACHE_SHIFT >>
+					ni->_IDM(index_block_size_bits)) + i));
+		}
+		flush_dcache_page(page);
+		kunmap_atomic(addr, KM_BIO_SRC_IRQ);
+		if (likely(!nr_err && recs))
+			SetPageUptodate(page);
+		else {
+			ntfs_error(ni->vol->sb, "Setting page error, index "
+					"0x%lx.", page->index);
+			SetPageError(page);
+		}
+	}
 	unlock_page(page);
 	return;
 still_busy:
@@ -94,11 +143,20 @@
 }
 
 /**
- * ntfs_file_read_block -
+ * ntfs_attr_read_block - fill a @page of an address space with data
+ * @page:	page cache page to fill with data
  *
- * NTFS version of block_read_full_page(). Adapted from ntfs_mst_readpage().
+ * Fill the page @page of the address space belonging to the @page->host inode.
+ * We read each buffer asynchronously and when all buffers are read in, our io
+ * completion handler end_buffer_read_attr_async(), if required, automatically
+ * applies the mst fixups to the page before finally marking it uptodate and
+ * unlocking it.
+ *
+ * Return 0 on success and -errno on error.
+ *
+ * Contains an adapted version of fs/buffer.c::block_read_full_page().
  */
-static int ntfs_file_read_block(struct page *page)
+static int ntfs_attr_read_block(struct page *page)
 {
 	VCN vcn;
 	LCN lcn;
@@ -119,7 +177,7 @@
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
-	if (!bh)
+	if (unlikely(!bh))
 		return -ENOMEM;
 
 	blocks = PAGE_CACHE_SIZE >> blocksize_bits;
@@ -128,11 +186,9 @@
 	zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits;
 
 #ifdef DEBUG
-	if (unlikely(!ni->mft_no)) {
-		ntfs_error(vol->sb, "NTFS: Attempt to access $MFT! This is a "
-				"very serious bug! Denying access...");
-		return -EACCES;
-	}
+	if (unlikely(!ni->run_list.rl && !ni->mft_no))
+		panic("NTFS: $MFT/$DATA run list has been unmapped! This is a "
+				"very serious bug! Cannot continue...");
 #endif
 
 	/* Loop through all the buffers in the page. */
@@ -211,7 +267,7 @@
 		for (i = 0; i < nr; i++) {
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
-			tbh->b_end_io = end_buffer_read_file_async;
+			tbh->b_end_io = end_buffer_read_attr_async;
 			set_buffer_async_read(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
@@ -220,7 +276,7 @@
 		return 0;
 	}
 	/* No i/o was scheduled on any of the buffers. */
-	if (!PageError(page))
+	if (likely(!PageError(page)))
 		SetPageUptodate(page);
 	else /* Signal synchronous i/o error. */
 		nr = -EIO;
@@ -234,17 +290,17 @@
  * @page:	page cache page to fill with data
  *
  * For non-resident attributes, ntfs_file_readpage() fills the @page of the open
- * file @file by calling the generic block_read_full_page() function provided by
- * the kernel which in turn invokes our ntfs_file_get_block() callback in order
- * to create and read in the buffers associated with the page asynchronously.
+ * file @file by calling the ntfs version of the generic block_read_full_page()
+ * function provided by the kernel, ntfs_attr_read_block(), which in turn
+ * creates and reads in the buffers associated with the page asynchronously.
  *
  * For resident attributes, OTOH, ntfs_file_readpage() fills @page by copying
  * the data from the mft record (which at this stage is most likely in memory)
- * and fills the remainder with zeroes. Thus, in this case I/O is synchronous,
+ * and fills the remainder with zeroes. Thus, in this case, I/O is synchronous,
  * as even if the mft record is not cached at this point in time, we need to
  * wait for it to be read in before we can do the copy.
  *
- * Return zero on success or -errno on error.
+ * Return 0 on success or -errno on error.
  */
 static int ntfs_file_readpage(struct file *file, struct page *page)
 {
@@ -256,43 +312,43 @@
 	u32 attr_len;
 	int err = 0;
 
-	if (!PageLocked(page))
+	if (unlikely(!PageLocked(page)))
 		PAGE_BUG(page);
 
 	ni = NTFS_I(page->mapping->host);
 
 	/* Is the unnamed $DATA attribute resident? */
-	if (test_bit(NI_NonResident, &ni->state)) {
+	if (NInoNonResident(ni)) {
 		/* Attribute is not resident. */
 
 		/* If the file is encrypted, we deny access, just like NT4. */
-		if (test_bit(NI_Encrypted, &ni->state)) {
+		if (NInoEncrypted(ni)) {
 			err = -EACCES;
 			goto unl_err_out;
 		}
 		/* Compressed data stream. Handled in compress.c. */
-		if (test_bit(NI_Compressed, &ni->state))
+		if (NInoCompressed(ni))
 			return ntfs_file_read_compressed_block(page);
 		/* Normal data stream. */
-		return ntfs_file_read_block(page);
+		return ntfs_attr_read_block(page);
 	}
 	/* Attribute is resident, implying it is not compressed or encrypted. */
 
 	/* Map, pin and lock the mft record for reading. */
 	mrec = map_mft_record(READ, ni);
-	if (IS_ERR(mrec)) {
+	if (unlikely(IS_ERR(mrec))) {
 		err = PTR_ERR(mrec);
 		goto unl_err_out;
 	}
 
 	ctx = get_attr_search_ctx(ni, mrec);
-	if (!ctx) {
+	if (unlikely(!ctx)) {
 		err = -ENOMEM;
 		goto unm_unl_err_out;
 	}
 
 	/* Find the data attribute in the mft record. */
-	if (!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx)) {
+	if (unlikely(!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx))) {
 		err = -ENOENT;
 		goto put_unm_unl_err_out;
 	}
@@ -331,6 +387,25 @@
 }
 
 /**
+ * ntfs_mst_readpage - fill a @page of the mft or a directory with data
+ * @file:	open file/directory to which the @page belongs or NULL
+ * @page:	page cache page to fill with data
+ *
+ * Readpage method for the VFS address space operations of directory inodes
+ * and the $MFT/$DATA attribute.
+ *
+ * We just call ntfs_attr_read_block() here, in fact we only need this wrapper
+ * because of the difference in function parameters.
+ */
+int ntfs_mst_readpage(struct file *file, struct page *page)
+{
+	if (unlikely(!PageLocked(page)))
+		PAGE_BUG(page);
+
+	return ntfs_attr_read_block(page);
+}
+
+/**
  * end_buffer_read_mftbmp_async -
  *
  * Async io completion handler for accessing mft bitmap. Adapted from
@@ -343,7 +418,7 @@
 	struct buffer_head *tmp;
 	struct page *page;
 
-	if (uptodate)
+	if (likely(uptodate))
 		set_buffer_uptodate(bh);
 	else
 		clear_buffer_uptodate(bh);
@@ -386,7 +461,7 @@
 	}
 
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	if (!PageError(page))
+	if (likely(!PageError(page)))
 		SetPageUptodate(page);
 	unlock_page(page);
 	return;
@@ -410,7 +485,7 @@
 	int nr, i;
 	unsigned char blocksize_bits;
 
-	if (!PageLocked(page))
+	if (unlikely(!PageLocked(page)))
 		PAGE_BUG(page);
 
 	blocksize = vol->sb->s_blocksize;
@@ -419,7 +494,7 @@
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
-	if (!bh)
+	if (unlikely(!bh))
 		return -ENOMEM;
 
 	blocks = PAGE_CACHE_SIZE >> blocksize_bits;
@@ -503,264 +578,7 @@
 		return 0;
 	}
 	/* No i/o was scheduled on any of the buffers. */
-	if (!PageError(page))
-		SetPageUptodate(page);
-	else /* Signal synchronous i/o error. */
-		nr = -EIO;
-	unlock_page(page);
-	return nr;
-}
-
-/**
- * end_buffer_read_mst_async - async io completion for reading index records
- * @bh:		buffer head on which io is completed
- * @uptodate:	whether @bh is now uptodate or not
- *
- * Asynchronous I/O completion handler for reading pages belonging to the
- * index allocation attribute address space of directory inodes.
- *
- * Perform the post read mst fixups when all IO on the page has been completed
- * and marks the page uptodate or sets the error bit on the page.
- *
- * Adapted from fs/buffer.c.
- *
- * NOTE: We use this function as async io completion handler for reading pages
- * belonging to the mft data attribute address space, too as this saves
- * duplicating an almost identical function. We do this by cheating a little
- * bit in setting the index_block_size in the mft ntfs_inode to the mft record
- * size of the volume (vol->mft_record_size), and index_block_size_bits to
- * mft_record_size_bits, respectively.
- */
-static void end_buffer_read_mst_async(struct buffer_head *bh, int uptodate)
-{
-	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
-	unsigned long flags;
-	struct buffer_head *tmp;
-	struct page *page;
-	ntfs_inode *ni;
-
-	if (uptodate)
-		set_buffer_uptodate(bh);
-	else
-		clear_buffer_uptodate(bh);
-
-	page = bh->b_page;
-
-	ni = NTFS_I(page->mapping->host);
-
-	if (likely(uptodate)) {
-		s64 file_ofs;
-
-		file_ofs = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
-		/* Check for the current buffer head overflowing. */
-		if (file_ofs + bh->b_size > ni->initialized_size) {
-			char *addr;
-			int ofs = 0;
-
-			if (file_ofs < ni->initialized_size)
-				ofs = ni->initialized_size - file_ofs;
-			addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
-			memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs);
-			flush_dcache_page(page);
-			kunmap_atomic(addr, KM_BIO_SRC_IRQ);
-		}
-	} else
-		SetPageError(page);
-
-	spin_lock_irqsave(&page_uptodate_lock, flags);
-	clear_buffer_async_read(bh);
-	unlock_buffer(bh);
-
-	tmp = bh->b_this_page;
-	while (tmp != bh) {
-		if (buffer_locked(tmp)) {
-			if (buffer_async_read(tmp))
-				goto still_busy;
-		} else if (!buffer_uptodate(tmp))
-			SetPageError(page);
-		tmp = tmp->b_this_page;
-	}
-
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	/*
-	 * If none of the buffers had errors then we can set the page uptodate,
-	 * but we first have to perform the post read mst fixups.
-	 */
-	if (!PageError(page)) {
-		char *addr;
-		unsigned int i, recs, nr_err = 0;
-		u32 rec_size;
-
-		rec_size = ni->_IDM(index_block_size);
-		recs = PAGE_CACHE_SIZE / rec_size;
-		addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
-		for (i = 0; i < recs; i++) {
-			if (!post_read_mst_fixup((NTFS_RECORD*)(addr +
-					i * rec_size), rec_size))
-				continue;
-			nr_err++;
-			ntfs_error(ni->vol->sb, "post_read_mst_fixup() failed, "
-					"corrupt %s record 0x%Lx. Run chkdsk.",
-					ni->mft_no ? "index" : "mft",
-					(long long)((page->index <<
-					PAGE_CACHE_SHIFT >>
-					ni->_IDM(index_block_size_bits)) + i));
-		}
-		flush_dcache_page(page);
-		kunmap_atomic(addr, KM_BIO_SRC_IRQ);
-		if (likely(!nr_err && recs))
-			SetPageUptodate(page);
-		else {
-			ntfs_error(ni->vol->sb, "Setting page error, index "
-					"0x%lx.", page->index);
-			SetPageError(page);
-		}
-	}
-	unlock_page(page);
-	return;
-still_busy:
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
-	return;
-}
-
-/**
- * ntfs_mst_readpage - fill a @page of the mft or a directory with data
- * @file:	open file/directory to which the page @page belongs or NULL
- * @page:	page cache page to fill with data
- *
- * Readpage method for the VFS address space operations.
- *
- * Fill the page @page of the $MFT or the open directory @dir. We read each
- * buffer asynchronously and when all buffers are read in our io completion
- * handler end_buffer_read_mst_async() automatically applies the mst fixups to
- * the page before finally marking it uptodate and unlocking it.
- *
- * Contains an adapted version of fs/buffer.c::block_read_full_page().
- */
-int ntfs_mst_readpage(struct file *dir, struct page *page)
-{
-	VCN vcn;
-	LCN lcn;
-	ntfs_inode *ni;
-	ntfs_volume *vol;
-	struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
-	sector_t iblock, lblock, zblock;
-	unsigned int blocksize, blocks, vcn_ofs;
-	int i, nr;
-	unsigned char blocksize_bits;
-
-	if (!PageLocked(page))
-		PAGE_BUG(page);
-
-	ni = NTFS_I(page->mapping->host);
-	vol = ni->vol;
-
-	blocksize_bits = VFS_I(ni)->i_blkbits;
-	blocksize = 1 << blocksize_bits;
-
-	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize, 0);
-	bh = head = page_buffers(page);
-	if (!bh)
-		return -ENOMEM;
-
-	blocks = PAGE_CACHE_SIZE >> blocksize_bits;
-	iblock = page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
-	lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits;
-	zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits;
-
-#ifdef DEBUG
-	if (unlikely(!ni->run_list.rl && !ni->mft_no))
-		panic("NTFS: $MFT/$DATA run list has been unmapped! This is a "
-				"very serious bug! Cannot continue...");
-#endif
-
-	/* Loop through all the buffers in the page. */
-	nr = i = 0;
-	do {
-		if (unlikely(buffer_uptodate(bh)))
-			continue;
-		if (unlikely(buffer_mapped(bh))) {
-			arr[nr++] = bh;
-			continue;
-		}
-		bh->b_bdev = vol->sb->s_bdev;
-		/* Is the block within the allowed limits? */
-		if (iblock < lblock) {
-			BOOL is_retry = FALSE;
-
-			/* Convert iblock into corresponding vcn and offset. */
-			vcn = (VCN)iblock << blocksize_bits >>
-					vol->cluster_size_bits;
-			vcn_ofs = ((VCN)iblock << blocksize_bits) &
-					vol->cluster_size_mask;
-retry_remap:
-			/* Convert the vcn to the corresponding lcn. */
-			down_read(&ni->run_list.lock);
-			lcn = vcn_to_lcn(ni->run_list.rl, vcn);
-			up_read(&ni->run_list.lock);
-			/* Successful remap. */
-			if (lcn >= 0) {
-				/* Setup buffer head to correct block. */
-				bh->b_blocknr = ((lcn << vol->cluster_size_bits)
-						+ vcn_ofs) >> blocksize_bits;
-				set_buffer_mapped(bh);
-				/* Only read initialized data blocks. */
-				if (iblock < zblock) {
-					arr[nr++] = bh;
-					continue;
-				}
-				/* Fully non-initialized data block, zero it. */
-				goto handle_zblock;
-			}
-			/* It is a hole, need to zero it. */
-			if (lcn == LCN_HOLE)
-				goto handle_hole;
-			/* If first try and run list unmapped, map and retry. */
-			if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
-				is_retry = TRUE;
-				if (!map_run_list(ni, vcn))
-					goto retry_remap;
-			}
-			/* Hard error, zero out region. */
-			SetPageError(page);
-			ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) failed "
-					"with error code 0x%Lx%s.",
-					(long long)vcn, (long long)-lcn,
-					is_retry ? " even after retrying" : "");
-			// FIXME: Depending on vol->on_errors, do something.
-		}
-		/*
-		 * Either iblock was outside lblock limits or vcn_to_lcn()
-		 * returned error. Just zero that portion of the page and set
-		 * the buffer uptodate.
-		 */
-handle_hole:
-		bh->b_blocknr = -1UL;
-		clear_buffer_mapped(bh);
-handle_zblock:
-		memset(kmap(page) + i * blocksize, 0, blocksize);
-		flush_dcache_page(page);
-		kunmap(page);
-		set_buffer_uptodate(bh);
-	} while (i++, iblock++, (bh = bh->b_this_page) != head);
-
-	/* Check we have at least one buffer ready for i/o. */
-	if (nr) {
-		/* Lock the buffers. */
-		for (i = 0; i < nr; i++) {
-			struct buffer_head *tbh = arr[i];
-			lock_buffer(tbh);
-			tbh->b_end_io = end_buffer_read_mst_async;
-			set_buffer_async_read(tbh);
-		}
-		/* Finally, start i/o on the buffers. */
-		for (i = 0; i < nr; i++)
-			submit_bh(READ, arr[i]);
-		return 0;
-	}
-	/* No i/o was scheduled on any of the buffers. */
-	if (!PageError(page))
+	if (likely(!PageError(page)))
 		SetPageUptodate(page);
 	else /* Signal synchronous i/o error. */
 		nr = -EIO;
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ntfs/attrib.c	Fri Jul  5 16:43:00 2002
@@ -27,338 +27,433 @@
 /* Temporary helper functions -- might become macros */
 
 /**
- * rl_mm - run_list memmove
+ * ntfs_rl_mm - run_list memmove
  *
  * It is up to the caller to serialize access to the run list @base.
  */
-static inline void rl_mm(run_list_element *base, int dst, int src, int size)
+static inline void ntfs_rl_mm(run_list_element *base, int dst, int src,
+		int size)
 {
-	if ((dst != src) && (size > 0))
-		memmove (base + dst, base + src, size * sizeof (*base));
+	if (likely((dst != src) && (size > 0)))
+		memmove(base + dst, base + src, size * sizeof (*base));
 }
 
 /**
- * rl_mc - run_list memory copy
+ * ntfs_rl_mc - run_list memory copy
  *
  * It is up to the caller to serialize access to the run lists @dstbase and
  * @srcbase.
  */
-static inline void rl_mc(run_list_element *dstbase, int dst,
+static inline void ntfs_rl_mc(run_list_element *dstbase, int dst,
 		run_list_element *srcbase, int src, int size)
 {
-	if (size > 0)
-		memcpy (dstbase+dst, srcbase+src, size * sizeof (*dstbase));
+	if (likely(size > 0))
+		memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
 }
 
 /**
  * ntfs_rl_realloc - Reallocate memory for run_lists
- * @orig:  The original memory allocation
- * @old:   The number of run_lists in the original
- * @new:   The number of run_lists we need space for
+ * @rl:		original run list
+ * @old_size:	number of run list elements in the original run list @rl
+ * @new_size:	number of run list elements we need space for
  *
  * As the run_lists grow, more memory will be required.  To prevent the
  * kernel having to allocate and reallocate large numbers of small bits of
  * memory, this function returns and entire page of memory.
  *
- * It is up to the caller to serialize access to the run list @orig.
+ * It is up to the caller to serialize access to the run list @rl.
  *
  * N.B.  If the new allocation doesn't require a different number of pages in
  *       memory, the function will return the original pointer.
  *
- * Return: Pointer  The newly allocated, or recycled,  memory.
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
+ * On success, return a pointer to the newly allocated, or recycled, memory.
+ * On error, return -errno. The following error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
  */
-static inline run_list_element *ntfs_rl_realloc(run_list_element *orig,
-		int old, int new)
+static inline run_list_element *ntfs_rl_realloc(run_list_element *rl,
+		int old_size, int new_size)
 {
-	run_list_element *nrl;
+	run_list_element *new_rl;
 
-	old = PAGE_ALIGN (old * sizeof (*orig));
-	new = PAGE_ALIGN (new * sizeof (*orig));
-	if (old == new)
-		return orig;
+	old_size = PAGE_ALIGN(old_size * sizeof(*rl));
+	new_size = PAGE_ALIGN(new_size * sizeof(*rl));
+	if (old_size == new_size)
+		return rl;
 
-	nrl = ntfs_malloc_nofs (new);
-	if (!nrl)
-		return ERR_PTR (-ENOMEM);
+	new_rl = ntfs_malloc_nofs(new_size);
+	if (unlikely(!new_rl))
+		return ERR_PTR(-ENOMEM);
 
-	if (orig) {
-		memcpy (nrl, orig, min (old, new));
-		ntfs_free (orig);
+	if (likely(rl != NULL)) {
+		if (unlikely(old_size > new_size))
+			old_size = new_size;
+		memcpy(new_rl, rl, old_size);
+		ntfs_free(rl);
 	}
-	return nrl;
+	return new_rl;
 }
 
 /**
- * ntfs_rl_merge - Join together two run_lists
- * @one:  The first run_list and destination
- * @two:  The second run_list
+ * ntfs_are_rl_mergeable - test if two run lists can be joined together
+ * @dst:	original run list
+ * @src:	new run list to test for mergeability with @dst
  *
- * If possible merge together two run_lists.  For this, their VCNs and LCNs
+ * Test if two run lists can be joined together. For this, their VCNs and LCNs
  * must be adjacent.
  *
- * It is up to the caller to serialize access to the run lists @one and @two.
+ * It is up to the caller to serialize access to the run lists @dst and @src.
  *
- * Return: TRUE   Success, the run_lists were merged
- *         FALSE  Failure, the run_lists were not merged
+ * Return: TRUE   Success, the run lists can be merged.
+ *         FALSE  Failure, the run lists cannot be merged.
  */
-static inline BOOL ntfs_rl_merge(run_list_element *one, run_list_element *two)
+static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst,
+		run_list_element *src)
 {
-	BUG_ON (!one || !two);
+	BUG_ON(!dst || !src);
 
-	if ((one->lcn < 0) || (two->lcn < 0))     /* Are we merging holes? */
+	if ((dst->lcn < 0) || (src->lcn < 0))     /* Are we merging holes? */
 		return FALSE;
-	if ((one->lcn + one->length) != two->lcn) /* Are the runs contiguous? */
+	if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */
 		return FALSE;
-	if ((one->vcn + one->length) != two->vcn) /* Are the runs misaligned? */
+	if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */
 		return FALSE;
 
-	one->length += two->length;
 	return TRUE;
 }
 
 /**
- * ntfs_rl_append - Append a run_list after the given element
- * @orig:   The original run_list to be worked on.
- * @osize:  The number of elements in @orig (including end marker).
- * @new:    The run_list to be inserted.
- * @nsize:  The number of elements in @new (excluding end marker).
- * @loc:    Append the new run_list after this element in @orig.
- *
- * Append a run_list after element @loc in @orig.  Merge the right end of
- * the new run_list, if necessary.  Adjust the size of the hole before the
- * appended run_list.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
+ * __ntfs_rl_merge - merge two run lists without testing if they can be merged
+ * @dst:	original, destination run list
+ * @src:	new run list to merge with @dst
+ *
+ * Merge the two run lists, writing into the destination run list @dst. The
+ * caller must make sure the run lists can be merged or this will corrupt the
+ * destination run list.
  *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ */
+static inline void __ntfs_rl_merge(run_list_element *dst, run_list_element *src)
+{
+	dst->length += src->length;
+}
+
+/**
+ * ntfs_rl_merge - test if two run lists can be joined together and merge them
+ * @dst:	original, destination run list
+ * @src:	new run list to merge with @dst
+ *
+ * Test if two run lists can be joined together. For this, their VCNs and LCNs
+ * must be adjacent. If they can be merged, perform the merge, writing into
+ * the destination run list @dst.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * Return: TRUE   Success, the run lists have been merged.
+ *         FALSE  Failure, the run lists cannot be merged and have not been
+ *		  modified.
  */
-static inline run_list_element *ntfs_rl_append(run_list_element *orig,
-		int osize, run_list_element *new, int nsize, int loc)
+static inline BOOL ntfs_rl_merge(run_list_element *dst, run_list_element *src)
+{
+	BOOL merge = ntfs_are_rl_mergeable(dst, src);
+
+	if (merge)
+		__ntfs_rl_merge(dst, src);
+	return merge;
+}
+
+/**
+ * ntfs_rl_append - append a run list after a given element
+ * @dst:	original run list to be worked on
+ * @dsize:	number of elements in @dst (including end marker)
+ * @src:	run list to be inserted into @dst
+ * @ssize:	number of elements in @src (excluding end marker)
+ * @loc:	append the new run list @src after this element in @dst
+ *
+ * Append the run list @src after element @loc in @dst.  Merge the right end of
+ * the new run list, if necessary. Adjust the size of the hole before the
+ * appended run list.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
+ */
+static inline run_list_element *ntfs_rl_append(run_list_element *dst,
+		int dsize, run_list_element *src, int ssize, int loc)
 {
-	run_list_element *res;
 	BOOL right;
+	int magic;
+
+	BUG_ON(!dst || !src);
+
+	/* First, check if the right hand end needs merging. */
+	right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
 
-	BUG_ON (!orig || !new);
+	/* Space required: @dst size + @src size, less one if we merged. */
+	dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
+	if (IS_ERR(dst))
+		return dst;
+	/*
+	 * We are guaranteed to succeed from here so can start modifying the
+	 * original run lists.
+	 */
 
 	/* First, merge the right hand end, if necessary. */
-	right = ntfs_rl_merge (new + nsize - 1, orig + loc + 1);
+	if (right)
+		__ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
 
-	/* Space required: Orig size + New size, less one if we merged. */
-	res = ntfs_rl_realloc (orig, osize, osize + nsize - right);
-	if (IS_ERR (res))
-		return res;
-
-	/* Move the tail of Orig out of the way, then copy in New. */
-	rl_mm (res, loc + 1 + nsize, loc + 1 + right, osize - loc - 1 - right);
-	rl_mc (res, loc + 1, new, 0, nsize);
+	magic = loc + ssize;
+
+	/* Move the tail of @dst out of the way, then copy in @src. */
+	ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right);
+	ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
 
 	/* Adjust the size of the preceding hole. */
-	res[loc].length = res[loc+1].vcn - res[loc].vcn;
+	dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
 
 	/* We may have changed the length of the file, so fix the end marker */
-	if (res[loc+nsize+1].lcn == LCN_ENOENT)
-		res[loc+nsize+1].vcn = res[loc+nsize].vcn + res[loc+nsize].length;
+	if (dst[magic + 1].lcn == LCN_ENOENT)
+		dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length;
 
-	return res;
+	return dst;
 }
 
 /**
- * ntfs_rl_insert - Insert a run_list into another
- * @orig:   The original run_list to be worked on.
- * @osize:  The number of elements in @orig (including end marker).
- * @new:    The run_list to be inserted.
- * @nsize:  The number of elements in @new (excluding end marker).
- * @loc:    Insert the new run_list before this element in @orig.
- *
- * Insert a run_list before element @loc in @orig.  Merge the left end of
- * the new run_list, if necessary.  Adjust the size of the hole after the
- * inserted run_list.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_insert - insert a run list into another
+ * @dst:	original run list to be worked on
+ * @dsize:	number of elements in @dst (including end marker)
+ * @src:	new run list to be inserted
+ * @ssize:	number of elements in @src (excluding end marker)
+ * @loc:	insert the new run list @src before this element in @dst
+ *
+ * Insert the run list @src before element @loc in the run list @dst. Merge the
+ * left end of the new run list, if necessary. Adjust the size of the hole
+ * after the inserted run list.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
  */
-static inline run_list_element *ntfs_rl_insert(run_list_element *orig,
-		int osize, run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_insert(run_list_element *dst,
+		int dsize, run_list_element *src, int ssize, int loc)
 {
-	run_list_element *res;
 	BOOL left = FALSE;
 	BOOL disc = FALSE;	/* Discontinuity */
 	BOOL hole = FALSE;	/* Following a hole */
+	int magic;
 
-	BUG_ON (!orig || !new);
+	BUG_ON(!dst || !src);
 
-	/* disc => Discontinuity between the end of Orig and the start of New.
+	/* disc => Discontinuity between the end of @dst and the start of @src.
 	 *         This means we might need to insert a hole.
-	 * hole => Orig ends with a hole or an unmapped region which we can
+	 * hole => @dst ends with a hole or an unmapped region which we can
 	 *         extend to match the discontinuity. */
-	if (loc == 0) {
-		disc = (new[0].vcn > 0);
-	} else {
-		left = ntfs_rl_merge (orig + loc - 1, new);
+	if (loc == 0)
+		disc = (src[0].vcn > 0);
+	else {
+		s64 merged_length;
+
+		left = ntfs_are_rl_mergeable(dst + loc - 1, src);
+
+		merged_length = dst[loc - 1].length;
+		if (left)
+			merged_length += src->length;
 
-		disc = (new[0].vcn > (orig[loc-1].vcn + orig[loc-1].length));
+		disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
 		if (disc)
-			hole = (orig[loc-1].lcn == LCN_HOLE);
+			hole = (dst[loc - 1].lcn == LCN_HOLE);
 	}
 
-	/* Space required: Orig size + New size, less one if we merged,
-	 * plus one if there was a discontinuity, less one for a trailing hole */
-	res = ntfs_rl_realloc (orig, osize, osize + nsize - left + disc - hole);
-	if (IS_ERR (res))
-		return res;
-
-	/* Move the tail of Orig out of the way, then copy in New. */
-	rl_mm (res, loc + nsize - left + disc - hole, loc, osize - loc);
-	rl_mc (res, loc + disc - hole, new, left, nsize - left);
+	/* Space required: @dst size + @src size, less one if we merged, plus
+	 * one if there was a discontinuity, less one for a trailing hole. */
+	dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole);
+	if (IS_ERR(dst))
+		return dst;
+	/*
+	 * We are guaranteed to succeed from here so can start modifying the
+	 * original run list.
+	 */
+
+	if (left)
+		__ntfs_rl_merge(dst + loc - 1, src);
+
+	magic = loc + ssize - left + disc - hole;
+
+	/* Move the tail of @dst out of the way, then copy in @src. */
+	ntfs_rl_mm(dst, magic, loc, dsize - loc);
+	ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left);
 
 	/* Adjust the VCN of the last run ... */
-	if (res[loc+nsize-left+disc-hole].lcn <= LCN_HOLE) {
-		res[loc+nsize-left+disc-hole].vcn =
-			res[loc+nsize-left+disc-hole-1].vcn +
-			res[loc+nsize-left+disc-hole-1].length;
-	}
+	if (dst[magic].lcn <= LCN_HOLE)
+		dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
 	/* ... and the length. */
-	if ((res[loc+nsize-left+disc-hole].lcn == LCN_HOLE) ||
-	    (res[loc+nsize-left+disc-hole].lcn == LCN_RL_NOT_MAPPED)) {
-		res[loc+nsize-left+disc-hole].length =
-			res[loc+nsize-left+disc-hole+1].vcn -
-			res[loc+nsize-left+disc-hole].vcn;
-	}
+	if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED)
+		dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn;
 
 	/* Writing beyond the end of the file and there's a discontinuity. */
 	if (disc) {
-		if (hole) {
-			res[loc-1].length = res[loc].vcn - res[loc-1].vcn;
-		} else {
+		if (hole)
+			dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn;
+		else {
 			if (loc > 0) {
-				res[loc].vcn = res[loc-1].vcn +
-					res[loc-1].length;
-				res[loc].length = res[loc+1].vcn - res[loc].vcn;
+				dst[loc].vcn = dst[loc - 1].vcn +
+						dst[loc - 1].length;
+				dst[loc].length = dst[loc + 1].vcn -
+						dst[loc].vcn;
 			} else {
-				res[loc].vcn = 0;
-				res[loc].length = res[loc+1].vcn;
+				dst[loc].vcn = 0;
+				dst[loc].length = dst[loc + 1].vcn;
 			}
-			res[loc].lcn = LCN_RL_NOT_MAPPED;
+			dst[loc].lcn = LCN_RL_NOT_MAPPED;
 		}
 
-		if (res[loc+nsize-left+disc].lcn == LCN_ENOENT)
-			res[loc+nsize-left+disc].vcn = res[loc+nsize-left+disc-1].vcn +
-				res[loc+nsize-left+disc-1].length;
-	}
+		magic += hole;
 
-	return res;
+		if (dst[magic].lcn == LCN_ENOENT)
+			dst[magic].vcn = dst[magic - 1].vcn +
+					dst[magic - 1].length;
+	}
+	return dst;
 }
 
 /**
- * ntfs_rl_replace - Overwrite a run_list element with another run_list
- * @orig:   The original run_list to be worked on.
- * @osize:  The number of elements in @orig (including end marker).
- * @new:    The run_list to be inserted.
- * @nsize:  The number of elements in @new (excluding end marker).
- * @loc:    Index of run_list @orig to overwrite with @new.
- *
- * Replace the run_list at @loc with @new.  Merge the left and right ends of
- * the inserted run_list, if necessary.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_replace - overwrite a run_list element with another run list
+ * @dst:	original run list to be worked on
+ * @dsize:	number of elements in @dst (including end marker)
+ * @src:	new run list to be inserted
+ * @ssize:	number of elements in @src (excluding end marker)
+ * @loc:	index in run list @dst to overwrite with @src
+ *
+ * Replace the run list element @dst at @loc with @src. Merge the left and
+ * right ends of the inserted run list, if necessary.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
  */
-static inline run_list_element *ntfs_rl_replace(run_list_element *orig,
-		int osize, run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
+		int dsize, run_list_element *src, int ssize, int loc)
 {
-	run_list_element *res;
 	BOOL left = FALSE;
 	BOOL right;
+	int magic;
 
-	BUG_ON (!orig || !new);
+	BUG_ON(!dst || !src);
 
 	/* First, merge the left and right ends, if necessary. */
-	right = ntfs_rl_merge (new + nsize - 1, orig + loc + 1);
+	right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
 	if (loc > 0)
-		left = ntfs_rl_merge (orig + loc - 1, new);
+		left = ntfs_are_rl_mergeable(dst + loc - 1, src);
 
-	/* Allocate some space.  We'll need less if the left, right
-	 * or both ends were merged. */
-	res = ntfs_rl_realloc (orig, osize, osize + nsize - left - right);
-	if (IS_ERR (res))
-		return res;
-
-	/* Move the tail of Orig out of the way, then copy in New. */
-	rl_mm (res, loc + nsize - left, loc + right + 1,
-		osize - loc - right - 1);
-	rl_mc (res, loc, new, left, nsize - left);
+	/* Allocate some space. We'll need less if the left, right, or both
+	 * ends were merged. */
+	dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right);
+	if (IS_ERR(dst))
+		return dst;
+	/*
+	 * We are guaranteed to succeed from here so can start modifying the
+	 * original run lists.
+	 */
+	if (right)
+		__ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
+	if (left)
+		__ntfs_rl_merge(dst + loc - 1, src);
+
+	/* FIXME: What does this mean? (AIA) */
+	magic = loc + ssize - left;
+
+	/* Move the tail of @dst out of the way, then copy in @src. */
+	ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1);
+	ntfs_rl_mc(dst, loc, src, left, ssize - left);
 
 	/* We may have changed the length of the file, so fix the end marker */
-	if (res[loc+nsize-left].lcn == LCN_ENOENT)
-		res[loc+nsize-left].vcn = res[loc+nsize-left-1].vcn +
-					  res[loc+nsize-left-1].length;
-	return res;
+	if (dst[magic].lcn == LCN_ENOENT)
+		dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
+	return dst;
 }
 
 /**
- * ntfs_rl_split - Insert a run_list into the centre of a hole
- * @orig:   The original run_list to be worked on.
- * @osize:  The number of elements in @orig (including end marker).
- * @new:    The run_list to be inserted.
- * @nsize:  The number of elements in @new (excluding end marker).
- * @loc:    Index of run_list in @orig to split with @new.
- *
- * Split the run_list at @loc into two and insert @new.  No merging of
- * run_lists is necessary.  Adjust the size of the holes either side.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_split - insert a run list into the centre of a hole
+ * @dst:	original run list to be worked on
+ * @dsize:	number of elements in @dst (including end marker)
+ * @src:	new run list to be inserted
+ * @ssize:	number of elements in @src (excluding end marker)
+ * @loc:	index in run list @dst at which to split and insert @src
+ *
+ * Split the run list @dst at @loc into two and insert @new in between the two
+ * fragments. No merging of run lists is necessary. Adjust the size of the
+ * holes either side.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
  */
-static inline run_list_element *ntfs_rl_split(run_list_element *orig, int osize,
-		run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize,
+		run_list_element *src, int ssize, int loc)
 {
-	run_list_element *res;
-
-	BUG_ON (!orig || !new);
-
-	/* Space required: Orig size + New size + One new hole. */
-	res = ntfs_rl_realloc (orig, osize, osize + nsize + 1);
-	if (IS_ERR (res))
-		return res;
+	BUG_ON(!dst || !src);
 
-	/* Move the tail of Orig out of the way, then copy in New. */
-	rl_mm (res, loc + 1 + nsize, loc, osize - loc);
-	rl_mc (res, loc + 1, new, 0, nsize);
+	/* Space required: @dst size + @src size + one new hole. */
+	dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
+	if (IS_ERR(dst))
+		return dst;
+	/*
+	 * We are guaranteed to succeed from here so can start modifying the
+	 * original run lists.
+	 */
 
-	/* Adjust the size of the holes either size of New. */
-	res[loc].length         = res[loc+1].vcn       - res[loc].vcn;
-	res[loc+nsize+1].vcn    = res[loc+nsize].vcn   + res[loc+nsize].length;
-	res[loc+nsize+1].length = res[loc+nsize+2].vcn - res[loc+nsize+1].vcn;
+	/* Move the tail of @dst out of the way, then copy in @src. */
+	ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc);
+	ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
+
+	/* Adjust the size of the holes either size of @src. */
+	dst[loc].length         = dst[loc+1].vcn       - dst[loc].vcn;
+	dst[loc+ssize+1].vcn    = dst[loc+ssize].vcn   + dst[loc+ssize].length;
+	dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn;
 
-	return res;
+	return dst;
 }
 
 /**
- * merge_run_lists - merge two run_lists into one
- * @drl:  The original run_list.
- * @srl:  The new run_list to be merge into @drl.
- *
- * First we sanity check the two run_lists to make sure that they are sensible
- * and can be merged.  The @srl run_list must be either after the @drl run_list
- * or completely within a hole in @drl.
+ * ntfs_merge_run_lists - merge two run_lists into one
+ * @drl:	original run list to be worked on
+ * @srl:	new run list to be merged into @drl
+ *
+ * First we sanity check the two run lists @srl and @drl to make sure that they
+ * are sensible and can be merged. The run list @srl must be either after the
+ * run list @drl or completely within a hole (or unmapped region) in @drl.
  *
  * It is up to the caller to serialize access to the run lists @drl and @srl.
  *
@@ -366,25 +461,28 @@
  *   1. When attribute lists are used and a further extent is being mapped.
  *   2. When new clusters are allocated to fill a hole or extend a file.
  *
- * There are four possible ways @srl can be merged.  It can be inserted at
- * the beginning of a hole; split the hole in two; appended at the end of
- * a hole; replace the whole hole.  It can also be appended to the end of
- * the run_list, which is just a variant of the insert case.
- *
- * N.B.  Either, or both, of the input pointers may be freed if the function
- *       is successful.  Only the returned pointer may be used.
- *
- *       If the function fails, neither of the input run_lists may be safe.
- *
- * Return: Pointer, The resultant merged run_list.
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- *         -EINVAL, Invalid parameters were passed in.
- *         -ERANGE, The run_lists overlap and cannot be merged.
+ * There are four possible ways @srl can be merged. It can:
+ *	- be inserted at the beginning of a hole,
+ *	- split the hole in two and be inserted between the two fragments,
+ *	- be appended at the end of a hole, or it can
+ *	- replace the whole hole.
+ * It can also be appended to the end of the run list, which is just a variant
+ * of the insert case.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @drl and @srl are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ *	-EINVAL	- Invalid parameters were passed in.
+ *	-ERANGE	- The run lists overlap and cannot be merged.
  */
-run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
+run_list_element *ntfs_merge_run_lists(run_list_element *drl,
+		run_list_element *srl)
 {
-	run_list_element *nrl;	/* New run list. */
 	int di, si;		/* Current index into @[ds]rl. */
 	int sstart;		/* First index with lcn > LCN_RL_NOT_MAPPED. */
 	int dins;		/* Index into @drl at which to insert @srl. */
@@ -392,49 +490,49 @@
 	int dfinal, sfinal;	/* The last index into @[ds]rl with
 				   lcn >= LCN_HOLE. */
 	int marker = 0;
+	VCN marker_vcn = 0;
 
-#if 1
-	ntfs_debug ("dst:");
-	ntfs_debug_dump_runlist (drl);
-	ntfs_debug ("src:");
-	ntfs_debug_dump_runlist (srl);
+#ifdef DEBUG
+	ntfs_debug("dst:");
+	ntfs_debug_dump_runlist(drl);
+	ntfs_debug("src:");
+	ntfs_debug_dump_runlist(srl);
 #endif
 
  	/* Check for silly calling... */
-	if (unlikely (!srl))
+	if (unlikely(!srl))
 		return drl;
-	if (unlikely (IS_ERR (srl) || IS_ERR (drl)))
-		return ERR_PTR (-EINVAL);
+	if (unlikely(IS_ERR(srl) || IS_ERR(drl)))
+		return ERR_PTR(-EINVAL);
 
 	/* Check for the case where the first mapping is being done now. */
-	if (unlikely (!drl)) {
-		nrl = srl;
-
+	if (unlikely(!drl)) {
+		drl = srl;
 		/* Complete the source run list if necessary. */
-		if (unlikely (srl[0].vcn)) {
+		if (unlikely(drl[0].vcn)) {
 			/* Scan to the end of the source run list. */
-			for (send = 0; likely (srl[send].length); send++)
+			for (dend = 0; likely(drl[dend].length); dend++)
 				;
-			nrl = ntfs_rl_realloc (srl, send, send + 1);
-			if (!nrl)
-				return ERR_PTR (-ENOMEM);
-
-			rl_mm (nrl, 1, 0, send);
-			nrl[0].vcn = 0;			/* Add start element. */
-			nrl[0].lcn = LCN_RL_NOT_MAPPED;
-			nrl[0].length = nrl[1].vcn;
+			drl = ntfs_rl_realloc(drl, dend, dend + 1);
+			if (IS_ERR(drl))
+				return drl;
+			/* Insert start element at the front of the run list. */
+			ntfs_rl_mm(drl, 1, 0, dend);
+			drl[0].vcn = 0;
+			drl[0].lcn = LCN_RL_NOT_MAPPED;
+			drl[0].length = drl[1].vcn;
 		}
 		goto finished;
 	}
 
 	si = di = 0;
 
-	/* Skip the unmapped start element(s) in each run_list if present. */
+	/* Skip any unmapped start element(s) in the source run_list. */
 	while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE)
 		si++;
 
-	/* Can't have an entirely unmapped srl run_list. */
-	BUG_ON (!srl[si].length);
+	/* Can't have an entirely unmapped source run list. */
+	BUG_ON(!srl[si].length);
 
 	/* Record the starting points. */
 	sstart = si;
@@ -445,19 +543,16 @@
 	 * appended to @drl.
 	 */
 	for (; drl[di].length; di++) {
-		if ((drl[di].vcn + drl[di].length) > srl[sstart].vcn)
+		if (drl[di].vcn + drl[di].length > srl[sstart].vcn)
 			break;
 	}
 	dins = di;
 
 	/* Sanity check for illegal overlaps. */
-	if ((drl[di].vcn == srl[si].vcn) &&
-	    (drl[di].lcn >= 0) &&
-	    (srl[si].lcn >= 0)) {
-		ntfs_error (NULL, "Run lists overlap. Cannot merge! Returning "
-				"ERANGE.");
-		nrl = ERR_PTR (-ERANGE);
-		goto exit;
+	if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
+			(srl[si].lcn >= 0)) {
+		ntfs_error(NULL, "Run lists overlap. Cannot merge!");
+		return ERR_PTR(-ERANGE);
 	}
 
 	/* Scan to the end of both run lists in order to know their sizes. */
@@ -466,9 +561,8 @@
 	for (dend = di; drl[dend].length; dend++)
 		;
 
-	if (srl[send].lcn == LCN_ENOENT) {
-		marker = send;
-	}
+	if (srl[send].lcn == (LCN)LCN_ENOENT)
+		marker_vcn = srl[marker = send].vcn;
 
 	/* Scan to the last element with lcn >= LCN_HOLE. */
 	for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--)
@@ -479,96 +573,142 @@
 	{
 	BOOL start;
 	BOOL finish;
-	int ds = dend   + 1;		/* Number of elements in drl & srl */
+	int ds = dend + 1;		/* Number of elements in drl & srl */
 	int ss = sfinal - sstart + 1;
 
 	start  = ((drl[dins].lcn <  LCN_RL_NOT_MAPPED) ||    /* End of file   */
 		  (drl[dins].vcn == srl[sstart].vcn));	     /* Start of hole */
 	finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) &&    /* End of file   */
 		 ((drl[dins].vcn + drl[dins].length) <=      /* End of hole   */
-		  (srl[send-1].vcn + srl[send-1].length)));
+		  (srl[send - 1].vcn + srl[send - 1].length)));
 
 	/* Or we'll lose an end marker */
 	if (start && finish && (drl[dins].length == 0))
 		ss++;
-	if (marker && (drl[dins].vcn + drl[dins].length > srl[send-1].vcn))
+	if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
 		finish = FALSE;
-
 #if 0
 	ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
 	ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
 	ntfs_debug("start = %i, finish = %i", start, finish);
 	ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);
 #endif
-	if (start)
+	if (start) {
 		if (finish)
-			nrl = ntfs_rl_replace (drl, ds, srl + sstart, ss, dins);
+			drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins);
 		else
-			nrl = ntfs_rl_insert  (drl, ds, srl + sstart, ss, dins);
-	else
+			drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins);
+	} else {
 		if (finish)
-			nrl = ntfs_rl_append  (drl, ds, srl + sstart, ss, dins);
+			drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins);
 		else
-			nrl = ntfs_rl_split   (drl, ds, srl + sstart, ss, dins);
-
-	if (marker && !IS_ERR(nrl)) {
-		for (ds = 0; nrl[ds].length; ds++)
+			drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins);
+	}
+	if (IS_ERR(drl)) {
+		ntfs_error(NULL, "Merge failed.");
+		return drl;
+	}
+	ntfs_free(srl);
+	if (marker) {
+		ntfs_debug("Triggering marker code.");
+		for (ds = dend; drl[ds].length; ds++)
 			;
-		nrl = ntfs_rl_insert(nrl, ds + 1, srl + marker, 1, ds);
+		/* We only need to care if @srl ended after @drl. */
+		if (drl[ds].vcn <= marker_vcn) {
+			int slots = 0;
+
+			if (drl[ds].vcn == marker_vcn) {
+				ntfs_debug("Old marker = 0x%Lx, replacing with "
+						"LCN_ENOENT.\n",
+						(unsigned long long)
+						drl[ds].lcn);
+				drl[ds].lcn = (LCN)LCN_ENOENT;
+				goto finished;
+			}
+			/*
+			 * We need to create an unmapped run list element in
+			 * @drl or extend an existing one before adding the
+			 * ENOENT terminator.
+			 */
+			if (drl[ds].lcn == (LCN)LCN_ENOENT) {
+				ds--;
+				slots = 1;
+			}
+			if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) {
+				/* Add an unmapped run list element. */
+				if (!slots) {
+					/* FIXME/TODO: We need to have the
+					 * extra memory already! (AIA) */
+					drl = ntfs_rl_realloc(drl, ds, ds + 2);
+					if (!drl)
+						goto critical_error;
+					slots = 2;
+				}
+				ds++;
+				/* Need to set vcn if it isn't set already. */
+				if (slots != 1)
+					drl[ds].vcn = drl[ds - 1].vcn +
+							drl[ds - 1].length;
+				drl[ds].lcn = (LCN)LCN_RL_NOT_MAPPED;
+				/* We now used up a slot. */
+				slots--;
+			}
+			drl[ds].length = marker_vcn - drl[ds].vcn;
+			/* Finally add the ENOENT terminator. */
+			ds++;
+			if (!slots) {
+				/* FIXME/TODO: We need to have the extra
+				 * memory already! (AIA) */
+				drl = ntfs_rl_realloc(drl, ds, ds + 1);
+				if (!drl)
+					goto critical_error;
+			}
+			drl[ds].vcn = marker_vcn;
+			drl[ds].lcn = (LCN)LCN_ENOENT;
+			drl[ds].length = (s64)0;
+		}
 	}
 	}
 
-	if (likely (!IS_ERR (nrl))) {
-		/* The merge was completed successfully. */
 finished:
-		if (nrl != srl)
-			ntfs_free (srl);
-		/*ntfs_debug ("Done.");*/
-		/*ntfs_debug ("Merged run list:");*/
-
-#if 1
-		ntfs_debug ("res:");
-		ntfs_debug_dump_runlist (nrl);
-#endif
-	} else {
-		ntfs_error (NULL, "Merge failed, returning error code %ld.",
-				-PTR_ERR (nrl));
-	}
-exit:
-	return nrl;
+	/* The merge was completed successfully. */
+	ntfs_debug("Merged run list:");
+	ntfs_debug_dump_runlist(drl);
+	return drl;
+
+critical_error:
+	/* Critical error! We cannot afford to fail here. */
+	ntfs_error(NULL, "Critical error! Not enough memory.");
+	panic("NTFS: Cannot continue.");
 }
 
 /**
  * decompress_mapping_pairs - convert mapping pairs array to run list
  * @vol:	ntfs volume on which the attribute resides
  * @attr:	attribute record whose mapping pairs array to decompress
- * @run_list:	optional run list in which to insert @attr's run list
- *
- * Decompress the attribute @attr's mapping pairs array into a run_list and
- * return the run list or -errno on error. If @run_list is not NULL then
- * the mapping pairs array of @attr is decompressed and the run list inserted
- * into the appropriate place in @run_list. If this is the case and the
- * function returns success, the original pointer passed into @run_list is no
- * longer valid.
+ * @old_rl:	optional run list in which to insert @attr's run list
  *
  * It is up to the caller to serialize access to the run list @old_rl.
  *
- * Check the return value for error with IS_ERR(ret_val). If this is FALSE,
- * the function was successful, the return value is the new run list, and if
- * an existing run list pointer was passed in, this is no longer valid.
- * If IS_ERR(ret_val) returns true, there was an error, the return value is not
- * a run_list pointer and the existing run list pointer if one was passed in
- * has not been touched. In this case use PTR_ERR(ret_val) to obtain the error
- * code. Following error codes are defined:
- * 	-ENOMEM		Not enough memory to allocate run list array.
- * 	-EIO		Corrupt run list.
- * 	-EINVAL		Invalid parameters were passed in.
- * 	-ERANGE		The two run lists overlap.
+ * Decompress the attribute @attr's mapping pairs array into a run list. On
+ * success, return the decompressed run list.
+ *
+ * If @old_rl is not NULL, decompressed run list is inserted into the
+ * appropriate place in @old_rl and the resultant, combined run list is
+ * returned. The original @old_rl is deallocated.
+ *
+ * On error, return -errno. @old_rl is left unmodified in that case.
+ *
+ * The following error codes are defined:
+ *	-ENOMEM	- Not enough memory to allocate run list array.
+ * 	-EIO	- Corrupt run list.
+ * 	-EINVAL	- Invalid parameters were passed in.
+ * 	-ERANGE	- The two run lists overlap.
  *
  * FIXME: For now we take the conceptionally simplest approach of creating the
  * new run list disregarding the already existing one and then splicing the
- * two into one if that is possible (we check for overlap and discard the new
- * run list if overlap present and return error).
+ * two into one, if that is possible (we check for overlap and discard the new
+ * run list if overlap present before returning ERR_PTR(-ERANGE)).
  */
 run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
 		const ATTR_RECORD *attr, run_list_element *old_rl)
@@ -576,12 +716,12 @@
 	VCN vcn;		/* Current vcn. */
 	LCN lcn; 		/* Current lcn. */
 	s64 deltaxcn;		/* Change in [vl]cn. */
-	run_list_element *rl = NULL;	/* The output run_list. */
-	run_list_element *rl2;	/* Temporary run_list. */
+	run_list_element *rl;	/* The output run list. */
 	u8 *buf;		/* Current position in mapping pairs array. */
 	u8 *attr_end;		/* End of attribute. */
-	int rlsize;		/* Size of run_list buffer. */
-	int rlpos;		/* Current run_list position. */
+	int rlsize;		/* Size of run list buffer. */
+	u16 rlpos;		/* Current run list position in units of
+				   run_list_elements. */
 	u8 b;			/* Current byte offset in buf. */
 
 #ifdef DEBUG
@@ -602,14 +742,12 @@
 		ntfs_error(vol->sb, "Corrupt attribute.");
 		return ERR_PTR(-EIO);
 	}
-	/* Current position in run_list array. */
+	/* Current position in run list array. */
 	rlpos = 0;
-	/* Allocate first page. */
-	rl = ntfs_malloc_nofs(PAGE_SIZE);
+	/* Allocate first page and set current run list size to one page. */
+	rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE);
 	if (unlikely(!rl))
 		return ERR_PTR(-ENOMEM);
-	/* Current run_list buffer size in bytes. */
-	rlsize = PAGE_SIZE;
 	/* Insert unmapped starting element if necessary. */
 	if (vcn) {
 		rl->vcn = (VCN)0;
@@ -624,18 +762,20 @@
 		 * operates on whole pages only.
 		 */
 		if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
+			run_list_element *rl2;
+			
 			rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
 			if (unlikely(!rl2)) {
 				ntfs_free(rl);
 				return ERR_PTR(-ENOMEM);
 			}
-			memmove(rl2, rl, rlsize);
+			memcpy(rl2, rl, rlsize);
 			ntfs_free(rl);
 			rl = rl2;
 			rlsize += PAGE_SIZE;
 		}
 		/* Enter the current vcn into the current run_list element. */
-		(rl + rlpos)->vcn = vcn;
+		rl[rlpos].vcn = vcn;
 		/*
 		 * Get the change in vcn, i.e. the run length in clusters.
 		 * Doing it this way ensures that we signextend negative values.
@@ -664,10 +804,10 @@
 			goto err_out;
 		}
 		/*
-		 * Enter the current run length into the current run_list
+		 * Enter the current run length into the current run list
 		 * element.
 		 */
-		(rl + rlpos)->length = deltaxcn;
+		rl[rlpos].length = deltaxcn;
 		/* Increment the current vcn by the current run length. */
 		vcn += deltaxcn;
 		/*
@@ -676,7 +816,7 @@
 		 * to LCN_HOLE.
 		 */
 		if (!(*buf & 0xf0))
-			(rl + rlpos)->lcn = (LCN)LCN_HOLE;
+			rl[rlpos].lcn = (LCN)LCN_HOLE;
 		else {
 			/* Get the lcn change which really can be negative. */
 			u8 b2 = *buf & 0xf;
@@ -709,7 +849,7 @@
 				goto err_out;
 			}
 			/* Enter the current lcn into the run_list element. */
-			(rl + rlpos)->lcn = lcn;
+			rl[rlpos].lcn = lcn;
 		}
 		/* Get to the next run_list element. */
 		rlpos++;
@@ -729,7 +869,7 @@
 				"non-resident attribute.");
 		goto err_out;
 	}
-	/* Setup not mapped run_list element if this is the base extent. */
+	/* Setup not mapped run list element if this is the base extent. */
 	if (!attr->_ANR(lowest_vcn)) {
 		VCN max_cluster;
 
@@ -742,13 +882,13 @@
 		 * likely, there are more extents following this one.
 		 */
 		if (deltaxcn < --max_cluster) {
-			//RAR ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
-					//RAR "max_cluster = 0x%Lx",
-					//RAR (long long)deltaxcn,
-					//RAR (long long)max_cluster);
-			(rl + rlpos)->vcn = vcn;
-			vcn += (rl + rlpos)->length = max_cluster - deltaxcn;
-			(rl + rlpos)->lcn = (LCN)LCN_RL_NOT_MAPPED;
+			ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
+					"max_cluster = 0x%Lx",
+					(long long)deltaxcn,
+					(long long)max_cluster);
+			rl[rlpos].vcn = vcn;
+			vcn += rl[rlpos].length = max_cluster - deltaxcn;
+			rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
 			rlpos++;
 		} else if (unlikely(deltaxcn > max_cluster)) {
 			ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "
@@ -757,25 +897,26 @@
 					(long long)max_cluster);
 			goto mpa_err;
 		}
-		(rl + rlpos)->lcn = (LCN)LCN_ENOENT;
+		rl[rlpos].lcn = (LCN)LCN_ENOENT;
 	} else /* Not the base extent. There may be more extents to follow. */
-		(rl + rlpos)->lcn = (LCN)LCN_RL_NOT_MAPPED;
+		rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
 
 	/* Setup terminating run_list element. */
-	(rl + rlpos)->vcn = vcn;
-	(rl + rlpos)->length = (s64)0;
-	//RAR ntfs_debug("Mapping pairs array successfully decompressed.");
-	//RAR ntfs_debug_dump_runlist(rl);
+	rl[rlpos].vcn = vcn;
+	rl[rlpos].length = (s64)0;
 	/* If no existing run list was specified, we are done. */
-	if (!old_rl)
+	if (!old_rl) {
+		ntfs_debug("Mapping pairs array successfully decompressed:");
+		ntfs_debug_dump_runlist(rl);
 		return rl;
+	}
 	/* Now combine the new and old run lists checking for overlaps. */
-	rl2 = merge_run_lists(old_rl, rl);
-	if (likely(!IS_ERR(rl2)))
-		return rl2;
+	old_rl = ntfs_merge_run_lists(old_rl, rl);
+	if (likely(!IS_ERR(old_rl)))
+		return old_rl;
 	ntfs_free(rl);
 	ntfs_error(vol->sb, "Failed to merge run lists.");
-	return rl2;
+	return old_rl;
 io_error:
 	ntfs_error(vol->sb, "Corrupt attribute.");
 err_out:
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Fri Jul  5 16:42:59 2002
+++ b/fs/ntfs/dir.c	Fri Jul  5 16:42:59 2002
@@ -27,7 +27,7 @@
 /**
  * The little endian Unicode string $I30 as a global constant.
  */
-const uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
+uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
 		const_cpu_to_le16('3'),	const_cpu_to_le16('0'),
 		const_cpu_to_le16(0) };
 
diff -Nru a/fs/ntfs/dir.h b/fs/ntfs/dir.h
--- a/fs/ntfs/dir.h	Fri Jul  5 16:42:56 2002
+++ b/fs/ntfs/dir.h	Fri Jul  5 16:42:56 2002
@@ -38,7 +38,7 @@
 } __attribute__ ((__packed__)) ntfs_name;
 
 /* The little endian Unicode string $I30 as a global constant. */
-extern const uchar_t I30[5];
+extern uchar_t I30[5];
 
 extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
 		const uchar_t *uname, const int uname_len, ntfs_name **res);
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Fri Jul  5 16:42:59 2002
+++ b/fs/ntfs/inode.c	Fri Jul  5 16:42:59 2002
@@ -24,6 +24,178 @@
 
 #include "ntfs.h"
 #include "dir.h"
+#include "inode.h"
+#include "attrib.h"
+
+/**
+ * ntfs_attr - ntfs in memory attribute structure
+ * @mft_no:	mft record number of the base mft record of this attribute
+ * @name:	Unicode name of the attribute (NULL if unnamed)
+ * @name_len:	length of @name in Unicode characters (0 if unnamed)
+ * @type:	attribute type (see layout.h)
+ *
+ * This structure exists only to provide a small structure for the
+ * ntfs_iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
+ *
+ * NOTE: Elements are ordered by size to make the structure as compact as
+ * possible on all architectures.
+ */
+typedef struct {
+	unsigned long mft_no;
+	uchar_t *name;
+	u32 name_len;
+	ATTR_TYPES type;
+} ntfs_attr;
+
+/**
+ * ntfs_test_inode - compare two (possibly fake) inodes for equality
+ * @vi:		vfs inode which to test
+ * @na:		ntfs attribute which is being tested with
+ *
+ * Compare the ntfs attribute embedded in the ntfs specific part of the vfs
+ * inode @vi for equality with the ntfs attribute @na.
+ *
+ * If searching for the normal file/directory inode, set @na->type to AT_UNUSED.
+ * @na->name and @na->name_len are then ignored.
+ *
+ * Return 1 if the attributes match and 0 if not.
+ *
+ * NOTE: This function runs with the inode_lock spin lock held so it is not
+ * allowed to sleep.
+ */
+static int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
+{
+	ntfs_inode *ni;
+
+	if (vi->i_ino != na->mft_no)
+		return 0;
+	ni = NTFS_I(vi);
+	/* If !NInoAttr(ni), @vi is a normal file or directory inode. */
+	if (likely(!NInoAttr(ni))) {
+		/* If not looking for a normal inode this is a mismatch. */
+		if (unlikely(na->type != AT_UNUSED))
+			return 0;
+	} else {
+		/* A fake inode describing an attribute. */
+		if (ni->type != na->type)
+			return 0;
+		if (ni->name_len != na->name_len)
+			return 0;
+		if (na->name_len && memcmp(ni->name, na->name,
+				na->name_len * sizeof(uchar_t)))
+			return 0;
+	}
+	/* Match! */
+	return 1;
+}
+
+/**
+ * ntfs_init_locked_inode - initialize an inode
+ * @vi:		vfs inode to initialize
+ * @na:		ntfs attribute which to initialize @vi to
+ *
+ * Initialize the vfs inode @vi with the values from the ntfs attribute @na in
+ * order to enable ntfs_test_inode() to do its work.
+ *
+ * If initializing the normal file/directory inode, set @na->type to AT_UNUSED.
+ * In that case, @na->name and @na->name_len should be set to NULL and 0,
+ * respectively. Although that is not strictly necessary as
+ * ntfs_read_inode_locked() will fill them in later.
+ *
+ * Return 0 on success and -errno on error.
+ *
+ * NOTE: This function runs with the inode_lock spin lock held so it is not
+ * allowed to sleep. (Hence the GFP_ATOMIC allocation.)
+ */
+static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na)
+{
+	ntfs_inode *ni = NTFS_I(vi);
+
+	vi->i_ino = na->mft_no;
+	ni->type = na->type;
+	ni->name = na->name;
+	ni->name_len = na->name_len;
+	/* If initializing a normal inode, we are done. */
+	if (likely(na->type == AT_UNUSED))
+		return 0;
+	/* It is a fake inode. */
+	NInoSetAttr(ni);
+	/*
+	 * We have I30 global constant as an optimization as it is the name
+	 * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC
+	 * allocation but that is ok. And most attributes are unnamed anyway,
+	 * thus the fraction of named attributes with name != I30 is actually
+	 * absolutely tiny.
+	 */
+	if (na->name && na->name_len && na->name != I30) {
+		unsigned int i;
+
+		i = na->name_len * sizeof(uchar_t);
+		ni->name = (uchar_t*)kmalloc(i + sizeof(uchar_t), GFP_ATOMIC);
+		if (!ni->name)
+			return -ENOMEM;
+		memcpy(ni->name, na->name, i);
+		ni->name[i] = cpu_to_le16('\0');
+	}
+	return 0;
+}
+
+typedef int (*test_t)(struct inode *, void *);
+typedef int (*set_t)(struct inode *, void *);
+static void ntfs_read_locked_inode(struct inode *vi);
+
+/**
+ * ntfs_iget - obtain a struct inode corresponding to a specific normal inode
+ * @sb:		super block of mounted volume
+ * @mft_no:	mft record number / inode number to obtain
+ *
+ * Obtain the struct inode corresponding to a specific normal inode (i.e. a
+ * file or directory).
+ *
+ * If the inode is in the cache, it is just returned with an increased
+ * reference count. Otherwise, a new struct inode is allocated and initialized,
+ * and finally ntfs_read_locked_inode() is called to read in the inode and
+ * fill in the remainder of the inode structure.
+ *
+ * Return the struct inode on success. Check the return value with IS_ERR() and
+ * if true, the function failed and the error code is obtained from PTR_ERR().
+ */
+struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no)
+{
+	struct inode *vi;
+	ntfs_attr na;
+
+	na.mft_no = mft_no;
+	na.type = AT_UNUSED;
+	na.name = NULL;
+	na.name_len = 0;
+
+	vi = iget5_locked(sb, mft_no, (test_t)ntfs_test_inode,
+			(set_t)ntfs_init_locked_inode, &na);
+	if (!vi)
+		return ERR_PTR(-ENOMEM);
+
+	/* If this is a freshly allocated inode, need to read it now. */
+	if (vi->i_state & I_NEW) {
+		ntfs_read_locked_inode(vi);
+		unlock_new_inode(vi);
+	}
+#if 0
+	// TODO: Enable this and do the follow up cleanup, i.e. remove all the
+	// bad inode checks. -- BUT: Do we actually want to do this? -- It may
+	// result in repeated attemps to read a bad inode which is not
+	// desirable. (AIA)
+	/*
+	 * There is no point in keeping bad inodes around. This also simplifies
+	 * things in that we never need to check for bad inodes elsewhere.
+	 */
+	if (is_bad_inode(vi)) {
+		iput(vi);
+		vi = ERR_PTR(-EIO);
+	}
+#endif
+	return vi;
+}
 
 struct inode *ntfs_alloc_big_inode(struct super_block *sb)
 {
@@ -32,12 +204,12 @@
 	ntfs_debug("Entering.");
 	ni = (ntfs_inode *)kmem_cache_alloc(ntfs_big_inode_cache,
 			SLAB_NOFS);
-	if (!ni) {
-		ntfs_error(sb, "Allocation of NTFS big inode structure "
-				"failed.");
-		return NULL;
+	if (likely(ni != NULL)) {
+		ni->state = 0;
+		return VFS_I(ni);
 	}
-	return VFS_I(ni);
+	ntfs_error(sb, "Allocation of NTFS big inode structure failed.");
+	return NULL;
 }
 
 void ntfs_destroy_big_inode(struct inode *inode)
@@ -49,17 +221,20 @@
 	kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
 }
 
-ntfs_inode *ntfs_alloc_inode(void)
+static ntfs_inode *ntfs_alloc_extent_inode(void)
 {
 	ntfs_inode *ni = (ntfs_inode *)kmem_cache_alloc(ntfs_inode_cache,
 			SLAB_NOFS);
 	ntfs_debug("Entering.");
-	if (unlikely(!ni))
-		ntfs_error(NULL, "Allocation of NTFS inode structure failed.");
-	return ni;
+	if (likely(ni != NULL)) {
+		ni->state = 0;
+		return ni;
+	}
+	ntfs_error(NULL, "Allocation of NTFS inode structure failed.");
+	return NULL;
 }
 
-void ntfs_destroy_inode(ntfs_inode *ni)
+void ntfs_destroy_extent_inode(ntfs_inode *ni)
 {
 	ntfs_debug("Entering.");
 	BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
@@ -68,27 +243,42 @@
 
 /**
  * __ntfs_init_inode - initialize ntfs specific part of an inode
+ * @sb:		super block of mounted volume
+ * @ni:		freshly allocated ntfs inode which to initialize
  *
  * Initialize an ntfs inode to defaults.
  *
+ * NOTE: ni->mft_no, ni->state, ni->type, ni->name, and ni->name_len are left
+ * untouched. Make sure to initialize them elsewhere.
+ *
  * Return zero on success and -ENOMEM on error.
  */
 static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
 {
 	ntfs_debug("Entering.");
-	memset(ni, 0, sizeof(ntfs_inode));
+	ni->initialized_size = ni->allocated_size = 0;
+	ni->seq_no = 0;
 	atomic_set(&ni->count, 1);
-	ni->vol = NULL;
+	ni->vol = NTFS_SB(sb);
 	init_run_list(&ni->run_list);
 	init_rwsem(&ni->mrec_lock);
 	atomic_set(&ni->mft_count, 0);
 	ni->page = NULL;
+	ni->page_ofs = 0;
+	ni->attr_list_size = 0;
 	ni->attr_list = NULL;
 	init_run_list(&ni->attr_list_rl);
+	ni->_IDM(index_block_size) = 0;
+	ni->_IDM(index_vcn_size) = 0;
+	ni->_IDM(bmp_size) = 0;
+	ni->_IDM(bmp_initialized_size) = 0;
+	ni->_IDM(bmp_allocated_size) = 0;
 	init_run_list(&ni->_IDM(bmp_rl));
+	ni->_IDM(index_block_size_bits) = 0;
+	ni->_IDM(index_vcn_size_bits) = 0;
 	init_MUTEX(&ni->extent_lock);
+	ni->nr_extents = 0;
 	ni->_INE(base_ntfs_ino) = NULL;
-	ni->vol = NTFS_SB(sb);
 	return;
 }
 
@@ -102,13 +292,18 @@
 	return;
 }
 
-ntfs_inode *ntfs_new_inode(struct super_block *sb)
+ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, unsigned long mft_no)
 {
-	ntfs_inode *ni = ntfs_alloc_inode();
+	ntfs_inode *ni = ntfs_alloc_extent_inode();
 
 	ntfs_debug("Entering.");
-	if (ni)
+	if (likely(ni != NULL)) {
 		__ntfs_init_inode(sb, ni);
+		ni->mft_no = mft_no;
+		ni->type = AT_UNUSED;
+		ni->name = NULL;
+		ni->name_len = 0;
+	}
 	return ni;
 }
 
@@ -189,18 +384,20 @@
 }
 
 /**
- * ntfs_read_inode - read an inode from its device
+ * ntfs_read_locked_inode - read an inode from its device
  * @vi:		inode to read
  *
- * ntfs_read_inode() is called from the VFS iget() function to read the inode
+ * ntfs_read_locked_inode() is called from the ntfs_iget() to read the inode
  * described by @vi into memory from the device.
  *
  * The only fields in @vi that we need to/can look at when the function is
  * called are i_sb, pointing to the mounted device's super block, and i_ino,
- * the number of the inode to load.
+ * the number of the inode to load. If this is a fake inode, i.e. NInoAttr(),
+ * then the fields type, name, and name_len are also valid, and describe the
+ * attribute which this fake inode represents.
  *
- * ntfs_read_inode() maps, pins and locks the mft record number i_ino for
- * reading and sets up the necessary @vi fields as well as initializing
+ * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
+ * for reading and sets up the necessary @vi fields as well as initializing
  * the ntfs inode.
  *
  * Q: What locks are held when the function is called?
@@ -209,9 +406,9 @@
  *    i_flags is set to 0 and we have no business touching it. Only an ioctl()
  *    is allowed to write to them. We should of course be honouring them but
  *    we need to do that using the IS_* macros defined in include/linux/fs.h.
- *    In any case ntfs_read_inode() has nothing to do with i_flags at all.
+ *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
  */
-void ntfs_read_inode(struct inode *vi)
+static void ntfs_read_locked_inode(struct inode *vi)
 {
 	ntfs_volume *vol = NTFS_SB(vi->i_sb);
 	ntfs_inode *ni;
@@ -239,7 +436,8 @@
 
 	/*
 	 * Initialize the ntfs specific part of @vi special casing
-	 * FILE_MFT which we need to do at mount time.
+	 * FILE_MFT which we need to do at mount time. This also sets
+	 * ni->mft_no to vi->i_ino.
 	 */
 	if (vi->i_ino != FILE_MFT)
 		ntfs_init_big_inode(vi);
@@ -358,13 +556,14 @@
 		if (vi->i_ino == FILE_MFT)
 			goto skip_attr_list_load;
 		ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
-		ni->state |= 1 << NI_AttrList;
+		NInoSetAttrList(ni);
 		if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||
-				ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+				ctx->attr->flags & ATTR_COMPRESSION_MASK ||
+				ctx->attr->flags & ATTR_IS_SPARSE) {
 			ntfs_error(vi->i_sb, "Attribute list attribute is "
-					"compressed/encrypted. Not allowed. "
-					"Corrupt inode. You should run "
-					"chkdsk.");
+					"compressed/encrypted/sparse. Not "
+					"allowed. Corrupt inode. You should "
+					"run chkdsk.");
 			goto put_unm_err_out;
 		}
 		/* Now allocate memory for the attribute list. */
@@ -377,7 +576,7 @@
 			goto ec_put_unm_err_out;
 		}
 		if (ctx->attr->non_resident) {
-			ni->state |= 1 << NI_AttrListNonResident;
+			NInoSetAttrListNonResident(ni);
 			if (ctx->attr->_ANR(lowest_vcn)) {
 				ntfs_error(vi->i_sb, "Attribute list has non "
 						"zero lowest_vcn. Inode is "
@@ -459,7 +658,7 @@
 		 * encrypted.
 		 */
 		if (ctx->attr->flags & ATTR_COMPRESSION_MASK)
-			ni->state |= 1 << NI_Compressed;
+			NInoSetCompressed(ni);
 		if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
 			if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
 				ntfs_error(vi->i_sb, "Found encrypted and "
@@ -467,8 +666,10 @@
 						"allowed.");
 				goto put_unm_err_out;
 			}
-			ni->state |= 1 << NI_Encrypted;
+			NInoSetEncrypted(ni);
 		}
+		if (ctx->attr->flags & ATTR_IS_SPARSE)
+			NInoSetSparse(ni);
 		ir = (INDEX_ROOT*)((char*)ctx->attr +
 				le16_to_cpu(ctx->attr->_ARA(value_offset)));
 		ir_end = (char*)ir + le32_to_cpu(ctx->attr->_ARA(value_length));
@@ -530,12 +731,19 @@
 			ni->_IDM(index_vcn_size) = vol->sector_size;
 			ni->_IDM(index_vcn_size_bits) = vol->sector_size_bits;
 		}
+
+		/* Setup the index allocation attribute, even if not present. */
+		NInoSetMstProtected(ni);
+		ni->type = AT_INDEX_ALLOCATION;
+		ni->name = I30;
+		ni->name_len = 4;
+
 		if (!(ir->index.flags & LARGE_INDEX)) {
 			/* No index allocation. */
 			vi->i_size = ni->initialized_size = 0;
 			goto skip_large_dir_stuff;
 		} /* LARGE_INDEX: Index allocation present. Setup state. */
-		ni->state |= 1 << NI_NonResident;
+		NInoSetIndexAllocPresent(ni);
 		/* Find index allocation attribute. */
 		reinit_attr_search_ctx(ctx);
 		if (!lookup_attr(AT_INDEX_ALLOCATION, I30, 4, CASE_SENSITIVE,
@@ -555,6 +763,11 @@
 					"is encrypted.");
 			goto put_unm_err_out;
 		}
+		if (ctx->attr->flags & ATTR_IS_SPARSE) {
+			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
+					"is sparse.");
+			goto put_unm_err_out;
+		}
 		if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
 			ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
 					"is compressed.");
@@ -581,13 +794,13 @@
 			goto put_unm_err_out;
 		}
 		if (ctx->attr->flags & (ATTR_COMPRESSION_MASK |
-				ATTR_IS_ENCRYPTED)) {
+				ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) {
 			ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
-					"and/or encrypted.");
+					"and/or encrypted and/or sparse.");
 			goto put_unm_err_out;
 		}
 		if (ctx->attr->non_resident) {
-			ni->state |= 1 << NI_BmpNonResident;
+			NInoSetBmpNonResident(ni);
 			if (ctx->attr->_ANR(lowest_vcn)) {
 				ntfs_error(vi->i_sb, "First extent of $BITMAP "
 						"attribute has non zero "
@@ -645,8 +858,15 @@
 		vi->i_fop = &ntfs_dir_ops;
 		vi->i_mapping->a_ops = &ntfs_dir_aops;
 	} else {
-		/* It is a file: find first extent of unnamed data attribute. */
+		/* It is a file. */
 		reinit_attr_search_ctx(ctx);
+
+		/* Setup the data attribute, even if not present. */
+		ni->type = AT_DATA;
+		ni->name = NULL;
+		ni->name_len = 0;
+
+		/* Find first extent of the unnamed data attribute. */
 		if (!lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx)) {
 			vi->i_size = ni->initialized_size =
 					ni->allocated_size = 0LL;
@@ -675,9 +895,9 @@
 		}
 		/* Setup the state. */
 		if (ctx->attr->non_resident) {
-			ni->state |= 1 << NI_NonResident;
+			NInoSetNonResident(ni);
 			if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
-				ni->state |= 1 << NI_Compressed;
+				NInoSetCompressed(ni);
 				if (vol->cluster_size > 4096) {
 					ntfs_error(vi->i_sb, "Found "
 						"compressed data but "
@@ -707,8 +927,9 @@
 					goto ec_put_unm_err_out;
 				}
 				ni->_ICF(compression_block_size) = 1U << (
-					       ctx->attr->_ANR(compression_unit)
-						+ vol->cluster_size_bits);
+						ctx->attr->_ANR(
+						compression_unit) +
+						vol->cluster_size_bits);
 				ni->_ICF(compression_block_size_bits) = ffs(
 					ni->_ICF(compression_block_size)) - 1;
 			}
@@ -718,8 +939,10 @@
 							"and compressed data.");
 					goto put_unm_err_out;
 				}
-				ni->state |= 1 << NI_Encrypted;
+				NInoSetEncrypted(ni);
 			}
+			if (ctx->attr->flags & ATTR_IS_SPARSE)
+				NInoSetSparse(ni);
 			if (ctx->attr->_ANR(lowest_vcn)) {
 				ntfs_error(vi->i_sb, "First extent of $DATA "
 						"attribute has non zero "
@@ -852,15 +1075,24 @@
 
 	ntfs_debug("Entering.");
 
-	/* Initialize the ntfs specific part of @vi. */
-	ntfs_init_big_inode(vi);
-	ni = NTFS_I(vi);
 	if (vi->i_ino != FILE_MFT) {
 		ntfs_error(sb, "Called for inode 0x%lx but only inode %d "
 				"allowed.", vi->i_ino, FILE_MFT);
 		goto err_out;
 	}
 
+	/* Initialize the ntfs specific part of @vi. */
+	ntfs_init_big_inode(vi);
+
+	ni = NTFS_I(vi);
+
+	/* Setup the data attribute. It is special as it is mst protected. */
+	NInoSetNonResident(ni);
+	NInoSetMstProtected(ni);
+	ni->type = AT_DATA;
+	ni->name = NULL;
+	ni->name_len = 0;
+
 	/*
 	 * This sets up our little cheat allowing us to reuse the async io
 	 * completion handler for directories.
@@ -930,13 +1162,14 @@
 		u8 *al_end;
 
 		ntfs_debug("Attribute list attribute found in $MFT.");
-		ni->state |= 1 << NI_AttrList;
+		NInoSetAttrList(ni);
 		if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||
-				ctx->attr->flags & ATTR_COMPRESSION_MASK) {
+				ctx->attr->flags & ATTR_COMPRESSION_MASK ||
+				ctx->attr->flags & ATTR_IS_SPARSE) {
 			ntfs_error(sb, "Attribute list attribute is "
-					"compressed/encrypted. Not allowed. "
-					"$MFT is corrupt. You should run "
-					"chkdsk.");
+					"compressed/encrypted/sparse. Not "
+					"allowed. $MFT is corrupt. You should "
+					"run chkdsk.");
 			goto put_err_out;
 		}
 		/* Now allocate memory for the attribute list. */
@@ -948,7 +1181,7 @@
 			goto put_err_out;
 		}
 		if (ctx->attr->non_resident) {
-			ni->state |= 1 << NI_AttrListNonResident;
+			NInoSetAttrListNonResident(ni);
 			if (ctx->attr->_ANR(lowest_vcn)) {
 				ntfs_error(sb, "Attribute list has non zero "
 						"lowest_vcn. $MFT is corrupt. "
@@ -1071,11 +1304,13 @@
 		}
 		/* $MFT must be uncompressed and unencrypted. */
 		if (attr->flags & ATTR_COMPRESSION_MASK ||
-				attr->flags & ATTR_IS_ENCRYPTED) {
-			ntfs_error(sb, "$MFT must be uncompressed and "
-					"unencrypted but a compressed/"
-					"encrypted extent was found. "
-					"$MFT is corrupt. Run chkdsk.");
+				attr->flags & ATTR_IS_ENCRYPTED ||
+				attr->flags & ATTR_IS_SPARSE) {
+			ntfs_error(sb, "$MFT must be uncompressed, "
+					"non-sparse, and unencrypted but a "
+					"compressed/sparse/encrypted extent "
+					"was found. $MFT is corrupt. Run "
+					"chkdsk.");
 			goto put_err_out;
 		}
 		/*
@@ -1123,7 +1358,7 @@
 				ntfs_error(sb, "$MFT is too big! Aborting.");
 				goto put_err_out;
 			}
-			vol->_VMM(nr_mft_records) = ll;
+			vol->nr_mft_records = ll;
 			/*
 			 * We have got the first extent of the run_list for
 			 * $MFT which means it is now relatively safe to call
@@ -1149,7 +1384,7 @@
 			 * ntfs_read_inode() on extents of $MFT/$DATA. But lets
 			 * hope this never happens...
 			 */
-			ntfs_read_inode(vi);
+			ntfs_read_locked_inode(vi);
 			if (is_bad_inode(vi)) {
 				ntfs_error(sb, "ntfs_read_inode() of $MFT "
 						"failed. BUG or corrupt $MFT. "
@@ -1296,29 +1531,42 @@
 
 		// FIXME: Handle dirty case for each extent inode!
 		for (i = 0; i < ni->nr_extents; i++)
-			ntfs_destroy_inode(ni->_INE(extent_ntfs_inos)[i]);
+			ntfs_clear_extent_inode(ni->_INE(extent_ntfs_inos)[i]);
 		kfree(ni->_INE(extent_ntfs_inos));
 	}
 	/* Free all alocated memory. */
 	down_write(&ni->run_list.lock);
-	ntfs_free(ni->run_list.rl);
-	ni->run_list.rl = NULL;
+	if (ni->run_list.rl) {
+		ntfs_free(ni->run_list.rl);
+		ni->run_list.rl = NULL;
+	}
 	up_write(&ni->run_list.lock);
 
-	ntfs_free(ni->attr_list);
+	if (ni->attr_list) {
+		ntfs_free(ni->attr_list);
+		ni->attr_list = NULL;
+	}
 
 	down_write(&ni->attr_list_rl.lock);
-	ntfs_free(ni->attr_list_rl.rl);
-	ni->attr_list_rl.rl = NULL;
+	if (ni->attr_list_rl.rl) {
+		ntfs_free(ni->attr_list_rl.rl);
+		ni->attr_list_rl.rl = NULL;
+	}
 	up_write(&ni->attr_list_rl.lock);
+
+	if (ni->name_len && ni->name != I30) {
+		/* Catch bugs... */
+		BUG_ON(!ni->name);
+		kfree(ni->name);
+	}
 }
 
-void ntfs_clear_inode(ntfs_inode *ni)
+void ntfs_clear_extent_inode(ntfs_inode *ni)
 {
 	__ntfs_clear_inode(ni);
 
 	/* Bye, bye... */
-	ntfs_destroy_inode(ni);
+	ntfs_destroy_extent_inode(ni);
 }
 
 /**
@@ -1339,7 +1587,8 @@
 
 	if (S_ISDIR(vi->i_mode)) {
 		down_write(&ni->_IDM(bmp_rl).lock);
-		ntfs_free(ni->_IDM(bmp_rl).rl);
+		if (ni->_IDM(bmp_rl).rl)
+			ntfs_free(ni->_IDM(bmp_rl).rl);
 		up_write(&ni->_IDM(bmp_rl).lock);
 	}
 	return;
diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h
--- a/fs/ntfs/inode.h	Fri Jul  5 16:43:00 2002
+++ b/fs/ntfs/inode.h	Fri Jul  5 16:43:00 2002
@@ -3,7 +3,7 @@
  *	     the Linux-NTFS project.
  *
  * Copyright (c) 2001,2002 Anton Altaparmakov.
- * Copyright (C) 2002 Richard Russon.
+ * Copyright (c) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -26,6 +26,7 @@
 
 #include <linux/seq_file.h>
 
+#include "layout.h"
 #include "volume.h"
 
 typedef struct _ntfs_inode ntfs_inode;
@@ -38,21 +39,39 @@
 	s64 initialized_size;	/* Copy from $DATA/$INDEX_ALLOCATION. */
 	s64 allocated_size;	/* Copy from $DATA/$INDEX_ALLOCATION. */
 	unsigned long state;	/* NTFS specific flags describing this inode.
-				   See fs/ntfs/ntfs.h:ntfs_inode_state_bits. */
+				   See ntfs_inode_state_bits below. */
 	unsigned long mft_no;	/* Number of the mft record / inode. */
 	u16 seq_no;		/* Sequence number of the mft record. */
 	atomic_t count;		/* Inode reference count for book keeping. */
 	ntfs_volume *vol;	/* Pointer to the ntfs volume of this inode. */
+	/*
+	 * If NInoAttr() is true, the below fields describe the attribute which
+	 * this fake inode belongs to. The actual inode of this attribute is
+	 * pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
+	 * below). For real inodes, we also set the type (AT_DATA for files and
+	 * AT_INDEX_ALLOCATION for directories), with the name = NULL and
+	 * name_len = 0 for files and name = I30 (global constant) and
+	 * name_len = 4 for directories.
+	 */
+	ATTR_TYPES type;	/* Attribute type of this fake inode. */
+	uchar_t *name;		/* Attribute name of this fake inode. */
+	u32 name_len;		/* Attribute name length of this fake inode. */
 	run_list run_list;	/* If state has the NI_NonResident bit set,
 				   the run list of the unnamed data attribute
 				   (if a file) or of the index allocation
-				   attribute (directory). If run_list.rl is
-				   NULL, the run list has not been read in or
-				   has been unmapped. If NI_NonResident is
-				   clear, the unnamed data attribute is
-				   resident (file) or there is no $I30 index
-				   allocation attribute (directory). In that
-				   case run_list.rl is always NULL.*/
+				   attribute (directory) or of the attribute
+				   described by the fake inode (if NInoAttr()).
+				   If run_list.rl is NULL, the run list has not
+				   been read in yet or has been unmapped. If
+				   NI_NonResident is clear, the attribute is
+				   resident (file and fake inode) or there is
+				   no $I30 index allocation attribute
+				   (small directory). In the latter case
+				   run_list.rl is always NULL.*/
+	/*
+	 * The following fields are only valid for real inodes and extent
+	 * inodes.
+	 */
 	struct rw_semaphore mrec_lock;	/* Lock for serializing access to the
 				   mft record belonging to this inode. */
 	atomic_t mft_count;	/* Mapping reference count for book keeping. */
@@ -74,17 +93,18 @@
 	union {
 		struct { /* It is a directory or $MFT. */
 			u32 index_block_size;	/* Size of an index block. */
-			u8 index_block_size_bits; /* Log2 of the above. */
 			u32 index_vcn_size;	/* Size of a vcn in this
 						   directory index. */
-			u8 index_vcn_size_bits;	/* Log2 of the above. */
 			s64 bmp_size;		/* Size of the $I30 bitmap. */
 			s64 bmp_initialized_size; /* Copy from $I30 bitmap. */
 			s64 bmp_allocated_size;	/* Copy from $I30 bitmap. */
 			run_list bmp_rl;	/* Run list for the $I30 bitmap
 						   if it is non-resident. */
+			u8 index_block_size_bits; /* Log2 of the above. */
+			u8 index_vcn_size_bits;	/* Log2 of the above. */
 		} SN(idm);
-		struct { /* It is a compressed file. */
+		struct { /* It is a compressed file or fake inode. */
+			s64 compressed_size;		/* Copy from $DATA. */
 			u32 compression_block_size;     /* Size of a compression
 						           block (cb). */
 			u8 compression_block_size_bits; /* Log2 of the size of
@@ -92,13 +112,13 @@
 			u8 compression_block_clusters;  /* Number of clusters
 							   per compression
 							   block. */
-			s64 compressed_size;		/* Copy from $DATA. */
 		} SN(icf);
 	} SN(idc);
 	struct semaphore extent_lock;	/* Lock for accessing/modifying the
 					   below . */
 	s32 nr_extents;	/* For a base mft record, the number of attached extent
-			   inodes (0 if none), for extent records this is -1. */
+			   inodes (0 if none), for extent records and for fake
+			   inodes describing an attribute this is -1. */
 	union {		/* This union is only used if nr_extents != 0. */
 		ntfs_inode **extent_ntfs_inos;	/* For nr_extents > 0, array of
 						   the ntfs inodes of the extent
@@ -107,7 +127,9 @@
 						   been loaded. */
 		ntfs_inode *base_ntfs_ino;	/* For nr_extents == -1, the
 						   ntfs inode of the base mft
-						   record. */
+						   record. For fake inodes, the
+						   real (base) inode to which
+						   the attribute belongs. */
 	} SN(ine);
 };
 
@@ -115,6 +137,79 @@
 #define _ICF(X)  SC(idc.icf,X)
 #define _INE(X)  SC(ine,X)
 
+/*
+ * Defined bits for the state field in the ntfs_inode structure.
+ * (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
+ */
+typedef enum {
+	NI_Dirty,		/* 1: Mft record needs to be written to disk. */
+	NI_AttrList,		/* 1: Mft record contains an attribute list. */
+	NI_AttrListNonResident,	/* 1: Attribute list is non-resident. Implies
+				      NI_AttrList is set. */
+
+	NI_Attr,		/* 1: Fake inode for attribute i/o.
+				   0: Real inode or extent inode. */
+
+	NI_MstProtected,	/* 1: Attribute is protected by MST fixups.
+				   0: Attribute is not protected by fixups. */
+	NI_NonResident,		/* 1: Unnamed data attr is non-resident (f).
+				   1: Attribute is non-resident (a). */
+	NI_IndexAllocPresent = NI_NonResident,	/* 1: $I30 index alloc attr is
+						   present (d). */
+	NI_Compressed,		/* 1: Unnamed data attr is compressed (f).
+				   1: Create compressed files by default (d).
+				   1: Attribute is compressed (a). */
+	NI_Encrypted,		/* 1: Unnamed data attr is encrypted (f).
+				   1: Create encrypted files by default (d).
+				   1: Attribute is encrypted (a). */
+	NI_Sparse,		/* 1: Unnamed data attr is sparse (f).
+				   1: Create sparse files by default (d).
+				   1: Attribute is sparse (a). */
+	NI_BmpNonResident,	/* 1: $I30 bitmap attr is non resident (d). */
+} ntfs_inode_state_bits;
+
+/*
+ * NOTE: We should be adding dirty mft records to a list somewhere and they
+ * should be independent of the (ntfs/vfs) inode structure so that an inode can
+ * be removed but the record can be left dirty for syncing later.
+ */
+
+/*
+ * Macro tricks to expand the NInoFoo(), NInoSetFoo(), and NInoClearFoo()
+ * functions.
+ */
+#define NINO_FNS(flag)					\
+static inline int NIno##flag(ntfs_inode *ni)		\
+{							\
+	return test_bit(NI_##flag, &(ni)->state);	\
+}							\
+static inline void NInoSet##flag(ntfs_inode *ni)	\
+{							\
+	set_bit(NI_##flag, &(ni)->state);		\
+}							\
+static inline void NInoClear##flag(ntfs_inode *ni)	\
+{							\
+	clear_bit(NI_##flag, &(ni)->state);		\
+}
+
+/* Emit the ntfs inode bitops functions. */
+NINO_FNS(Dirty)
+NINO_FNS(AttrList)
+NINO_FNS(AttrListNonResident)
+NINO_FNS(Attr)
+NINO_FNS(MstProtected)
+NINO_FNS(NonResident)
+NINO_FNS(IndexAllocPresent)
+NINO_FNS(Compressed)
+NINO_FNS(Encrypted)
+NINO_FNS(Sparse)
+NINO_FNS(BmpNonResident)
+
+/*
+ * The full structure containing a ntfs_inode and a vfs struct inode. Used for
+ * all real and fake inodes but not for extent inodes which lack the vfs struct
+ * inode.
+ */
 typedef struct {
 	ntfs_inode ntfs_inode;
 	struct inode vfs_inode;		/* The vfs inode structure. */
@@ -136,14 +231,16 @@
 	return &((big_ntfs_inode*)ni)->vfs_inode;
 }
 
+extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
+
 extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
 extern void ntfs_destroy_big_inode(struct inode *inode);
 extern void ntfs_clear_big_inode(struct inode *vi);
 
-extern ntfs_inode *ntfs_new_inode(struct super_block *sb);
-extern void ntfs_clear_inode(ntfs_inode *ni);
+extern ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
+		unsigned long mft_no);
+extern void ntfs_clear_extent_inode(ntfs_inode *ni);
 
-extern void ntfs_read_inode(struct inode *vi);
 extern void ntfs_read_inode_mount(struct inode *vi);
 
 extern void ntfs_dirty_inode(struct inode *vi);
diff -Nru a/fs/ntfs/mft.c b/fs/ntfs/mft.c
--- a/fs/ntfs/mft.c	Fri Jul  5 16:42:56 2002
+++ b/fs/ntfs/mft.c	Fri Jul  5 16:42:56 2002
@@ -102,7 +102,7 @@
  * ntfs_mft_aops - address space operations for access to $MFT
  *
  * Address space operations for access to $MFT. This allows us to simply use
- * read_cache_page() in map_mft_record().
+ * ntfs_map_page() in map_mft_record_page().
  */
 struct address_space_operations ntfs_mft_aops = {
 	writepage:	NULL,			/* Write dirty page to disk. */
@@ -334,9 +334,9 @@
 
 	/*
 	 * If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
-	 * ntfs_clear_inode() in the extent inode case, and to the caller in
-	 * the non-extent, yet pure ntfs inode case, to do the actual tear
-	 * down of all structures and freeing of all allocated memory.
+	 * ntfs_clear_extent_inode() in the extent inode case, and to the
+	 * caller in the non-extent, yet pure ntfs inode case, to do the actual
+	 * tear down of all structures and freeing of all allocated memory.
 	 */
 	return;
 }
@@ -417,14 +417,13 @@
 		return m;
 	}
 	/* Record wasn't there. Get a new ntfs inode and initialize it. */
-	ni = ntfs_new_inode(base_ni->vol->sb);
+	ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
 	if (!ni) {
 		up(&base_ni->extent_lock);
 		atomic_dec(&base_ni->count);
 		return ERR_PTR(-ENOMEM);
 	}
 	ni->vol = base_ni->vol;
-	ni->mft_no = mft_no;
 	ni->seq_no = seq_no;
 	ni->nr_extents = -1;
 	ni->_INE(base_ntfs_ino) = base_ni;
@@ -433,7 +432,7 @@
 	if (IS_ERR(m)) {
 		up(&base_ni->extent_lock);
 		atomic_dec(&base_ni->count);
-		ntfs_clear_inode(ni);
+		ntfs_clear_extent_inode(ni);
 		goto map_err_out;
 	}
 	/* Verify the sequence number. */
@@ -479,7 +478,7 @@
 	 * release it or we will leak memory.
 	 */
 	if (destroy_ni)
-		ntfs_clear_inode(ni);
+		ntfs_clear_extent_inode(ni);
 	return m;
 }
 
diff -Nru a/fs/ntfs/mst.c b/fs/ntfs/mst.c
--- a/fs/ntfs/mst.c	Fri Jul  5 16:42:56 2002
+++ b/fs/ntfs/mst.c	Fri Jul  5 16:42:56 2002
@@ -48,7 +48,7 @@
 	usa_ofs = le16_to_cpu(b->usa_ofs);
 	/* Decrement usa_count to get number of fixups. */
 	usa_count = le16_to_cpu(b->usa_count) - 1;
-	/* Size and alignement checks. */
+	/* Size and alignment checks. */
 	if ( size & (NTFS_BLOCK_SIZE - 1)	||
 	     usa_ofs & 1			||
 	     usa_ofs + (usa_count * 2) > size	||
@@ -132,7 +132,7 @@
 	usa_ofs = le16_to_cpu(b->usa_ofs);
 	/* Decrement usa_count to get number of fixups. */
 	usa_count = le16_to_cpu(b->usa_count) - 1;
-	/* Size and alignement checks. */
+	/* Size and alignment checks. */
 	if ( size & (NTFS_BLOCK_SIZE - 1)	||
 	     usa_ofs & 1			||
 	     usa_ofs + (usa_count * 2) > size	||
diff -Nru a/fs/ntfs/namei.c b/fs/ntfs/namei.c
--- a/fs/ntfs/namei.c	Fri Jul  5 16:43:00 2002
+++ b/fs/ntfs/namei.c	Fri Jul  5 16:43:00 2002
@@ -38,8 +38,8 @@
  * supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
  * converts the name to Unicode and walks the contents of the directory inode
  * @dir_ino looking for the converted Unicode name. If the name is found in the
- * directory, the corresponding inode is loaded by calling iget() on its inode
- * number and the inode is associated with the dentry @dent via a call to
+ * directory, the corresponding inode is loaded by calling ntfs_iget() on its
+ * inode number and the inode is associated with the dentry @dent via a call to
  * d_add().
  *
  * If the name is not found in the directory, a NULL inode is inserted into the
@@ -111,9 +111,9 @@
 	kmem_cache_free(ntfs_name_cache, uname);
 	if (!IS_ERR_MREF(mref)) {
 		dent_ino = MREF(mref);
-		ntfs_debug("Found inode 0x%lx. Calling iget.", dent_ino);
-		dent_inode = iget(vol->sb, dent_ino);
-		if (dent_inode) {
+		ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
+		dent_inode = ntfs_iget(vol->sb, dent_ino);
+		if (likely(!IS_ERR(dent_inode))) {
 			/* Consistency check. */
 			if (MSEQNO(mref) == NTFS_I(dent_inode)->seq_no ||
 					dent_ino == FILE_MFT) {
@@ -132,16 +132,19 @@
 			ntfs_error(vol->sb, "Found stale reference to inode "
 					"0x%lx (reference sequence number = "
 					"0x%x, inode sequence number = 0x%x, "
-					"returning -EACCES. Run chkdsk.",
+					"returning -EIO. Run chkdsk.",
 					dent_ino, MSEQNO(mref),
 					NTFS_I(dent_inode)->seq_no);
 			iput(dent_inode);
+			dent_inode = ERR_PTR(-EIO);
 		} else
-			ntfs_error(vol->sb, "iget(0x%lx) failed, returning "
-					"-EACCES.", dent_ino);
+			ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
+				   "error code %li.", dent_ino,
+				   PTR_ERR(dent_inode));
 		if (name)
 			kfree(name);
-		return ERR_PTR(-EACCES);
+		/* Return the error code. */
+		return (struct dentry *)dent_inode;
 	}
 	/* It is guaranteed that name is no longer allocated at this point. */
 	if (MREF_ERR(mref) == -ENOENT) {
@@ -256,7 +259,8 @@
 		BUG_ON(real_dent->d_inode != dent_inode);
 		/*
 		 * Already have the inode and the dentry attached, decrement
-		 * the reference count to balance the iget() we did earlier on.
+		 * the reference count to balance the ntfs_iget() we did
+		 * earlier on.
 		 */
 		iput(dent_inode);
 		return real_dent;
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Fri Jul  5 16:42:59 2002
+++ b/fs/ntfs/ntfs.h	Fri Jul  5 16:42:59 2002
@@ -53,41 +53,6 @@
 	NTFS_MAX_NAME_LEN	= 255,
 } NTFS_CONSTANTS;
 
-/*
- * Defined bits for the state field in the ntfs_inode structure.
- * (f) = files only, (d) = directories only
- */
-typedef enum {
-	NI_Dirty,		/* 1: Mft record needs to be written to disk. */
-	NI_AttrList,		/* 1: Mft record contains an attribute list. */
-	NI_AttrListNonResident,	/* 1: Attribute list is non-resident. Implies
-				      NI_AttrList is set. */
-	NI_NonResident,		/* 1: Unnamed data attr is non-resident (f).
-				   1: $I30 index alloc attr is present (d). */
-	NI_Compressed,		/* 1: Unnamed data attr is compressed (f).
-				   1: Create compressed files by default (d). */
-	NI_Encrypted,		/* 1: Unnamed data attr is encrypted (f).
-				   1: Create encrypted files by default (d). */
-	NI_BmpNonResident,	/* 1: $I30 bitmap attr is non resident (d). */
-} ntfs_inode_state_bits;
-
-/*
- * NOTE: We should be adding dirty mft records to a list somewhere and they
- * should be independent of the (ntfs/vfs) inode structure so that an inode can
- * be removed but the record can be left dirty for syncing later.
- */
-
-#define NInoDirty(n_ino)	  test_bit(NI_Dirty, &(n_ino)->state)
-#define NInoSetDirty(n_ino)	  set_bit(NI_Dirty, &(n_ino)->state)
-#define NInoClearDirty(n_ino)	  clear_bit(NI_Dirty, &(n_ino)->state)
-
-#define NInoAttrList(n_ino)	  test_bit(NI_AttrList, &(n_ino)->state)
-#define NInoNonResident(n_ino)	  test_bit(NI_NonResident, &(n_ino)->state)
-#define NInoIndexAllocPresent(n_ino) test_bit(NI_NonResident, &(n_ino)->state)
-#define NInoCompressed(n_ino)	  test_bit(NI_Compressed, &(n_ino)->state)
-#define NInoEncrypted(n_ino)	  test_bit(NI_Encrypted, &(n_ino)->state)
-#define NInoBmpNonResident(n_ino) test_bit(NI_BmpNonResident, &(n_ino)->state)
-
 /* Global variables. */
 
 /* Slab caches (from super.c). */
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Fri Jul  5 16:42:59 2002
+++ b/fs/ntfs/super.c	Fri Jul  5 16:42:59 2002
@@ -605,17 +605,17 @@
 				sizeof(unsigned long) * 4);
 		return FALSE;
 	}
-	vol->_VCL(nr_clusters) = ll;
-	ntfs_debug("vol->nr_clusters = 0x%Lx", (long long)vol->_VCL(nr_clusters));
+	vol->nr_clusters = ll;
+	ntfs_debug("vol->nr_clusters = 0x%Lx", (long long)vol->nr_clusters);
 	ll = sle64_to_cpu(b->mft_lcn);
-	if (ll >= vol->_VCL(nr_clusters)) {
+	if (ll >= vol->nr_clusters) {
 		ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird.");
 		return FALSE;
 	}
 	vol->mft_lcn = ll;
 	ntfs_debug("vol->mft_lcn = 0x%Lx", (long long)vol->mft_lcn);
 	ll = sle64_to_cpu(b->mftmirr_lcn);
-	if (ll >= vol->_VCL(nr_clusters)) {
+	if (ll >= vol->nr_clusters) {
 		ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. "
 				"Weird.");
 		return FALSE;
@@ -629,7 +629,7 @@
 	 * Determine MFT zone size. This is not strictly the right place to do
 	 * this, but I am too lazy to create a function especially for it...
 	 */
-	vol->mft_zone_end = vol->_VCL(nr_clusters);
+	vol->mft_zone_end = vol->nr_clusters;
 	switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */
 	case 4:
 		vol->mft_zone_end = vol->mft_zone_end >> 1;	/* 50%   */
@@ -678,9 +678,9 @@
 
 	ntfs_debug("Entering.");
 	/* Read upcase table and setup vol->upcase and vol->upcase_len. */
-	ino = iget(sb, FILE_UpCase);
-	if (!ino || is_bad_inode(ino)) {
-		if (ino)
+	ino = ntfs_iget(sb, FILE_UpCase);
+	if (IS_ERR(ino) || is_bad_inode(ino)) {
+		if (!IS_ERR(ino))
 			iput(ino);
 		goto upcase_failed;
 	}
@@ -848,7 +848,7 @@
 			vol->mftbmp_allocated_size =
 					sle64_to_cpu(attr->_ANR(allocated_size));
 			/* Consistency check. */
-			if (vol->mftbmp_size < (vol->_VMM(nr_mft_records) + 7) >> 3) {
+			if (vol->mftbmp_size < (vol->nr_mft_records + 7) >> 3) {
 				ntfs_error(sb, "$MFT/$BITMAP is too short to "
 						"contain a complete mft "
 						"bitmap: impossible. $MFT is "
@@ -914,9 +914,9 @@
 	// volume read-write...
 
 	/* Get mft mirror inode. */
-	vol->mftmirr_ino = iget(sb, FILE_MFTMirr);
-	if (!vol->mftmirr_ino || is_bad_inode(vol->mftmirr_ino)) {
-		if (is_bad_inode(vol->mftmirr_ino))
+	vol->mftmirr_ino = ntfs_iget(sb, FILE_MFTMirr);
+	if (IS_ERR(vol->mftmirr_ino) || is_bad_inode(vol->mftmirr_ino)) {
+		if (!IS_ERR(vol->mftmirr_ino))
 			iput(vol->mftmirr_ino);
 		ntfs_error(sb, "Failed to load $MFTMirr.");
 		return FALSE;
@@ -932,13 +932,13 @@
 	 * need for any locking at this stage as we are already running
 	 * exclusively as we are mount in progress task.
 	 */
-	vol->lcnbmp_ino = iget(sb, FILE_Bitmap);
-	if (!vol->lcnbmp_ino || is_bad_inode(vol->lcnbmp_ino)) {
-		if (is_bad_inode(vol->lcnbmp_ino))
+	vol->lcnbmp_ino = ntfs_iget(sb, FILE_Bitmap);
+	if (IS_ERR(vol->lcnbmp_ino) || is_bad_inode(vol->lcnbmp_ino)) {
+		if (!IS_ERR(vol->lcnbmp_ino))
 			iput(vol->lcnbmp_ino);
 		goto bitmap_failed;
 	}
-	if ((vol->_VCL(nr_lcn_bits) + 7) >> 3 > vol->lcnbmp_ino->i_size) {
+	if ((vol->nr_clusters + 7) >> 3 > vol->lcnbmp_ino->i_size) {
 		iput(vol->lcnbmp_ino);
 bitmap_failed:
 		ntfs_error(sb, "Failed to load $Bitmap.");
@@ -948,9 +948,9 @@
 	 * Get the volume inode and setup our cache of the volume flags and
 	 * version.
 	 */
-	vol->vol_ino = iget(sb, FILE_Volume);
-	if (!vol->vol_ino || is_bad_inode(vol->vol_ino)) {
-		if (is_bad_inode(vol->vol_ino))
+	vol->vol_ino = ntfs_iget(sb, FILE_Volume);
+	if (IS_ERR(vol->vol_ino) || is_bad_inode(vol->vol_ino)) {
+		if (!IS_ERR(vol->vol_ino))
 			iput(vol->vol_ino);
 volume_failed:
 		ntfs_error(sb, "Failed to load $Volume.");
@@ -993,9 +993,9 @@
 	 * Get the inode for the logfile and empty it if this is a read-write
 	 * mount.
 	 */
-	tmp_ino = iget(sb, FILE_LogFile);
-	if (!tmp_ino || is_bad_inode(tmp_ino)) {
-		if (is_bad_inode(tmp_ino))
+	tmp_ino = ntfs_iget(sb, FILE_LogFile);
+	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
+		if (!IS_ERR(tmp_ino))
 			iput(tmp_ino);
 		ntfs_error(sb, "Failed to load $LogFile.");
 		// FIMXE: We only want to empty the thing so pointless bailing
@@ -1010,9 +1010,9 @@
 	 * Get the inode for the attribute definitions file and parse the
 	 * attribute definitions.
 	 */ 
-	tmp_ino = iget(sb, FILE_AttrDef);
-	if (!tmp_ino || is_bad_inode(tmp_ino)) {
-		if (is_bad_inode(tmp_ino))
+	tmp_ino = ntfs_iget(sb, FILE_AttrDef);
+	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
+		if (!IS_ERR(tmp_ino))
 			iput(tmp_ino);
 		ntfs_error(sb, "Failed to load $AttrDef.");
 		goto iput_vol_bmp_mirr_err_out;
@@ -1020,9 +1020,9 @@
 	// FIXME: Parse the attribute definitions.
 	iput(tmp_ino);
 	/* Get the root directory inode. */
-	vol->root_ino = iget(sb, FILE_root);
-	if (!vol->root_ino || is_bad_inode(vol->root_ino)) {
-		if (is_bad_inode(vol->root_ino))
+	vol->root_ino = ntfs_iget(sb, FILE_root);
+	if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) {
+		if (!IS_ERR(vol->root_ino))
 			iput(vol->root_ino);
 		ntfs_error(sb, "Failed to load root directory.");
 		goto iput_vol_bmp_mirr_err_out;
@@ -1032,18 +1032,18 @@
 		return TRUE;
 	/* NTFS 3.0+ specific initialization. */
 	/* Get the security descriptors inode. */
-	vol->secure_ino = iget(sb, FILE_Secure);
-	if (!vol->secure_ino || is_bad_inode(vol->secure_ino)) {
-		if (is_bad_inode(vol->secure_ino))
+	vol->secure_ino = ntfs_iget(sb, FILE_Secure);
+	if (IS_ERR(vol->secure_ino) || is_bad_inode(vol->secure_ino)) {
+		if (!IS_ERR(vol->secure_ino))
 			iput(vol->secure_ino);
 		ntfs_error(sb, "Failed to load $Secure.");
 		goto iput_root_vol_bmp_mirr_err_out;
 	}
 	// FIXME: Initialize security.
 	/* Get the extended system files' directory inode. */
-	tmp_ino = iget(sb, FILE_Extend);
-	if (!tmp_ino || is_bad_inode(tmp_ino)) {
-		if (is_bad_inode(tmp_ino))
+	tmp_ino = ntfs_iget(sb, FILE_Extend);
+	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
+		if (!IS_ERR(tmp_ino))
 			iput(tmp_ino);
 		ntfs_error(sb, "Failed to load $Extend.");
 		goto iput_sec_root_vol_bmp_mirr_err_out;
@@ -1051,8 +1051,8 @@
 	// FIXME: Do something. E.g. want to delete the $UsnJrnl if exists.
 	// Note we might be doing this at the wrong level; we might want to
 	// d_alloc_root() and then do a "normal" open(2) of $Extend\$UsnJrnl
-	// rather than using iget here, as we don't know the inode number for
-	// the files in $Extend directory.
+	// rather than using ntfs_iget here, as we don't know the inode number
+	// for the files in $Extend directory.
 	iput(tmp_ino);
 	return TRUE;
 iput_sec_root_vol_bmp_mirr_err_out:
@@ -1077,7 +1077,7 @@
  * releases all inodes and memory belonging to the NTFS specific part of the
  * super block.
  */
-void ntfs_put_super(struct super_block *vfs_sb)
+static void ntfs_put_super(struct super_block *vfs_sb)
 {
 	ntfs_volume *vol = NTFS_SB(vfs_sb);
 
@@ -1155,7 +1155,7 @@
  * Errors are ignored and we just return the number of free clusters we have
  * found. This means we return an underestimate on error.
  */
-s64 get_nr_free_clusters(ntfs_volume *vol)
+static s64 get_nr_free_clusters(ntfs_volume *vol)
 {
 	struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
 	filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
@@ -1172,7 +1172,7 @@
 	 * Convert the number of bits into bytes rounded up, then convert into
 	 * multiples of PAGE_CACHE_SIZE.
 	 */
-	max_index = (vol->_VCL(nr_clusters) + 7) >> (3 + PAGE_CACHE_SHIFT);
+	max_index = (vol->nr_clusters + 7) >> (3 + PAGE_CACHE_SHIFT);
 	/* Use multiples of 4 bytes. */
 	max_size = PAGE_CACHE_SIZE >> 2;
 	ntfs_debug("Reading $BITMAP, max_index = 0x%lx, max_size = 0x%x.",
@@ -1211,7 +1211,7 @@
 		 * Get the multiples of 4 bytes in use in the final partial
 		 * page.
 		 */
-		max_size = ((((vol->_VCL(nr_clusters) + 7) >> 3) & ~PAGE_CACHE_MASK)
+		max_size = ((((vol->nr_clusters + 7) >> 3) & ~PAGE_CACHE_MASK)
 				+ 3) >> 2;
 		/* If there is a partial page go back and do it. */
 		if (max_size) {
@@ -1227,7 +1227,7 @@
 }
 
 /**
- * get_nr_free_mft_records - return the number of free inodes on a volume
+ * __get_nr_free_mft_records - return the number of free inodes on a volume
  * @vol:	ntfs volume for which to obtain free inode count
  *
  * Calculate the number of free mft records (inodes) on the mounted NTFS
@@ -1235,8 +1235,10 @@
  *
  * Errors are ignored and we just return the number of free inodes we have
  * found. This means we return an underestimate on error.
+ *
+ * NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
  */
-unsigned long get_nr_free_mft_records(ntfs_volume *vol)
+static unsigned long __get_nr_free_mft_records(ntfs_volume *vol)
 {
 	struct address_space *mapping;
 	filler_t *readpage;
@@ -1247,14 +1249,13 @@
 
 	ntfs_debug("Entering.");
 	/* Serialize accesses to the inode bitmap. */
-	down_read(&vol->mftbmp_lock);
 	mapping = &vol->mftbmp_mapping;
 	readpage = (filler_t*)mapping->a_ops->readpage;
 	/*
 	 * Convert the number of bits into bytes rounded up, then convert into
 	 * multiples of PAGE_CACHE_SIZE.
 	 */
-	max_index = (vol->_VMM(nr_mft_records) + 7) >> (3 + PAGE_CACHE_SHIFT);
+	max_index = (vol->nr_mft_records + 7) >> (3 + PAGE_CACHE_SHIFT);
 	/* Use multiples of 4 bytes. */
 	max_size = PAGE_CACHE_SIZE >> 2;
 	ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
@@ -1293,12 +1294,12 @@
 		 * Get the multiples of 4 bytes in use in the final partial
 		 * page.
 		 */
-		max_size = ((((vol->_VMM(nr_mft_records) + 7) >> 3) &
+		max_size = ((((vol->nr_mft_records + 7) >> 3) &
 				~PAGE_CACHE_MASK) + 3) >> 2;
 		/* If there is a partial page go back and do it. */
 		if (max_size) {
 			/* Compensate for out of bounds zero bits. */
-			if ((i = vol->_VMM(nr_mft_records) & 31))
+			if ((i = vol->nr_mft_records & 31))
 				nr_free -= 32 - i;
 			ntfs_debug("Handling partial page, max_size = 0x%x",
 					max_size);
@@ -1307,7 +1308,6 @@
 	}
 	ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx",
 			index - 1);
-	up_read(&vol->mftbmp_lock);
 	ntfs_debug("Exiting.");
 	return nr_free;
 }
@@ -1330,7 +1330,7 @@
  *
  * Return 0 on success or -errno on error.
  */
-int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
+static int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
 {
 	ntfs_volume *vol = NTFS_SB(sb);
 	s64 size;
@@ -1345,7 +1345,7 @@
 	 * inodes are also stored in data blocs ($MFT is a file) this is just
 	 * the total clusters.
 	 */
-	sfs->f_blocks = vol->_VCL(nr_clusters) << vol->cluster_size_bits >>
+	sfs->f_blocks = vol->nr_clusters << vol->cluster_size_bits >>
 				PAGE_CACHE_SHIFT;
 	/* Free data blocks in file system in units of f_bsize. */
 	size	      = get_nr_free_clusters(vol) << vol->cluster_size_bits >>
@@ -1354,10 +1354,12 @@
 		size = 0LL;
 	/* Free blocks avail to non-superuser, same as above on NTFS. */
 	sfs->f_bavail = sfs->f_bfree = size;
+	down_read(&vol->mftbmp_lock);
 	/* Total file nodes in file system (at this moment in time). */
 	sfs->f_files  = vol->mft_ino->i_size >> vol->mft_record_size_bits;
 	/* Free file nodes in fs (based on current total count). */
-	sfs->f_ffree = get_nr_free_mft_records(vol);
+	sfs->f_ffree = __get_nr_free_mft_records(vol);
+	up_read(&vol->mftbmp_lock);
 	/*
 	 * File system id. This is extremely *nix flavour dependent and even
 	 * within Linux itself all fs do their own thing. I interpret this to
@@ -1394,8 +1396,6 @@
 struct super_operations ntfs_sops = {
 	alloc_inode:	ntfs_alloc_big_inode,	/* VFS: Allocate a new inode. */
 	destroy_inode:	ntfs_destroy_big_inode,	/* VFS: Deallocate an inode. */
-	read_inode:	ntfs_read_inode,	/* VFS: Load inode from disk,
-						   called from iget(). */
 	dirty_inode:	ntfs_dirty_inode,	/* VFS: Called from
 						   __mark_inode_dirty(). */
 	//write_inode:	NULL,		/* VFS: Write dirty inode to disk. */
@@ -1575,9 +1575,9 @@
 	/*
 	 * Now load the metadata required for the page cache and our address
 	 * space operations to function. We do this by setting up a specialised
-	 * read_inode method and then just calling iget() to obtain the inode
-	 * for $MFT which is sufficient to allow our normal inode operations
-	 * and associated address space operations to function.
+	 * read_inode method and then just calling the normal iget() to obtain
+	 * the inode for $MFT which is sufficient to allow our normal inode
+	 * operations and associated address space operations to function.
 	 */
 	/*
 	 * Poison vol->mft_ino so we know whether iget() called into our
@@ -1601,9 +1601,7 @@
 	 * Note: sb->s_op has already been set to &ntfs_sops by our specialized
 	 * ntfs_read_inode_mount() method when it was invoked by iget().
 	 */
-
 	down(&ntfs_lock);
-
 	/*
 	 * The current mount is a compression user if the cluster size is
 	 * less than or equal 4kiB.
@@ -1618,7 +1616,6 @@
 			goto iput_tmp_ino_err_out_now;
 		}
 	}
-
 	/*
 	 * Increment the number of mounts and generate the global default
 	 * upcase table if necessary. Also temporarily increment the number of
@@ -1629,12 +1626,10 @@
 	ntfs_nr_upcase_users++;
 
 	up(&ntfs_lock);
-
 	/*
 	 * From now on, ignore @silent parameter. If we fail below this line,
 	 * it will be due to a corrupt fs or a system error, so we report it.
 	 */
-
 	/*
 	 * Open the system files with normal access functions and complete
 	 * setting up the ntfs super block.
@@ -1643,9 +1638,8 @@
 		ntfs_error(sb, "Failed to load system files.");
 		goto unl_upcase_iput_tmp_ino_err_out_now;
 	}
-
 	if ((sb->s_root = d_alloc_root(vol->root_ino))) {
-		/* We increment i_count simulating an iget(). */
+		/* We increment i_count simulating an ntfs_iget(). */
 		atomic_inc(&vol->root_ino->i_count);
 		ntfs_debug("Exiting, status successful.");
 		/* Release the default upcase if it has no users. */
@@ -1709,10 +1703,11 @@
 	}
 #undef OGIN
 	/*
-	 * This is needed to get ntfs_clear_inode() called for each inode we
-	 * have ever called iget()/iput() on, otherwise we A) leak resources
-	 * and B) a subsequent mount fails automatically due to iget() never
-	 * calling down into our ntfs_read_inode{_mount}() methods again...
+	 * This is needed to get ntfs_clear_extent_inode() called for each
+	 * inode we have ever called ntfs_iget()/iput() on, otherwise we A)
+	 * leak resources and B) a subsequent mount fails automatically due to
+	 * ntfs_iget() never calling down into our ntfs_read_locked_inode()
+	 * method again...
 	 */
 	if (invalidate_inodes(sb)) {
 		ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h
--- a/fs/ntfs/volume.h	Fri Jul  5 16:42:56 2002
+++ b/fs/ntfs/volume.h	Fri Jul  5 16:42:56 2002
@@ -3,7 +3,7 @@
  *	      of the Linux-NTFS project.
  *
  * Copyright (c) 2001,2002 Anton Altaparmakov.
- * Copyright (C) 2002 Richard Russon.
+ * Copyright (c) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -89,10 +89,8 @@
 	u32 index_record_size;		/* in bytes */
 	u32 index_record_size_mask;	/* index_record_size - 1 */
 	u8 index_record_size_bits;	/* log2(index_record_size) */
-	union {
-		LCN nr_clusters;	/* Volume size in clusters. */
-		LCN nr_lcn_bits;	/* Number of bits in lcn bitmap. */
-	} SN(vcl);
+	LCN nr_clusters;		/* Volume size in clusters == number of
+					   bits in lcn bitmap. */
 	LCN mft_lcn;			/* Cluster location of mft data. */
 	LCN mftmirr_lcn;		/* Cluster location of copy of mft. */
 	u64 serial_no;			/* The volume serial number. */
@@ -104,10 +102,8 @@
 	struct inode *mft_ino;		/* The VFS inode of $MFT. */
 	struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
 					    mft record bitmap ($MFT/$BITMAP). */
-	union {
-		unsigned long nr_mft_records; /* Number of mft records. */
-		unsigned long nr_mft_bits; /* Number of bits in mft bitmap. */
-	} SN(vmm);
+	unsigned long nr_mft_records;	/* Number of mft records == number of
+					   bits in mft bitmap. */
 	struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */
 	run_list mftbmp_rl;		/* Run list for $MFT/$BITMAP. */
 	s64 mftbmp_size;		/* Data size of $MFT/$BITMAP. */
@@ -127,9 +123,6 @@
 					   only, otherwise NULL). */
 	struct nls_table *nls_map;
 } ntfs_volume;
-
-#define _VCL(X)  SC(vcl,X)
-#define _VMM(X)  SC(vmm,X)
 
 #endif /* _LINUX_NTFS_VOLUME_H */
 
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Fri Jul  5 16:42:56 2002
+++ b/fs/open.c	Fri Jul  5 16:42:56 2002
@@ -30,9 +30,7 @@
 		retval = -ENOSYS;
 		if (sb->s_op && sb->s_op->statfs) {
 			memset(buf, 0, sizeof(struct statfs));
-			lock_kernel();
 			retval = sb->s_op->statfs(sb, buf);
-			unlock_kernel();
 		}
 	}
 	return retval;
@@ -664,6 +662,14 @@
 			goto cleanup_all;
 	}
 	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
+
+	/* NB: we're sure to have correct a_ops only after f_op->open */
+	if (f->f_flags & O_DIRECT) {
+		error = -EINVAL;
+		if (inode->i_mapping && inode->i_mapping->a_ops)
+			if (!inode->i_mapping->a_ops->direct_IO)
+				goto cleanup_all;
+	}
 
 	return f;
 
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Fri Jul  5 16:42:59 2002
+++ b/fs/partitions/check.c	Fri Jul  5 16:42:59 2002
@@ -13,15 +13,11 @@
  *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
  */
 
-#include <linux/config.h>
+#include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/blk.h>
-#include <linux/init.h>
-#include <linux/raid/md.h>
 #include <linux/buffer_head.h>	/* for invalidate_bdev() */
+#include <linux/kmod.h>
 
 #include "check.h"
 
@@ -225,6 +221,136 @@
 #endif
 }
 
+/* Driverfs file support */
+static ssize_t partition_device_kdev_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf (page, "%x\n",kdev.value);
+}
+static struct driver_file_entry partition_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: partition_device_kdev_read,
+};
+
+static ssize_t partition_device_type_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "BLK\n");
+}
+static struct driver_file_entry partition_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: partition_device_type_read,
+};
+
+void driverfs_create_partitions(struct gendisk *hd, int minor)
+{
+	int pos = -1;
+	int devnum = minor >> hd->minor_shift;
+	char dirname[256];
+	struct device *parent = 0;
+	int max_p;
+	int part;
+	devfs_handle_t dir = 0;
+	
+	/* get parent driverfs device structure */
+	if (hd->driverfs_dev_arr)
+		parent = hd->driverfs_dev_arr[devnum];
+	else /* if driverfs not supported by subsystem, skip partitions */
+		return;
+	
+	/* get parent device node directory name */
+	if (hd->de_arr) {
+		dir = hd->de_arr[devnum];
+		if (dir)
+			pos = devfs_generate_path (dir, dirname, 
+						   sizeof dirname);
+	}
+	
+	if (pos < 0) {
+		disk_name(hd, minor, dirname);
+		pos = 0;
+	}
+	
+	max_p = (1 << hd->minor_shift);
+	
+	/* for all partitions setup parents and device node names */
+	for(part=0; part < max_p; part++) {
+		if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) {
+			struct device * current_driverfs_dev = 
+				&hd->part[minor+part].hd_driverfs_dev;
+			current_driverfs_dev->parent = parent;
+			/* handle disc case */
+			current_driverfs_dev->driver_data =
+					(void *)__mkdev(hd->major, minor+part);
+			if (part == 0) {
+				if (parent)  {
+					sprintf(current_driverfs_dev->name,
+						"%sdisc", parent->name);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:disc", parent->bus_id);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"disc");
+					sprintf(current_driverfs_dev->bus_id,
+						"disc");
+				}
+			} else { /* this is a partition */
+				if (parent) {
+					sprintf(current_driverfs_dev->name,
+						"%spart%d", parent->name, part);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:p%d", parent->bus_id, part);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"part%d", part);
+					sprintf(current_driverfs_dev->bus_id, 
+						"p%d" ,part);
+				}
+			}
+			if (parent) current_driverfs_dev->bus = parent->bus;
+			device_register(current_driverfs_dev);
+			device_create_file(current_driverfs_dev,
+					&partition_device_type_file);
+			device_create_file(current_driverfs_dev,
+					&partition_device_kdev_file);
+		}
+	}
+	return;
+}
+
+void driverfs_remove_partitions(struct gendisk *hd, int minor)
+{
+	int max_p;
+	int part;
+	struct device * current_driverfs_dev;
+	
+	max_p=(1 << hd->minor_shift);
+	
+	/* for all parts setup parent relationships and device node names */
+	for(part=1; part < max_p; part++) {
+		if ((hd->part[minor + part].nr_sects >= 1)) {
+			current_driverfs_dev = 
+				&hd->part[minor + part].hd_driverfs_dev;
+			device_remove_file(current_driverfs_dev,
+					partition_device_type_file.name);
+			device_remove_file(current_driverfs_dev,
+					partition_device_kdev_file.name);
+			put_device(current_driverfs_dev);	
+		}
+	}
+	current_driverfs_dev = &hd->part[minor].hd_driverfs_dev;
+	device_remove_file(current_driverfs_dev, 
+				partition_device_type_file.name);
+	device_remove_file(current_driverfs_dev, 
+				partition_device_kdev_file.name);
+	put_device(current_driverfs_dev);	
+	return;
+}
+
 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 {
 	devfs_handle_t de = NULL;
@@ -285,6 +411,13 @@
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 	bdput(bdev);
 	i = first_part_minor - 1;
+
+	/* Setup driverfs tree */
+	if (hd->sizes)
+		driverfs_create_partitions(hd, i);
+	else
+		driverfs_remove_partitions(hd, i);
+
 	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }
 
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Fri Jul  5 16:42:53 2002
+++ b/fs/proc/array.c	Fri Jul  5 16:42:53 2002
@@ -71,6 +71,7 @@
 #include <linux/signal.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
+#include <linux/times.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -360,15 +361,15 @@
 		task->cmin_flt,
 		task->maj_flt,
 		task->cmaj_flt,
-		task->times.tms_utime,
-		task->times.tms_stime,
-		task->times.tms_cutime,
-		task->times.tms_cstime,
+		jiffies_to_clock_t(task->utime),
+		jiffies_to_clock_t(task->stime),
+		jiffies_to_clock_t(task->cutime),
+		jiffies_to_clock_t(task->cstime),
 		priority,
 		nice,
 		0UL /* removed */,
-		task->it_real_value,
-		task->start_time,
+		jiffies_to_clock_t(task->it_real_value),
+		jiffies_to_clock_t(task->start_time),
 		vsize,
 		mm ? mm->rss : 0, /* you might want to shift this left 3 */
 		task->rlim[RLIMIT_RSS].rlim_cur,
@@ -538,11 +539,11 @@
  *         + (index into the line)
  */
 /* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4	  "%08lx-%08lx %s %08lx %s %lu"
+#define MAPS_LINE_FORMAT4	  "%08lx-%08lx %s %08lx %02x:%02x %lu"
 #define MAPS_LINE_MAX4	49 /* sum of 8  1  8  1 4 1 8 1 5 1 10 1 */
 
 /* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8	  "%016lx-%016lx %s %016lx %s %lu"
+#define MAPS_LINE_FORMAT8	  "%016lx-%016lx %s %016lx %02x:%02x %lu"
 #define MAPS_LINE_MAX8	73 /* sum of 16  1  16  1 4 1 16 1 5 1 10 1 */
 
 #define MAPS_LINE_FORMAT	(sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8)
@@ -554,7 +555,7 @@
 	char *line;
 	char str[5];
 	int flags;
-	kdev_t dev;
+	dev_t dev;
 	unsigned long ino;
 	int len;
 
@@ -566,7 +567,7 @@
 	str[3] = flags & VM_MAYSHARE ? 's' : 'p';
 	str[4] = 0;
 
-	dev = NODEV;
+	dev = 0;
 	ino = 0;
 	if (map->vm_file != NULL) {
 		dev = map->vm_file->f_dentry->d_inode->i_dev;
@@ -584,7 +585,7 @@
 	len = sprintf(line,
 		      MAPS_LINE_FORMAT,
 		      map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-		      kdevname(dev), ino);
+		      MAJOR(dev), MINOR(dev), ino);
 
 	if(map->vm_file) {
 		int i;
@@ -692,15 +693,15 @@
 
 	len = sprintf(buffer,
 		"cpu  %lu %lu\n",
-		task->times.tms_utime,
-		task->times.tms_stime);
+		jiffies_to_clock_t(task->utime),
+		jiffies_to_clock_t(task->stime));
 		
 	for (i = 0 ; i < NR_CPUS; i++) {
 		if (cpu_online(i))
 		len += sprintf(buffer + len, "cpu%d %lu %lu\n",
 			i,
-				       task->per_cpu_utime[i],
-				       task->per_cpu_stime[i]);
+			jiffies_to_clock_t(task->per_cpu_utime[i]),
+			jiffies_to_clock_t(task->per_cpu_stime[i]));
 
 	}
 	return len;
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Fri Jul  5 16:42:59 2002
+++ b/fs/proc/proc_misc.c	Fri Jul  5 16:42:59 2002
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
+#include <linux/times.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -98,7 +99,7 @@
 	int len;
 
 	uptime = jiffies;
-	idle = init_task.times.tms_utime + init_task.times.tms_stime;
+	idle = init_task.utime + init_task.stime;
 
 	/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
 	   that would overflow about every five days at HZ == 100.
@@ -294,18 +295,21 @@
 #endif
 	}
 
-	len = sprintf(page, "cpu  %u %u %u %lu\n", user, nice, system,
-		      jif * num_online_cpus() - (user + nice + system));
+	len = sprintf(page, "cpu  %u %u %u %lu\n",
+		jiffies_to_clock_t(user),
+		jiffies_to_clock_t(nice),
+		jiffies_to_clock_t(system),
+		jiffies_to_clock_t(jif * num_online_cpus() - (user + nice + system)));
 	for (i = 0 ; i < NR_CPUS; i++){
 		if (!cpu_online(i)) continue;
 		len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
 			i,
-			kstat.per_cpu_user[i],
-			kstat.per_cpu_nice[i],
-			kstat.per_cpu_system[i],
-			jif - (  kstat.per_cpu_user[i] \
+			jiffies_to_clock_t(kstat.per_cpu_user[i]),
+			jiffies_to_clock_t(kstat.per_cpu_nice[i]),
+			jiffies_to_clock_t(kstat.per_cpu_system[i]),
+			jiffies_to_clock_t(jif - (  kstat.per_cpu_user[i] \
 				   + kstat.per_cpu_nice[i] \
-				   + kstat.per_cpu_system[i]));
+				   + kstat.per_cpu_system[i])));
 	}
 	len += sprintf(page + len,
 		"page %u %u\n"
diff -Nru a/fs/qnx4/inode.c b/fs/qnx4/inode.c
--- a/fs/qnx4/inode.c	Fri Jul  5 16:42:59 2002
+++ b/fs/qnx4/inode.c	Fri Jul  5 16:42:59 2002
@@ -281,12 +281,16 @@
 
 static int qnx4_statfs(struct super_block *sb, struct statfs *buf)
 {
+	lock_kernel();
+
 	buf->f_type    = sb->s_magic;
 	buf->f_bsize   = sb->s_blocksize;
 	buf->f_blocks  = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8;
 	buf->f_bfree   = qnx4_count_free_blocks(sb);
 	buf->f_bavail  = buf->f_bfree;
 	buf->f_namelen = QNX4_NAME_MAX;
+
+	unlock_kernel();
 
 	return 0;
 }
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Fri Jul  5 16:42:59 2002
+++ b/fs/ramfs/inode.c	Fri Jul  5 16:42:59 2002
@@ -130,7 +130,12 @@
 
 static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
-	return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+	int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+	if (!retval) {
+		dir->i_nlink++;
+		dentry->d_inode->i_nlink++;
+	}
+	return retval;
 }
 
 static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode)
@@ -186,25 +191,30 @@
 }
 
 /*
- * This works for both directories and regular files.
- * (non-directories will always have empty subdirs)
+ * Unlink a ramfs entry
  */
 static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
 {
+	struct inode *inode = dentry->d_inode;
+
+	inode->i_nlink--;
+	dput(dentry);			/* Undo the count from "create" - this does all the work */
+	return 0;
+}
+
+static int ramfs_rmdir(struct inode * dir, struct dentry *dentry)
+{
 	int retval = -ENOTEMPTY;
 
 	if (ramfs_empty(dentry)) {
-		struct inode *inode = dentry->d_inode;
-
-		inode->i_nlink--;
-		dput(dentry);			/* Undo the count from "create" - this does all the work */
+		dentry->d_inode->i_nlink--;
+		ramfs_unlink(dir, dentry);
+		dir->i_nlink--;
 		retval = 0;
 	}
 	return retval;
 }
 
-#define ramfs_rmdir ramfs_unlink
-
 /*
  * The VFS layer already does all the dentry stuff for rename,
  * we just have to decrement the usage count for the target if
@@ -220,6 +230,10 @@
 		if (inode) {
 			inode->i_nlink--;
 			dput(new_dentry);
+		}
+		if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+			old_dir->i_nlink--;
+			new_dir->i_nlink++;
 		}
 		error = 0;
 	}
diff -Nru a/fs/reiserfs/buffer2.c b/fs/reiserfs/buffer2.c
--- a/fs/reiserfs/buffer2.c	Fri Jul  5 16:43:00 2002
+++ b/fs/reiserfs/buffer2.c	Fri Jul  5 16:43:00 2002
@@ -25,6 +25,13 @@
 {
   int repeat_counter = 0;
 
+  /*
+   * FIXME! Temporary cludge until ReiserFS people tell what they
+   * actually are trying to protect against!
+   */
+  if (1)
+  	return;
+
   while (atomic_read (&(bh->b_count)) > 1) {
 
     if ( !(++repeat_counter % 30000000) ) {
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Fri Jul  5 16:42:59 2002
+++ b/fs/smbfs/inode.c	Fri Jul  5 16:42:59 2002
@@ -145,7 +145,6 @@
 	fattr->f_ino	= inode->i_ino;
 	fattr->f_uid	= inode->i_uid;
 	fattr->f_gid	= inode->i_gid;
-	fattr->f_rdev	= inode->i_rdev;
 	fattr->f_size	= inode->i_size;
 	fattr->f_mtime	= inode->i_mtime;
 	fattr->f_ctime	= inode->i_ctime;
@@ -183,7 +182,6 @@
 	inode->i_nlink	= fattr->f_nlink;
 	inode->i_uid	= fattr->f_uid;
 	inode->i_gid	= fattr->f_gid;
-	inode->i_rdev	= fattr->f_rdev;
 	inode->i_ctime	= fattr->f_ctime;
 	inode->i_blksize= fattr->f_blksize;
 	inode->i_blocks = fattr->f_blocks;
@@ -604,7 +602,13 @@
 static int
 smb_statfs(struct super_block *sb, struct statfs *buf)
 {
-	int result = smb_proc_dskattr(sb, buf);
+	int result;
+	
+	lock_kernel();
+
+	result = smb_proc_dskattr(sb, buf);
+
+	unlock_kernel();
 
 	buf->f_type = SMB_SUPER_MAGIC;
 	buf->f_namelen = SMB_MAXPATHLEN;
diff -Nru a/fs/stat.c b/fs/stat.c
--- a/fs/stat.c	Fri Jul  5 16:42:59 2002
+++ b/fs/stat.c	Fri Jul  5 16:42:59 2002
@@ -17,7 +17,7 @@
 
 void generic_fillattr(struct inode *inode, struct kstat *stat)
 {
-	stat->dev = kdev_t_to_nr(inode->i_dev);
+	stat->dev = inode->i_dev;
 	stat->ino = inode->i_ino;
 	stat->mode = inode->i_mode;
 	stat->nlink = inode->i_nlink;
diff -Nru a/fs/udf/super.c b/fs/udf/super.c
--- a/fs/udf/super.c	Fri Jul  5 16:43:00 2002
+++ b/fs/udf/super.c	Fri Jul  5 16:43:00 2002
@@ -1726,6 +1726,8 @@
 static int
 udf_statfs(struct super_block *sb, struct statfs *buf)
 {
+	lock_kernel();
+
 	buf->f_type = UDF_SUPER_MAGIC;
 	buf->f_bsize = sb->s_blocksize;
 	buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
@@ -1737,6 +1739,8 @@
 	buf->f_ffree = buf->f_bfree;
 	/* __kernel_fsid_t f_fsid */
 	buf->f_namelen = UDF_NAME_LEN;
+
+	unlock_kernel();
 
 	return 0;
 }
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Fri Jul  5 16:42:44 2002
+++ b/fs/ufs/super.c	Fri Jul  5 16:42:44 2002
@@ -959,6 +959,8 @@
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 
+	lock_kernel();
+
 	uspi = sb->u.ufs_sb.s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
 	
@@ -972,6 +974,9 @@
 	buf->f_files = uspi->s_ncg * uspi->s_ipg;
 	buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
 	buf->f_namelen = UFS_MAXNAMLEN;
+
+	unlock_kernel();
+
 	return 0;
 }
 
diff -Nru a/include/asm-i386/param.h b/include/asm-i386/param.h
--- a/include/asm-i386/param.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-i386/param.h	Fri Jul  5 16:42:59 2002
@@ -1,6 +1,12 @@
 #ifndef _ASMi386_PARAM_H
 #define _ASMi386_PARAM_H
 
+#ifdef __KERNEL__
+# define HZ		1000		/* Internal kernel timer frequency */
+# define USER_HZ	100		/* .. some user interfaces are in "ticks" */
+# define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
+#endif
+
 #ifndef HZ
 #define HZ 100
 #endif
@@ -16,9 +22,5 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
-#endif
 
 #endif
diff -Nru a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
--- a/include/asm-ppc/commproc.h	Fri Jul  5 16:43:00 2002
+++ b/include/asm-ppc/commproc.h	Fri Jul  5 16:43:00 2002
@@ -382,213 +382,6 @@
 	ushort	sen_taddrl;	/* temp address (LSB) */
 } scc_enet_t;
 
-/***  MBX  ************************************************************/
-
-#ifdef CONFIG_MBX
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
- * to the MBX860 board.  Any two of the four available clocks could be
- * used, and the MPC860 cookbook manual has an example using different
- * clock pins.
- */
-#define PA_ENET_RXD	((ushort)0x0001)
-#define PA_ENET_TXD	((ushort)0x0002)
-#define PA_ENET_TCLK	((ushort)0x0200)
-#define PA_ENET_RCLK	((ushort)0x0800)
-#define PC_ENET_TENA	((ushort)0x0001)
-#define PC_ENET_CLSN	((ushort)0x0010)
-#define PC_ENET_RENA	((ushort)0x0020)
-
-/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
- * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x000000ff)
-#define SICR_ENET_CLKRT	((uint)0x0000003d)
-#endif	/* CONFIG_MBX */
-
-/***  RPXLITE  ********************************************************/
-
-#ifdef CONFIG_RPXLITE
-/* This ENET stuff is for the MPC850 with ethernet on SCC2.  Some of
- * this may be unique to the RPX-Lite configuration.
- * Note TENA is on Port B.
- */
-#define PA_ENET_RXD	((ushort)0x0004)
-#define PA_ENET_TXD	((ushort)0x0008)
-#define PA_ENET_TCLK	((ushort)0x0200)
-#define PA_ENET_RCLK	((ushort)0x0800)
-#define PB_ENET_TENA	((uint)0x00002000)
-#define PC_ENET_CLSN	((ushort)0x0040)
-#define PC_ENET_RENA	((ushort)0x0080)
-
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00003d00)
-#endif	/* CONFIG_RPXLITE */
-
-/***  BSEIP  **********************************************************/
-
-#ifdef CONFIG_BSEIP
-/* This ENET stuff is for the MPC823 with ethernet on SCC2.
- * This is unique to the BSE ip-Engine board.
- */
-#define PA_ENET_RXD	((ushort)0x0004)
-#define PA_ENET_TXD	((ushort)0x0008)
-#define PA_ENET_TCLK	((ushort)0x0100)
-#define PA_ENET_RCLK	((ushort)0x0200)
-#define PB_ENET_TENA	((uint)0x00002000)
-#define PC_ENET_CLSN	((ushort)0x0040)
-#define PC_ENET_RENA	((ushort)0x0080)
-
-/* BSE uses port B and C bits for PHY control also.
-*/
-#define PB_BSE_POWERUP	((uint)0x00000004)
-#define PB_BSE_FDXDIS	((uint)0x00008000)
-#define PC_BSE_LOOPBACK	((ushort)0x0800)
-
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002c00)
-#endif	/* CONFIG_BSEIP */
-
-/***  RPXCLASSIC  *****************************************************/
-
-#ifdef CONFIG_RPXCLASSIC
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC1 use.
- */
-#define PA_ENET_RXD	((ushort)0x0001)
-#define PA_ENET_TXD	((ushort)0x0002)
-#define PA_ENET_TCLK	((ushort)0x0200)
-#define PA_ENET_RCLK	((ushort)0x0800)
-#define PB_ENET_TENA	((uint)0x00001000)
-#define PC_ENET_CLSN	((ushort)0x0010)
-#define PC_ENET_RENA	((ushort)0x0020)
-
-/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
- * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x000000ff)
-#define SICR_ENET_CLKRT	((uint)0x0000003d)
-#endif	/* CONFIG_RPXCLASSIC */
-
-/***  TQM823L, TQM850L  ***********************************************/
-
-#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L)
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC1 use.
- */
-#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
-#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
-#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
-
-#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
-
-#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
-#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
- * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002600)
-#endif	/* CONFIG_TQM823L, CONFIG_TQM850L */
-
-/***  FPS850L  *********************************************************/
-
-#ifdef CONFIG_FPS850L
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC1 use.
- */
-#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
-#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
-#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
-
-#define PC_ENET_TENA	((ushort)0x0002)	/* PC 14 */
-#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
-#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
-
-/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
- * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002600)
-#endif	/* CONFIG_FPS850L */
-
-/***  TQM860L  ********************************************************/
-
-#ifdef CONFIG_TQM860L
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC1 use.
- */
-#define PA_ENET_RXD	((ushort)0x0001)	/* PA 15 */
-#define PA_ENET_TXD	((ushort)0x0002)	/* PA 14 */
-#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
-
-#define PC_ENET_TENA	((ushort)0x0001)	/* PC 15 */
-#define PC_ENET_CLSN	((ushort)0x0010)	/* PC 11 */
-#define PC_ENET_RENA	((ushort)0x0020)	/* PC 10 */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
- * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x000000ff)
-#define SICR_ENET_CLKRT	((uint)0x00000026)
-#endif	/* CONFIG_TQM860L */
-
-/***  SPD823TS  *******************************************************/
-
-#ifdef CONFIG_SPD823TS
-/* Bits in parallel I/O port registers that have to be set/cleared
- * to configure the pins for SCC2 use.
- */
-#define PA_ENET_MDC	((ushort)0x0001)	/* PA 15 !!! */
-#define PA_ENET_MDIO	((ushort)0x0002)	/* PA 14 !!! */
-#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
-#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
-#define PA_ENET_RCLK	((ushort)0x0200)	/* PA  6 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
-
-#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
-
-#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
-#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
-#define	PC_ENET_RESET	((ushort)0x0100)	/* PC  7 !!! */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
- * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002E00)
-#endif	/* CONFIG_SPD823TS */
-
-
-/***  SM850  *********************************************************/
-
-/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
-
-#ifdef CONFIG_SM850
-#define PB_ENET_RXD	((uint)0x00000004)	/* PB 29 */
-#define PB_ENET_TXD	((uint)0x00000002)	/* PB 30 */
-#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
-
-#define PC_ENET_LBK	((ushort)0x0008)	/* PC 12 */
-#define PC_ENET_TENA	((ushort)0x0004)	/* PC 13 */
-
-#define PC_ENET_RENA	((ushort)0x0800)	/* PC  4 */
-#define PC_ENET_CLSN	((ushort)0x0400)	/* PC  5 */
-
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
- * SCC3.  Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero.
- */
-#define SICR_ENET_MASK	((uint)0x00FF0000)
-#define SICR_ENET_CLKRT	((uint)0x00260000)
-#endif	/* CONFIG_SM850 */
-
-/*********************************************************************/
-
 /* SCC Event register as used by Ethernet.
 */
 #define SCCE_ENET_GRA	((ushort)0x0080)	/* Graceful stop complete */
diff -Nru a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
--- a/include/asm-ppc/open_pic.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-ppc/open_pic.h	Fri Jul  5 16:42:59 2002
@@ -55,7 +55,8 @@
 
 /* Exported functions */
 extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
-extern void openpic_init(int, int, int);
+extern void openpic_init(int linux_irq_offset);
+extern void openpic_init_nmi_irq(u_int irq);
 extern u_int openpic_irq(void);
 extern void openpic_eoi(void);
 extern void openpic_request_IPIs(void);
diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-ppc/page.h	Fri Jul  5 16:42:59 2002
@@ -85,10 +85,12 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
+struct page;
 extern void clear_page(void *page);
 extern void copy_page(void *to, void *from);
-extern void clear_user_page(void *page, unsigned long vaddr);
-extern void copy_user_page(void *to, void *from, unsigned long vaddr);
+extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+extern void copy_user_page(void *to, void *from, unsigned long vaddr,
+			   struct page *pg);
 
 #ifndef CONFIG_APUS
 #define PPC_MEMSTART	0
diff -Nru a/include/asm-ppc/param.h b/include/asm-ppc/param.h
--- a/include/asm-ppc/param.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-ppc/param.h	Fri Jul  5 16:42:59 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.param.h 1.8 08/20/01 22:50:29 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifndef _ASM_PPC_PARAM_H
 #define _ASM_PPC_PARAM_H
@@ -8,6 +8,12 @@
 #define HZ 100
 #endif
 
+#ifdef __KERNEL__
+#define HZ		100		/* internal timer frequency */
+#define USER_HZ		100		/* for user interfaces in "ticks" */
+#define CLOCKS_PER_SEC	(USER_HZ)	/* frequency at which times() counts */
+#endif
+
 #define EXEC_PAGESIZE	4096
 
 #ifndef NGROUPS
@@ -19,9 +25,5 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
-#endif
 
 #endif
diff -Nru a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h
--- a/include/asm-ppc/ppc_asm.h	Fri Jul  5 16:42:56 2002
+++ b/include/asm-ppc/ppc_asm.h	Fri Jul  5 16:42:56 2002
@@ -49,22 +49,13 @@
 #define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
-/*
- * Once a version of gas that understands the AltiVec instructions
- * is freely available, we can do this the normal way...  - paulus
- */
-#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
-#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
-#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
-#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
-
-#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n));  stvx n,b,base
 #define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
 #define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
 #define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
 #define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
 #define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
-#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
+#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); lvx n,b,base
 #define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
 #define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
 #define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
@@ -169,7 +160,11 @@
 
 #else
 #define FIX_SRR1(ra, rb)
+#ifndef CONFIG_40x
 #define	RFI		rfi
+#else
+#define RFI		rfi; b .	/* Prevent prefetch past rfi */
+#endif
 #define MTMSRD(r)	mtmsr	r
 #define CLR_TOP32(r)
 #endif /* CONFIG_PPC64BRIDGE */
diff -Nru a/include/asm-ppc/system.h b/include/asm-ppc/system.h
--- a/include/asm-ppc/system.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-ppc/system.h	Fri Jul  5 16:42:59 2002
@@ -57,10 +57,14 @@
 extern void poweroff_now(void);
 #ifdef CONFIG_6xx
 extern long _get_L2CR(void);
+extern long _get_L3CR(void);
 extern void _set_L2CR(unsigned long);
+extern void _set_L3CR(unsigned long);
 #else
 #define _get_L2CR()	0L
+#define _get_L3CR()	0L
 #define _set_L2CR(val)	do { } while(0)
+#define _set_L3CR(val)	do { } while(0)
 #endif
 extern void via_cuda_init(void);
 extern void pmac_nvram_init(void);
@@ -79,9 +83,14 @@
 struct device_node;
 extern void note_scsi_host(struct device_node *, void *);
 
+#define prepare_arch_schedule(prev)		do { } while(0)
+#define finish_arch_schedule(prev)		do { } while(0)
+#define prepare_arch_switch(rq)			do { } while(0)
+#define finish_arch_switch(rq)			spin_unlock_irq(&(rq)->lock)
+
 struct task_struct;
-#define prepare_to_switch()	do { } while(0)
-extern void switch_to(struct task_struct *, struct task_struct *);
+extern void __switch_to(struct task_struct *, struct task_struct *);
+#define switch_to(prev, next, last)	__switch_to((prev), (next))
 
 struct thread_struct;
 extern struct task_struct *_switch(struct thread_struct *prev,
diff -Nru a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h
--- a/include/asm-ppc/tlbflush.h	Fri Jul  5 16:42:59 2002
+++ b/include/asm-ppc/tlbflush.h	Fri Jul  5 16:42:59 2002
@@ -21,21 +21,20 @@
 extern void _tlbia(void);
 
 #if defined(CONFIG_4xx)
-#define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
 
 static inline void flush_tlb_all(void)
-	{ __tlbia(); }
+	{ _tlbia(); }
 static inline void flush_tlb_mm(struct mm_struct *mm)
-	{ __tlbia(); }
+	{ _tlbia(); }
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 				unsigned long vmaddr)
 	{ _tlbie(vmaddr); }
 static inline void flush_tlb_range(struct vm_area_struct *vma,
 				unsigned long start, unsigned long end)
-	{ __tlbia(); }
+	{ _tlbia(); }
 static inline void flush_tlb_kernel_range(unsigned long start,
 				unsigned long end)
-	{ __tlbia(); }
+	{ _tlbia(); }
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
 #elif defined(CONFIG_8xx)
diff -Nru a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
--- a/include/asm-ppc/uaccess.h	Fri Jul  5 16:42:50 2002
+++ b/include/asm-ppc/uaccess.h	Fri Jul  5 16:42:50 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.uaccess.h 1.8 09/11/01 18:10:06 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _PPC_UACCESS_H
@@ -272,7 +272,11 @@
 {
 	if (access_ok(VERIFY_WRITE, addr, size))
 		return __clear_user(addr, size);
-	return size? -EFAULT: 0;
+	if ((unsigned long)addr < TASK_SIZE) {
+		unsigned long over = (unsigned long)addr + size - TASK_SIZE;
+		return __clear_user(addr, size - over) + over;
+	}
+	return size;
 }
 
 extern int __strncpy_from_user(char *dst, const char *src, long count);
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/bio.h	Fri Jul  5 16:43:00 2002
@@ -203,8 +203,6 @@
 
 extern inline void bio_init(struct bio *);
 
-extern int bio_ioctl(kdev_t, unsigned int, unsigned long);
-
 #ifdef CONFIG_HIGHMEM
 /*
  * remember to add offset! and never ever reenable interrupts between a
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Fri Jul  5 16:42:50 2002
+++ b/include/linux/buffer_head.h	Fri Jul  5 16:42:50 2002
@@ -121,7 +121,6 @@
 #define page_has_buffers(page)	PagePrivate(page)
 
 #define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
-#define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
 
 
 /*
@@ -156,7 +155,6 @@
 void __wait_on_buffer(struct buffer_head *);
 void sleep_on_buffer(struct buffer_head *bh);
 void wake_up_buffer(struct buffer_head *bh);
-int fsync_dev(kdev_t);
 int fsync_bdev(struct block_device *);
 int fsync_super(struct super_block *);
 int fsync_no_super(struct block_device *);
@@ -164,7 +162,7 @@
 struct buffer_head * __getblk(struct block_device *, sector_t, int);
 void __brelse(struct buffer_head *);
 void __bforget(struct buffer_head *);
-struct buffer_head * __bread(struct block_device *, int, int);
+struct buffer_head *__bread(struct block_device *, sector_t block, int size);
 void wakeup_bdflush(void);
 struct buffer_head *alloc_buffer_head(void);
 void free_buffer_head(struct buffer_head * bh);
@@ -201,9 +199,9 @@
  * inline definitions
  */
 
-static inline void get_bh(struct buffer_head * bh)
+static inline void get_bh(struct buffer_head *bh)
 {
-        atomic_inc(&(bh)->b_count);
+        atomic_inc(&bh->b_count);
 }
 
 static inline void put_bh(struct buffer_head *bh)
@@ -212,68 +210,49 @@
         atomic_dec(&bh->b_count);
 }
 
-/*
- * If an error happens during the make_request, this function
- * has to be recalled. It marks the buffer as clean and not
- * uptodate, and it notifys the upper layer about the end
- * of the I/O.
- */
-static inline void buffer_IO_error(struct buffer_head * bh)
-{
-	clear_buffer_dirty(bh);
-
-	/*
-	 * b_end_io has to clear the BH_Uptodate bitflag in the read error
-	 * case, however buffer contents are not necessarily bad if a
-	 * write fails
-	 */
-	bh->b_end_io(bh, buffer_uptodate(bh));
-}
-
-
-static inline void brelse(struct buffer_head *buf)
+static inline void brelse(struct buffer_head *bh)
 {
-	if (buf)
-		__brelse(buf);
+	if (bh)
+		__brelse(bh);
 }
 
-static inline void bforget(struct buffer_head *buf)
+static inline void bforget(struct buffer_head *bh)
 {
-	if (buf)
-		__bforget(buf);
+	if (bh)
+		__bforget(bh);
 }
 
-static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
+static inline struct buffer_head *sb_bread(struct super_block *sb, sector_t block)
 {
 	return __bread(sb->s_bdev, block, sb->s_blocksize);
 }
 
-static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
+static inline struct buffer_head *sb_getblk(struct super_block *sb, sector_t block)
 {
 	return __getblk(sb->s_bdev, block, sb->s_blocksize);
 }
 
 static inline struct buffer_head *
-sb_find_get_block(struct super_block *sb, int block)
+sb_find_get_block(struct super_block *sb, sector_t block)
 {
 	return __find_get_block(sb->s_bdev, block, sb->s_blocksize);
 }
 
 static inline void
-map_bh(struct buffer_head *bh, struct super_block *sb, int block)
+map_bh(struct buffer_head *bh, struct super_block *sb, sector_t block)
 {
 	set_buffer_mapped(bh);
 	bh->b_bdev = sb->s_bdev;
 	bh->b_blocknr = block;
 }
 
-static inline void wait_on_buffer(struct buffer_head * bh)
+static inline void wait_on_buffer(struct buffer_head *bh)
 {
 	if (buffer_locked(bh))
 		__wait_on_buffer(bh);
 }
 
-static inline void lock_buffer(struct buffer_head * bh)
+static inline void lock_buffer(struct buffer_head *bh)
 {
 	while (test_set_buffer_locked(bh))
 		__wait_on_buffer(bh);
diff -Nru a/include/linux/cdrom.h b/include/linux/cdrom.h
--- a/include/linux/cdrom.h	Fri Jul  5 16:42:50 2002
+++ b/include/linux/cdrom.h	Fri Jul  5 16:42:50 2002
@@ -716,6 +716,7 @@
 
 #ifdef __KERNEL__
 #include <linux/devfs_fs_kernel.h>
+#include <linux/device.h>
 
 struct cdrom_write_settings {
 	unsigned char fpacket;		/* fixed/variable packets */
@@ -730,6 +731,7 @@
 	struct cdrom_device_info *next; /* next device_info for this major */
 	void *handle;		        /* driver-dependent data */
 	devfs_handle_t de;		/* real driver should create this  */
+	struct device cdrom_driverfs_dev; /* driverfs implementation */
 	int number;			/* generic driver updates this  */
 /* specifications */
         kdev_t dev;	                /* device number */
@@ -805,11 +807,8 @@
     long error;
 } tracktype;
 
-extern void cdrom_count_tracks(struct cdrom_device_info *cdi,tracktype* tracks);
-extern int cdrom_get_next_writable(kdev_t dev, long *next_writable);
-extern int cdrom_get_last_written(kdev_t dev, long *last_written);
+extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written);
 extern int cdrom_number_of_slots(struct cdrom_device_info *cdi);
-extern int cdrom_select_disc(struct cdrom_device_info *cdi, int slot);
 extern int cdrom_mode_select(struct cdrom_device_info *cdi,
 			     struct cdrom_generic_command *cgc);
 extern int cdrom_mode_sense(struct cdrom_device_info *cdi,
@@ -817,7 +816,6 @@
 			    int page_code, int page_control);
 extern void init_cdrom_command(struct cdrom_generic_command *cgc,
 			       void *buffer, int len, int type);
-extern struct cdrom_device_info *cdrom_find_device(kdev_t dev);
 
 typedef struct {
 	__u16 disc_information_length;
@@ -900,10 +898,6 @@
 	__u32 track_size;
 	__u32 last_rec_address;
 } track_information;
-
-extern int cdrom_get_disc_info(kdev_t dev, disc_information *di);
-extern int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type,
-				track_information *ti);
 
 /* The SCSI spec says there could be 256 slots. */
 #define CDROM_MAX_SLOTS	256
diff -Nru a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
--- a/include/linux/devpts_fs.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/devpts_fs.h	Fri Jul  5 16:43:00 2002
@@ -10,64 +10,23 @@
  *
  * ------------------------------------------------------------------------- */
 
-/*
- * Prototypes for the pty driver <-> devpts filesystem interface.  Most
- * of this is really just a hack so we can exclude it or build it as a
- * module, and probably should go away eventually.
- */
-
 #ifndef _LINUX_DEVPTS_FS_H
 #define _LINUX_DEVPTS_FS_H 1
 
-#include <linux/config.h>
-#include <linux/kdev_t.h>
-#include <linux/tty.h>
-
 #ifdef CONFIG_DEVPTS_FS
 
-void devpts_pty_new(int, kdev_t);
-void devpts_pty_kill(int);
-#define unix98_max_ptys               NR_PTYS * UNIX98_NR_MAJORS;
-
-#elif defined(CONFIG_DEVPTS_FS_MODULE)
-
-#ifdef BUILDING_PTY_C
-void (*devpts_upcall_new)(int,kdev_t) = NULL;
-void (*devpts_upcall_kill)(int)       = NULL;
-unsigned int unix98_max_ptys          = NR_PTYS * UNIX98_NR_MAJORS;
+void devpts_pty_new(int, dev_t);	/* mknod in devpts */
+void devpts_pty_kill(int);		/* unlink */
 
-EXPORT_SYMBOL(devpts_upcall_new);
-EXPORT_SYMBOL(devpts_upcall_kill);
-EXPORT_SYMBOL(unix98_max_ptys);
 #else
-extern void (*devpts_upcall_new)(int,kdev_t);
-extern void (*devpts_upcall_kill)(int);
-extern unsigned int unix98_max_ptys;
-#endif
 
-#ifndef BUILDING_DEVPTS
-static inline void
-devpts_pty_new(int line, kdev_t device)
+static inline void devpts_pty_new(int line, dev_t device)
 {
-	if ( devpts_upcall_new )
-		return devpts_upcall_new(line,device);
 }
 
-static inline void
-devpts_pty_kill(int line)
+static inline void devpts_pty_kill(int line)
 {
-	if ( devpts_upcall_kill )
-		return devpts_upcall_kill(line);
 }
-#endif
-
-#else  /* No /dev/pts filesystem at all */
-
-static inline void
-devpts_pty_new(int line, kdev_t device) { }
-
-static inline void
-devpts_pty_kill(int line) { }
 
 #endif
 
diff -Nru a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
--- a/include/linux/ext2_fs_sb.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/ext2_fs_sb.h	Fri Jul  5 16:43:00 2002
@@ -17,14 +17,6 @@
 #define _LINUX_EXT2_FS_SB
 
 /*
- * The following is not needed anymore since the descriptors buffer
- * heads are now dynamically allocated
- */
-/* #define EXT2_MAX_GROUP_DESC	8 */
-
-#define EXT2_MAX_GROUP_LOADED	8
-
-/*
  * second extended-fs super-block data in memory
  */
 struct ext2_sb_info {
@@ -41,12 +33,6 @@
 	struct buffer_head * s_sbh;	/* Buffer containing the super block */
 	struct ext2_super_block * s_es;	/* Pointer to the super block in the buffer */
 	struct buffer_head ** s_group_desc;
-	unsigned short s_loaded_inode_bitmaps;
-	unsigned short s_loaded_block_bitmaps;
-	unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED];
-	struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
-	unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
-	struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
 	unsigned long  s_mount_opt;
 	uid_t s_resuid;
 	gid_t s_resgid;
diff -Nru a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h
--- a/include/linux/ext3_fs_sb.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/ext3_fs_sb.h	Fri Jul  5 16:43:00 2002
@@ -22,14 +22,6 @@
 #endif
 
 /*
- * The following is not needed anymore since the descriptors buffer
- * heads are now dynamically allocated
- */
-/* #define EXT3_MAX_GROUP_DESC	8 */
-
-#define EXT3_MAX_GROUP_LOADED	8
-
-/*
  * third extended-fs super-block data in memory
  */
 struct ext3_sb_info {
@@ -46,12 +38,6 @@
 	struct buffer_head * s_sbh;	/* Buffer containing the super block */
 	struct ext3_super_block * s_es;	/* Pointer to the super block in the buffer */
 	struct buffer_head ** s_group_desc;
-	unsigned short s_loaded_inode_bitmaps;
-	unsigned short s_loaded_block_bitmaps;
-	unsigned long s_inode_bitmap_number[EXT3_MAX_GROUP_LOADED];
-	struct buffer_head * s_inode_bitmap[EXT3_MAX_GROUP_LOADED];
-	unsigned long s_block_bitmap_number[EXT3_MAX_GROUP_LOADED];
-	struct buffer_head * s_block_bitmap[EXT3_MAX_GROUP_LOADED];
 	unsigned long  s_mount_opt;
 	uid_t s_resuid;
 	gid_t s_resgid;
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/fs.h	Fri Jul  5 16:42:59 2002
@@ -359,7 +359,7 @@
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
-	kdev_t			i_dev;
+	dev_t			i_dev;
 	umode_t			i_mode;
 	nlink_t			i_nlink;
 	uid_t			i_uid;
@@ -701,6 +701,9 @@
 
 /*
  * File types
+ *
+ * NOTE! These match bits 12..15 of stat.st_mode
+ * (ie "(i_mode >> 12) & 15").
  */
 #define DT_UNKNOWN	0
 #define DT_FIFO		1
@@ -1220,7 +1223,6 @@
 extern int submit_bh(int, struct buffer_head *);
 struct bio;
 extern int submit_bio(int, struct bio *);
-extern int is_read_only(kdev_t);
 extern int bdev_read_only(struct block_device *);
 extern int set_blocksize(struct block_device *, int);
 extern int sb_set_blocksize(struct super_block *, int);
diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h
--- a/include/linux/genhd.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/genhd.h	Fri Jul  5 16:42:59 2002
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/major.h>
+#include <linux/device.h>
 
 enum {
 /* These three have identical behaviour; use the second one if DOS fdisk gets
@@ -62,6 +63,7 @@
 	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
 	int number;                     /* stupid old code wastes space  */
+	struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -80,6 +82,7 @@
 	struct block_device_operations *fops;
 
 	devfs_handle_t *de_arr;         /* one per physical disc */
+	struct device **driverfs_dev_arr;/* support driverfs hierarchy */
 	char *flags;                    /* one per physical disc */
 };
 
@@ -241,6 +244,7 @@
 
 extern void devfs_register_partitions (struct gendisk *dev, int minor,
 				       int unregister);
+extern void driverfs_remove_partitions (struct gendisk *hd, int minor);
 
 static inline unsigned int disk_index (kdev_t dev)
 {
diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h
--- a/include/linux/gfp.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/gfp.h	Fri Jul  5 16:42:59 2002
@@ -18,14 +18,14 @@
 #define __GFP_HIGHIO	0x80	/* Can start high mem physical IO? */
 #define __GFP_FS	0x100	/* Can call down to low-level FS? */
 
-#define GFP_NOHIGHIO	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
-#define GFP_NOIO	(__GFP_HIGH | __GFP_WAIT)
-#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
+#define GFP_NOHIGHIO	(             __GFP_WAIT | __GFP_IO)
+#define GFP_NOIO	(             __GFP_WAIT)
+#define GFP_NOFS	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 #define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
-#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_KERNEL	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_NFS		(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 #define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/input.h	Fri Jul  5 16:42:59 2002
@@ -2,7 +2,7 @@
 #define _INPUT_H
 
 /*
- * $Id: input.h,v 1.57 2002/01/02 11:59:56 vojtech Exp $
+ * $Id: input.h,v 1.68 2002/05/31 10:35:49 fsirl Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
@@ -322,12 +322,13 @@
 #define KEY_FINANCE		219
 #define KEY_SPORT		220
 #define KEY_SHOP		221
-
-#define KEY_UNKNOWN		240
-
+#define KEY_ALTERASE		222
+#define KEY_CANCEL		223
 #define KEY_BRIGHTNESSDOWN	224
 #define KEY_BRIGHTNESSUP	225
 
+#define KEY_UNKNOWN		240
+
 #define BTN_MISC		0x100
 #define BTN_0			0x100
 #define BTN_1			0x101
@@ -394,6 +395,10 @@
 #define BTN_STYLUS		0x14b
 #define BTN_STYLUS2		0x14c
 
+#define BTN_WHEEL		0x150
+#define BTN_GEAR_DOWN		0x150
+#define BTN_GEAR_UP		0x151
+
 #define KEY_MAX			0x1ff
 
 /*
@@ -514,23 +519,19 @@
  * Structures used in ioctls to upload effects to a device
  * The first structures are not passed directly by using ioctls.
  * They are sub-structures of the actually sent structure (called ff_effect)
- *
- * Ranges:
- *  0 <= __u16 <= 65535
- *  -32767 <= __s16 <= +32767     ! Not -32768 for lower bound !
  */
 
 struct ff_replay {
-	__u16 length;		/* Duration of an effect in ms. All other times are also expressed in ms */
-	__u16 delay;		/* Time to wait before to start playing an effect */
+	__u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
+	__u16 delay;  /* Time to wait before to start playing an effect */
 };
 
 struct ff_trigger {
-	__u16 button;		/* Number of button triggering an effect */
-	__u16 interval;		/* Time to wait before an effect can be re-triggered (ms) */
+	__u16 button;   /* Number of button triggering an effect */
+	__u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
 };
 
-struct ff_shape {
+struct ff_envelope {
 	__u16 attack_length;	/* Duration of attack (ms) */
 	__u16 attack_level;	/* Level at beginning of attack */
 	__u16 fade_length;	/* Duration of fade (ms) */
@@ -539,41 +540,56 @@
 
 /* FF_CONSTANT */
 struct ff_constant_effect {
-	__s16 level;		/* Strength of effect. Negative values are OK */
-	struct ff_shape shape;
+	__s16 level;	    /* Strength of effect. Negative values are OK */
+	struct ff_envelope envelope;
 };
 
-/* FF_SPRING of FF_FRICTION */
-struct ff_interactive_effect {
-/* Axis along which effect must be created. If null, the field named direction
- * is used
- * It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y)
- * It overrides the value of ff_effect::direction, which is used only if
- * axis == 0
- */
-	__u16 axis;
+/* FF_RAMP */
+struct ff_ramp_effect {
+	__s16 start_level;
+	__s16 end_level;
+	struct ff_envelope envelope;
+};
 
+/* FF_SPRING of FF_FRICTION */
+struct ff_condition_effect {
 	__u16 right_saturation; /* Max level when joystick is on the right */
-	__u16 left_saturation;	/* Max level when joystick in on the left */
+	__u16 left_saturation;  /* Max level when joystick in on the left */
 
 	__s16 right_coeff;	/* Indicates how fast the force grows when the
 				   joystick moves to the right */
 	__s16 left_coeff;	/* Same for left side */
 
-	__u16 deadband;		/* Size of area where no force is produced */
-	__s16 center;		/* Position of dead dead zone */
+	__u16 deadband;	/* Size of area where no force is produced */
+	__s16 center;	/* Position of dead zone */
 
 };
 
 /* FF_PERIODIC */
 struct ff_periodic_effect {
-	__u16 waveform;		/* Kind of wave (sine, square...) */
-	__u16 period;		/* in ms */
+	__u16 waveform;	/* Kind of wave (sine, square...) */
+	__u16 period;	/* in ms */
 	__s16 magnitude;	/* Peak value */
-	__s16 offset;		/* Mean value of wave (roughly) */
+	__s16 offset;	/* Mean value of wave (roughly) */
 	__u16 phase;		/* 'Horizontal' shift */
 
-	struct ff_shape shape;
+	struct ff_envelope envelope;
+
+/* Only used if waveform == FF_CUSTOM */
+	__u32 custom_len;	/* Number of samples  */	
+	__s16 *custom_data;	/* Buffer of samples */
+/* Note: the data pointed by custom_data is copied by the driver. You can
+ * therefore dispose of the memory after the upload/update */
+};
+
+/* FF_RUMBLE */
+/* Some rumble pads have two motors of different weight.
+   strong_magnitude represents the magnitude of the vibration generated
+   by the heavy motor.
+*/
+struct ff_rumble_effect {
+	__u16 strong_magnitude;  /* Magnitude of the heavy motor */
+	__u16 weak_magnitude;    /* Magnitude of the light one */
 };
 
 /*
@@ -598,27 +614,14 @@
 
 	union {
 		struct ff_constant_effect constant;
+		struct ff_ramp_effect ramp;
 		struct ff_periodic_effect periodic;
-		struct ff_interactive_effect interactive;
+		struct ff_condition_effect condition[2]; /* One for each axis */
+		struct ff_rumble_effect rumble;
 	} u;
 };
 
 /*
- * Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to
- * access the bitmap.
- */
-
-#define FF_BTN(x)	((x) - BTN_MISC + FF_BTN_OFFSET)
-#define FF_BTN_OFFSET	0x00
-
-/*
- * Force feedback axis mappings. Use FF_ABS() to access the bitmap.
- */
-
-#define FF_ABS(x)	((x) + FF_ABS_OFFSET)
-#define FF_ABS_OFFSET	0x40
-
-/*
  * Force feedback effect types
  */
 
@@ -627,6 +630,9 @@
 #define FF_CONSTANT	0x52
 #define FF_SPRING	0x53
 #define FF_FRICTION	0x54
+#define FF_DAMPER	0x55
+#define FF_INERTIA	0x56
+#define FF_RAMP		0x57
 
 /*
  * Force feedback periodic effect types
@@ -668,8 +674,6 @@
 	char *name;
 	char *phys;
 	char *uniq;
-	int number;
-
 	unsigned short idbus;
 	unsigned short idvendor;
 	unsigned short idproduct;
@@ -706,8 +710,6 @@
 	int absmin[ABS_MAX + 1];
 	int absfuzz[ABS_MAX + 1];
 	int absflat[ABS_MAX + 1];
-
-	int only_one_writer;
 
 	int (*open)(struct input_dev *dev);
 	void (*close)(struct input_dev *dev);
diff -Nru a/include/linux/interrupt.h b/include/linux/interrupt.h
--- a/include/linux/interrupt.h	Fri Jul  5 16:42:48 2002
+++ b/include/linux/interrupt.h	Fri Jul  5 16:42:48 2002
@@ -57,6 +57,7 @@
 	HI_SOFTIRQ=0,
 	NET_TX_SOFTIRQ,
 	NET_RX_SOFTIRQ,
+	SCSI_SOFTIRQ,
 	TASKLET_SOFTIRQ
 };
 
diff -Nru a/include/linux/jbd.h b/include/linux/jbd.h
--- a/include/linux/jbd.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/jbd.h	Fri Jul  5 16:43:00 2002
@@ -250,6 +250,13 @@
 	return bh->b_private;
 }
 
+#define HAVE_JOURNAL_CALLBACK_STATUS
+struct journal_callback {
+	struct list_head jcb_list;
+	void (*jcb_func)(struct journal_callback *jcb, int error);
+	/* user data goes here */
+};
+
 struct jbd_revoke_table_s;
 
 /* The handle_t type represents a single atomic update being performed
@@ -280,6 +287,12 @@
 	   operations */
 	int			h_err;
 
+	/* List of application registered callbacks for this handle.
+	 * The function(s) will be called after the transaction that
+	 * this handle is part of has been committed to disk.
+	 */
+	struct list_head	h_jcb;
+
 	/* Flags */
 	unsigned int	h_sync:		1;	/* sync-on-close */
 	unsigned int	h_jdata:	1;	/* force data journaling */
@@ -399,6 +412,10 @@
 
 	/* How many handles used this transaction? */
 	int t_handle_count;
+
+	/* List of registered callback functions for this transaction.
+	 * Called when the transaction is committed. */
+	struct list_head	t_jcb;
 };
 
 
@@ -647,6 +664,9 @@
 extern int	 journal_try_to_free_buffers(journal_t *, struct page *, int);
 extern int	 journal_stop(handle_t *);
 extern int	 journal_flush (journal_t *);
+extern void	 journal_callback_set(handle_t *handle,
+				      void (*fn)(struct journal_callback *,int),
+				      struct journal_callback *jcb);
 
 extern void	 journal_lock_updates (journal_t *);
 extern void	 journal_unlock_updates (journal_t *);
diff -Nru a/include/linux/kdev_t.h b/include/linux/kdev_t.h
--- a/include/linux/kdev_t.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/kdev_t.h	Fri Jul  5 16:42:59 2002
@@ -36,8 +36,7 @@
 Admissible operations on an object of type kdev_t:
 - passing it along
 - comparing it for equality with another such object
-- storing it in inode->i_dev, inode->i_rdev, req->rq_dev, de->dc_dev,
-- tty->device
+- storing it in inode->i_rdev, req->rq_dev, de->dc_dev, tty->device
 - using its bit pattern as argument in a hash function
 - finding its major and minor
 - complaining about it
diff -Nru a/include/linux/list.h b/include/linux/list.h
--- a/include/linux/list.h	Fri Jul  5 16:42:50 2002
+++ b/include/linux/list.h	Fri Jul  5 16:42:50 2002
@@ -136,6 +136,19 @@
 	return head->next == head;
 }
 
+static inline void __list_splice(list_t *list, list_t *head)
+{
+	list_t *first = list->next;
+	list_t *last = list->prev;
+	list_t *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
 /**
  * list_splice - join two lists
  * @list: the new list to add.
@@ -145,15 +158,22 @@
 {
 	list_t *first = list->next;
 
-	if (first != list) {
-		list_t *last = list->prev;
-		list_t *at = head->next;
-
-		first->prev = head;
-		head->next = first;
+	if (first != list)
+		__list_splice(list, head);
+}
 
-		last->next = at;
-		at->prev = last;
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(list_t *list, list_t *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
 	}
 }
 
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/mm.h	Fri Jul  5 16:42:56 2002
@@ -305,6 +305,16 @@
 #define NOPAGE_SIGBUS	(NULL)
 #define NOPAGE_OOM	((struct page *) (-1))
 
+/*
+ * Different kinds of faults, as returned by handle_mm_fault().
+ * Used to decide whether a process gets delivered SIGBUS or
+ * just gets major/minor fault counters bumped up.
+ */
+#define VM_FAULT_OOM	(-1)
+#define VM_FAULT_SIGBUS	0
+#define VM_FAULT_MINOR	1
+#define VM_FAULT_MAJOR	2
+
 /* The array of struct pages */
 extern struct page *mem_map;
 
diff -Nru a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
--- a/include/linux/nfsd/export.h	Fri Jul  5 16:42:48 2002
+++ b/include/linux/nfsd/export.h	Fri Jul  5 16:42:48 2002
@@ -70,7 +70,7 @@
 	int			ex_flags;
 	struct vfsmount *	ex_mnt;
 	struct dentry *		ex_dentry;
-	kdev_t			ex_dev;
+	dev_t			ex_dev;
 	ino_t			ex_ino;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
@@ -94,7 +94,7 @@
 void			exp_readunlock(void);
 struct svc_client *	exp_getclient(struct sockaddr_in *sin);
 void			exp_putclient(struct svc_client *clp);
-struct svc_export *	exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
+struct svc_export *	exp_get(struct svc_client *clp, dev_t dev, ino_t ino);
 struct svc_export *	exp_get_fsid(struct svc_client *clp, int fsid);
 struct svc_export *	exp_get_by_name(struct svc_client *clp,
 					struct vfsmount *mnt,
diff -Nru a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
--- a/include/linux/nfsd/nfsfh.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/nfsd/nfsfh.h	Fri Jul  5 16:43:00 2002
@@ -143,13 +143,13 @@
 	return udev;
 }
 
-static inline kdev_t u32_to_kdev_t(__u32 udev)
+static inline dev_t u32_to_dev_t(__u32 udev)
 {
 	unsigned int minor, major;
 
 	minor = (udev & 0xff) | ((udev >> 8) & 0xfff00);
 	major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00);
-	return mk_kdev(major, minor);
+	return MKDEV(major, minor);
 }
 
 static inline __u32 ino_t_to_u32(ino_t ino)
diff -Nru a/include/linux/raid/linear.h b/include/linux/raid/linear.h
--- a/include/linux/raid/linear.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/raid/linear.h	Fri Jul  5 16:42:59 2002
@@ -4,7 +4,6 @@
 #include <linux/raid/md.h>
 
 struct dev_info {
-	kdev_t		dev;
 	struct block_device *bdev;
 	unsigned long	size;
 	unsigned long	offset;
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/raid/md.h	Fri Jul  5 16:42:56 2002
@@ -66,7 +66,7 @@
 extern char * partition_name (kdev_t dev);
 extern inline char * bdev_partition_name (struct block_device *bdev)
 {
-	return partition_name(to_kdev_t(bdev->bd_dev));
+	return partition_name(bdev ? to_kdev_t(bdev->bd_dev) : NODEV);
 }
 extern int register_md_personality (int p_num, mdk_personality_t *p);
 extern int unregister_md_personality (int p_num);
@@ -77,7 +77,7 @@
 extern void md_interrupt_thread (mdk_thread_t *thread);
 extern void md_update_sb (mddev_t *mddev);
 extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
-extern void md_sync_acct(kdev_t dev, unsigned long nr_sectors);
+extern void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors);
 extern int md_error (mddev_t *mddev, struct block_device *bdev);
 extern int md_run_setup(void);
 
diff -Nru a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
--- a/include/linux/raid/md_k.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/raid/md_k.h	Fri Jul  5 16:42:56 2002
@@ -160,16 +160,6 @@
 	int desc_nr;			/* descriptor index in the superblock */
 };
 
-
-/*
- * disk operations in a working array:
- */
-#define DISKOP_SPARE_INACTIVE	0
-#define DISKOP_SPARE_WRITE	1
-#define DISKOP_SPARE_ACTIVE	2
-#define DISKOP_HOT_REMOVE_DISK	3
-#define DISKOP_HOT_ADD_DISK	4
-
 typedef struct mdk_personality_s mdk_personality_t;
 
 struct mddev_s
@@ -213,19 +203,12 @@
 	int (*run)(mddev_t *mddev);
 	int (*stop)(mddev_t *mddev);
 	int (*status)(char *page, mddev_t *mddev);
-	int (*error_handler)(mddev_t *mddev, kdev_t dev);
-
-/*
- * Some personalities (RAID-1, RAID-5) can have disks hot-added and
- * hot-removed. Hot removal is different from failure. (failure marks
- * a disk inactive, but the disk is still part of the array) The interface
- * to such operations is the 'pers->diskop()' function, can be NULL.
- *
- * the diskop function can change the pointer pointing to the incoming
- * descriptor, but must do so very carefully. (currently only
- * SPARE_ACTIVE expects such a change)
- */
-	int (*diskop) (mddev_t *mddev, mdp_disk_t **descriptor, int state);
+	int (*error_handler)(mddev_t *mddev, struct block_device *bdev);
+	int (*hot_add_disk) (mddev_t *mddev, mdp_disk_t *descriptor, mdk_rdev_t *rdev);
+	int (*hot_remove_disk) (mddev_t *mddev, int number);
+	int (*spare_write) (mddev_t *mddev, int number);
+	int (*spare_inactive) (mddev_t *mddev);
+	int (*spare_active) (mddev_t *mddev, mdp_disk_t **descriptor);
 	int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
 };
 
diff -Nru a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h
--- a/include/linux/raid/multipath.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/raid/multipath.h	Fri Jul  5 16:43:00 2002
@@ -6,7 +6,6 @@
 struct multipath_info {
 	int		number;
 	int		raid_disk;
-	kdev_t		dev;
 	struct block_device *bdev;
 
 	/*
diff -Nru a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
--- a/include/linux/raid/raid1.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/raid/raid1.h	Fri Jul  5 16:43:00 2002
@@ -8,7 +8,6 @@
 struct mirror_info {
 	int		number;
 	int		raid_disk;
-	kdev_t		dev;
 	struct block_device *bdev;
 	sector_t	head_position;
 	atomic_t	nr_pending;
diff -Nru a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
--- a/include/linux/raid/raid5.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/raid/raid5.h	Fri Jul  5 16:42:59 2002
@@ -192,7 +192,6 @@
  
 
 struct disk_info {
-	kdev_t	dev;
 	struct block_device *bdev;
 	int	operational;
 	int	number;
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/reiserfs_fs.h	Fri Jul  5 16:43:00 2002
@@ -1675,13 +1675,10 @@
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
 int reiserfs_in_journal(struct super_block *p_s_sb, unsigned long bl, int searchall, unsigned long *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-struct super_block *reiserfs_get_super(kdev_t dev) ;
 void flush_async_commits(struct super_block *p_s_sb) ;
 
 int buffer_journaled(const struct buffer_head *bh) ;
 int mark_buffer_journal_new(struct buffer_head *bh) ;
-int reiserfs_sync_all_buffers(kdev_t dev, int wait) ;
-int reiserfs_sync_buffers(kdev_t dev, int wait) ;
 int reiserfs_add_page_to_flush_list(struct reiserfs_transaction_handle *,
                                     struct inode *, struct buffer_head *) ;
 int reiserfs_remove_page_from_flush_list(struct reiserfs_transaction_handle *,
diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
--- a/include/linux/reiserfs_fs_sb.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/reiserfs_fs_sb.h	Fri Jul  5 16:43:00 2002
@@ -160,7 +160,7 @@
   int t_blocks_allocated ;      /* number of blocks this writer allocated */
   unsigned long t_trans_id ;    /* sanity check, equals the current trans id */
   struct super_block *t_super ; /* super for this FS when journal_begin was 
-                                   called. saves calls to reiserfs_get_super */
+                                   called. */
 } ;
 
 /*
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/sched.h	Fri Jul  5 16:42:56 2002
@@ -10,7 +10,6 @@
 #include <linux/threads.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/times.h>
 #include <linux/timex.h>
 #include <linux/jiffies.h>
 #include <linux/rbtree.h>
@@ -310,7 +309,7 @@
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
-	struct tms times;
+	unsigned long utime, stime, cutime, cstime;
 	unsigned long start_time;
 	long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
@@ -386,12 +385,12 @@
 #define PF_MEMDIE	0x00001000	/* Killed for out-of-memory */
 #define PF_FREE_PAGES	0x00002000	/* per process page freeing */
 #define PF_FLUSHER	0x00004000	/* responsible for disk writeback */
-#define PF_RADIX_TREE	0x00008000	/* debug: performing radix tree alloc */
+#define PF_NOWARN	0x00008000	/* debug: don't warn if alloc fails */
 
 #define PF_FREEZE	0x00010000	/* this task should be frozen for suspend */
 #define PF_IOTHREAD	0x00020000	/* this thread is needed for doing I/O to swap */
 #define PF_FROZEN	0x00040000	/* frozen for system suspend */
-
+#define PF_INVALIDATE	0x00080000	/* debug: unmounting an fs. killme. */
 /*
  * Ptrace flags
  */
@@ -418,8 +417,7 @@
 extern int task_nice(task_t *p);
 extern int idle_cpu(int cpu);
 
-asmlinkage long sys_sched_yield(void);
-#define yield() sys_sched_yield()
+void yield(void);
 
 /*
  * The default (Linux) execution domain.
@@ -837,10 +835,11 @@
 	return unlikely(test_thread_flag(TIF_NEED_RESCHED));
 }
 
+extern void __cond_resched(void);
 static inline void cond_resched(void)
 {
 	if (need_resched())
-		schedule();
+		__cond_resched();
 }
 
 /* Reevaluate whether the task has signals pending delivery.
diff -Nru a/include/linux/smb.h b/include/linux/smb.h
--- a/include/linux/smb.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/smb.h	Fri Jul  5 16:43:00 2002
@@ -10,7 +10,6 @@
 #define _LINUX_SMB_H
 
 #include <linux/types.h>
-#include <linux/kdev_t.h>
 
 enum smb_protocol { 
 	SMB_PROTOCOL_NONE, 
@@ -85,7 +84,6 @@
 	nlink_t		f_nlink;
 	uid_t		f_uid;
 	gid_t		f_gid;
-	kdev_t		f_rdev;
 	loff_t		f_size;
 	time_t		f_atime;
 	time_t		f_mtime;
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Fri Jul  5 16:42:48 2002
+++ b/include/linux/sysctl.h	Fri Jul  5 16:42:48 2002
@@ -30,7 +30,10 @@
 
 struct file;
 
-#define CTL_MAXNAME 10
+#define CTL_MAXNAME 10		/* how many path components do we allow in a
+				   call to sysctl?   In other words, what is
+				   the largest acceptable value for the nlen
+				   member of a struct __sysctl_args to have? */
 
 struct __sysctl_args {
 	int *name;
@@ -145,6 +148,7 @@
 	VM_DIRTY_SYNC=13,	/* dirty_sync_ratio */
 	VM_DIRTY_WB_CS=14,	/* dirty_writeback_centisecs */
 	VM_DIRTY_EXPIRE_CS=15,	/* dirty_expire_centisecs */
+	VM_NR_PDFLUSH_THREADS=16, /* nr_pdflush_threads */
 };
 
 
diff -Nru a/include/linux/time.h b/include/linux/time.h
--- a/include/linux/time.h	Fri Jul  5 16:43:00 2002
+++ b/include/linux/time.h	Fri Jul  5 16:43:00 2002
@@ -12,6 +12,16 @@
 };
 #endif /* _STRUCT_TIMESPEC */
 
+struct timeval {
+	time_t		tv_sec;		/* seconds */
+	suseconds_t	tv_usec;	/* microseconds */
+};
+
+struct timezone {
+	int	tz_minuteswest;	/* minutes west of Greenwich */
+	int	tz_dsttime;	/* type of dst correction */
+};
+
 #ifdef __KERNEL__
 
 /*
@@ -48,6 +58,27 @@
 	value->tv_sec = jiffies / HZ;
 }
 
+/* Same for "timeval" */
+static __inline__ unsigned long
+timeval_to_jiffies(struct timeval *value)
+{
+	unsigned long sec = value->tv_sec;
+	long usec = value->tv_usec;
+
+	if (sec >= (MAX_JIFFY_OFFSET / HZ))
+		return MAX_JIFFY_OFFSET;
+	usec += 1000000L / HZ - 1;
+	usec /= 1000000L / HZ;
+	return HZ * sec + usec;
+}
+
+static __inline__ void
+jiffies_to_timeval(unsigned long jiffies, struct timeval *value)
+{
+	value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
+	value->tv_sec = jiffies / HZ;
+}
+
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
@@ -87,17 +118,6 @@
 #define CURRENT_TIME (xtime.tv_sec)
 
 #endif /* __KERNEL__ */
-
-
-struct timeval {
-	time_t		tv_sec;		/* seconds */
-	suseconds_t	tv_usec;	/* microseconds */
-};
-
-struct timezone {
-	int	tz_minuteswest;	/* minutes west of Greenwich */
-	int	tz_dsttime;	/* type of dst correction */
-};
 
 #define NFDBITS			__NFDBITS
 
diff -Nru a/include/linux/times.h b/include/linux/times.h
--- a/include/linux/times.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/times.h	Fri Jul  5 16:42:56 2002
@@ -1,6 +1,10 @@
 #ifndef _LINUX_TIMES_H
 #define _LINUX_TIMES_H
 
+#ifdef __KERNEL__
+# define jiffies_to_clock_t(x) ((x) / (HZ / USER_HZ))
+#endif
+
 struct tms {
 	clock_t tms_utime;
 	clock_t tms_stime;
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Fri Jul  5 16:42:59 2002
+++ b/include/linux/usb.h	Fri Jul  5 16:42:59 2002
@@ -104,6 +104,7 @@
 #include <linux/interrupt.h>	/* for in_interrupt() */
 #include <linux/list.h>		/* for struct list_head */
 #include <linux/device.h>	/* for struct device */
+#include <linux/fs.h>		/* for struct file_operations */
 
 
 static __inline__ void wait_ms(unsigned int ms)
@@ -648,14 +649,6 @@
  *	because its device has been (or is being) disconnected.  The
  *	handle passed is what was returned by probe(), or was provided
  *	to usb_driver_claim_interface().
- * @fops: USB drivers can reuse some character device framework in
- *	the USB subsystem by providing a file operations vector and
- *	a minor number.
- * @minor: Used with fops to simplify creating USB character devices.
- *	Such drivers have sixteen character devices, using the USB
- *	major number and starting with this minor number.
- * @num_minors: Used with minor to specify how many minors are used by
- *	this driver.
  * @ioctl: Used for drivers that want to talk to userspace through
  *	the "usbfs" filesystem.  This lets devices provide ways to
  *	expose information to user space regardless of where they
@@ -694,11 +687,6 @@
 	    );
 
 	struct list_head driver_list;
-
-	struct file_operations *fops;
-	int minor;
-	int num_minors;
-
 	struct semaphore serialize;
 
 	/* ioctl -- userspace apps can talk to drivers through usbfs */
@@ -722,13 +710,8 @@
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
-#ifndef CONFIG_USB_DYNAMIC_MINORS
-static inline int usb_register_dev(struct usb_driver *new_driver, int num_minors, int *start_minor) { return -ENODEV; }
-static inline void usb_deregister_dev(struct usb_driver *driver, int num_minors, int start_minor) {}
-#else
-extern int usb_register_dev(struct usb_driver *new_driver, int num_minors, int *start_minor);
-extern void usb_deregister_dev(struct usb_driver *driver, int num_minors, int start_minor);
-#endif
+extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor);
+extern void usb_deregister_dev(int num_minors, int start_minor);
 
 /* -------------------------------------------------------------------------- */
 
diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h
--- a/include/linux/writeback.h	Fri Jul  5 16:42:56 2002
+++ b/include/linux/writeback.h	Fri Jul  5 16:42:56 2002
@@ -24,18 +24,22 @@
 /*
  * fs/fs-writeback.c
  */
-#define WB_SYNC_NONE	0	/* Don't wait on anything */
-#define WB_SYNC_LAST	1	/* Wait on the last-written mapping */
-#define WB_SYNC_ALL	2	/* Wait on every mapping */
-#define WB_SYNC_HOLD	3	/* Hold the inode on sb_dirty for sys_sync() */
+enum writeback_sync_modes {
+	WB_SYNC_NONE =  0,	/* Don't wait on anything */
+	WB_SYNC_LAST =  1,	/* Wait on the last-written mapping */
+	WB_SYNC_ALL =   2,	/* Wait on every mapping */
+	WB_SYNC_HOLD =  3,	/* Hold the inode on sb_dirty for sys_sync() */
+};
 
-void writeback_unlocked_inodes(int *nr_to_write, int sync_mode,
-				unsigned long *older_than_this);
+void writeback_unlocked_inodes(int *nr_to_write,
+			       enum writeback_sync_modes sync_mode,
+			       unsigned long *older_than_this);
 void wake_up_inode(struct inode *inode);
 void __wait_on_inode(struct inode * inode);
 void sync_inodes_sb(struct super_block *, int wait);
 void sync_inodes(int wait);
 
+/* writeback.h requires fs.h; it, too, is not included from here. */
 static inline void wait_on_inode(struct inode *inode)
 {
 	if (inode->i_state & I_LOCK)
@@ -45,15 +49,22 @@
 /*
  * mm/page-writeback.c
  */
+/* These 5 are exported to sysctl. */
 extern int dirty_background_ratio;
 extern int dirty_async_ratio;
 extern int dirty_sync_ratio;
 extern int dirty_writeback_centisecs;
 extern int dirty_expire_centisecs;
 
+
 void balance_dirty_pages(struct address_space *mapping);
 void balance_dirty_pages_ratelimited(struct address_space *mapping);
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
 int do_writepages(struct address_space *mapping, int *nr_to_write);
+
+/* pdflush.c */
+extern int nr_pdflush_threads;	/* Global so it can be exported to sysctl
+				   read-only. */
+
 
 #endif		/* WRITEBACK_H */
diff -Nru a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c	Fri Jul  5 16:43:00 2002
+++ b/kernel/acct.c	Fri Jul  5 16:43:00 2002
@@ -319,8 +319,8 @@
 	ac.ac_btime = CT_TO_SECS(current->start_time) +
 		(xtime.tv_sec - (jiffies / HZ));
 	ac.ac_etime = encode_comp_t(jiffies - current->start_time);
-	ac.ac_utime = encode_comp_t(current->times.tms_utime);
-	ac.ac_stime = encode_comp_t(current->times.tms_stime);
+	ac.ac_utime = encode_comp_t(current->utime);
+	ac.ac_stime = encode_comp_t(current->stime);
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
 	ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0;
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/exit.c	Fri Jul  5 16:42:59 2002
@@ -648,8 +648,8 @@
 				}
 				goto end_wait4;
 			case TASK_ZOMBIE:
-				current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
-				current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
+				current->cutime += p->utime + p->cutime;
+				current->cstime += p->stime + p->cstime;
 				read_unlock(&tasklist_lock);
 				retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
 				if (!retval && stat_addr)
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Fri Jul  5 16:42:56 2002
+++ b/kernel/fork.c	Fri Jul  5 16:42:56 2002
@@ -686,8 +686,8 @@
 
 	p->leader = 0;		/* session leadership doesn't inherit */
 	p->tty_old_pgrp = 0;
-	p->times.tms_utime = p->times.tms_stime = 0;
-	p->times.tms_cutime = p->times.tms_cstime = 0;
+	p->utime = p->stime = 0;
+	p->cutime = p->cstime = 0;
 #ifdef CONFIG_SMP
 	{
 		int i;
diff -Nru a/kernel/itimer.c b/kernel/itimer.c
--- a/kernel/itimer.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/itimer.c	Fri Jul  5 16:42:59 2002
@@ -12,34 +12,6 @@
 
 #include <asm/uaccess.h>
 
-/*
- * change timeval to jiffies, trying to avoid the 
- * most obvious overflows..
- *
- * The tv_*sec values are signed, but nothing seems to 
- * indicate whether we really should use them as signed values
- * when doing itimers. POSIX doesn't mention this (but if
- * alarm() uses itimers without checking, we have to use unsigned
- * arithmetic).
- */
-static unsigned long tvtojiffies(struct timeval *value)
-{
-	unsigned long sec = (unsigned) value->tv_sec;
-	unsigned long usec = (unsigned) value->tv_usec;
-
-	if (sec > (ULONG_MAX / HZ))
-		return ULONG_MAX;
-	usec += 1000000 / HZ - 1;
-	usec /= 1000000 / HZ;
-	return HZ*sec+usec;
-}
-
-static void jiffiestotv(unsigned long jiffies, struct timeval *value)
-{
-	value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
-	value->tv_sec = jiffies / HZ;
-}
-
 int do_getitimer(int which, struct itimerval *value)
 {
 	register unsigned long val, interval;
@@ -70,8 +42,8 @@
 	default:
 		return(-EINVAL);
 	}
-	jiffiestotv(val, &value->it_value);
-	jiffiestotv(interval, &value->it_interval);
+	jiffies_to_timeval(val, &value->it_value);
+	jiffies_to_timeval(interval, &value->it_interval);
 	return 0;
 }
 
@@ -110,8 +82,8 @@
 	register unsigned long i, j;
 	int k;
 
-	i = tvtojiffies(&value->it_interval);
-	j = tvtojiffies(&value->it_value);
+	i = timeval_to_jiffies(&value->it_interval);
+	j = timeval_to_jiffies(&value->it_value);
 	if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
 		return k;
 	switch (which) {
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Fri Jul  5 16:42:50 2002
+++ b/kernel/ksyms.c	Fri Jul  5 16:42:50 2002
@@ -185,7 +185,6 @@
 EXPORT_SYMBOL(invalidate_device);
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
-EXPORT_SYMBOL(fsync_dev);
 EXPORT_SYMBOL(fsync_bdev);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
@@ -196,14 +195,12 @@
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(sb_set_blocksize);
 EXPORT_SYMBOL(sb_min_blocksize);
-EXPORT_SYMBOL(__getblk);
 EXPORT_SYMBOL(cdget);
 EXPORT_SYMBOL(cdput);
 EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bd_claim);
 EXPORT_SYMBOL(bd_release);
-EXPORT_SYMBOL(__bread);
 EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);
@@ -329,11 +326,11 @@
 /* block device driver support */
 EXPORT_SYMBOL(blk_size);
 EXPORT_SYMBOL(blk_dev);
-EXPORT_SYMBOL(is_read_only);
 EXPORT_SYMBOL(bdev_read_only);
 EXPORT_SYMBOL(set_device_ro);
 EXPORT_SYMBOL(bmap);
 EXPORT_SYMBOL(devfs_register_partitions);
+EXPORT_SYMBOL(driverfs_remove_partitions);
 EXPORT_SYMBOL(blkdev_open);
 EXPORT_SYMBOL(blkdev_get);
 EXPORT_SYMBOL(blkdev_put);
@@ -474,7 +471,8 @@
 EXPORT_SYMBOL(preempt_schedule);
 #endif
 EXPORT_SYMBOL(schedule_timeout);
-EXPORT_SYMBOL(sys_sched_yield);
+EXPORT_SYMBOL(yield);
+EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(set_user_nice);
 EXPORT_SYMBOL(task_nice);
 EXPORT_SYMBOL_GPL(idle_cpu);
@@ -549,7 +547,6 @@
 EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(init_special_inode);
-EXPORT_SYMBOL(__find_get_block);
 EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(__insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
@@ -588,6 +585,7 @@
 EXPORT_SYMBOL(__run_task_queue);
 EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(raise_softirq);
+EXPORT_SYMBOL(open_softirq);
 EXPORT_SYMBOL(cpu_raise_softirq);
 EXPORT_SYMBOL(__tasklet_schedule);
 EXPORT_SYMBOL(__tasklet_hi_schedule);
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/sched.c	Fri Jul  5 16:42:59 2002
@@ -1447,6 +1447,18 @@
 	return 0;
 }
 
+void __cond_resched(void)
+{
+	set_current_state(TASK_RUNNING);
+	schedule();
+}
+
+void yield(void)
+{
+	set_current_state(TASK_RUNNING);
+	sys_sched_yield();
+}
+
 asmlinkage long sys_sched_get_priority_max(int policy)
 {
 	int ret = -EINVAL;
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/signal.c	Fri Jul  5 16:42:59 2002
@@ -779,8 +779,8 @@
 	info.si_uid = tsk->uid;
 
 	/* FIXME: find out whether or not this is supposed to be c*time. */
-	info.si_utime = tsk->times.tms_utime;
-	info.si_stime = tsk->times.tms_stime;
+	info.si_utime = tsk->utime;
+	info.si_stime = tsk->stime;
 
 	status = tsk->exit_code & 0x7f;
 	why = SI_KERNEL;	/* shouldn't happen */
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/softirq.c	Fri Jul  5 16:42:59 2002
@@ -262,7 +262,6 @@
 		printk("Attempt to kill tasklet from interrupt\n");
 
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		current->state = TASK_RUNNING;
 		do
 			yield();
 		while (test_bit(TASKLET_STATE_SCHED, &t->state));
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/suspend.c	Fri Jul  5 16:42:59 2002
@@ -237,8 +237,7 @@
 			todo++;
 		}
 		read_unlock(&tasklist_lock);
-		sys_sched_yield();
-		schedule();
+		yield();
 		if (time_after(jiffies, start_time + TIMEOUT)) {
 			PRINTK( "\n" );
 			printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo );
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Fri Jul  5 16:42:56 2002
+++ b/kernel/sys.c	Fri Jul  5 16:42:56 2002
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/device.h>
+#include <linux/times.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -833,10 +834,16 @@
 	 *	atomically safe type this is just fine. Conceptually its
 	 *	as if the syscall took an instant longer to occur.
 	 */
-	if (tbuf)
-		if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
+	if (tbuf) {
+		struct tms tmp;
+		tmp.tms_utime = jiffies_to_clock_t(current->utime);
+		tmp.tms_stime = jiffies_to_clock_t(current->stime);
+		tmp.tms_cutime = jiffies_to_clock_t(current->cutime);
+		tmp.tms_cstime = jiffies_to_clock_t(current->cstime);
+		if (copy_to_user(tbuf, &tmp, sizeof(struct tms)))
 			return -EFAULT;
-	return jiffies;
+	}
+	return jiffies_to_clock_t(jiffies);
 }
 
 /*
@@ -1193,28 +1200,22 @@
 	memset((char *) &r, 0, sizeof(r));
 	switch (who) {
 		case RUSAGE_SELF:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
+			jiffies_to_timeval(p->utime, &r.ru_utime);
+			jiffies_to_timeval(p->stime, &r.ru_stime);
 			r.ru_minflt = p->min_flt;
 			r.ru_majflt = p->maj_flt;
 			r.ru_nswap = p->nswap;
 			break;
 		case RUSAGE_CHILDREN:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
+			jiffies_to_timeval(p->cutime, &r.ru_utime);
+			jiffies_to_timeval(p->cstime, &r.ru_stime);
 			r.ru_minflt = p->cmin_flt;
 			r.ru_majflt = p->cmaj_flt;
 			r.ru_nswap = p->cnswap;
 			break;
 		default:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
+			jiffies_to_timeval(p->utime + p->cutime, &r.ru_utime);
+			jiffies_to_timeval(p->stime + p->cstime, &r.ru_stime);
 			r.ru_minflt = p->min_flt + p->cmin_flt;
 			r.ru_majflt = p->maj_flt + p->cmaj_flt;
 			r.ru_nswap = p->nswap + p->cnswap;
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Fri Jul  5 16:42:56 2002
+++ b/kernel/sysctl.c	Fri Jul  5 16:42:56 2002
@@ -258,6 +258,13 @@
 	{0}
 };
 
+/* Constants for minimum and maximum testing in vm_table.
+   We use these as one-element integer vectors. */
+static int zero = 0;
+static int one = 1;
+static int one_hundred = 100;
+
+
 static ctl_table vm_table[] = {
 	{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
 	 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
@@ -266,18 +273,37 @@
 	{VM_PAGE_CLUSTER, "page-cluster", 
 	 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_DIRTY_BACKGROUND, "dirty_background_ratio",
-	&dirty_background_ratio, sizeof(dirty_background_ratio),
-	0644, NULL, &proc_dointvec},
+	 &dirty_background_ratio, sizeof(dirty_background_ratio),
+	 0644, NULL, &proc_dointvec_minmax,  &sysctl_intvec, NULL,
+	 &zero, &one_hundred },
 	{VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio,
-	sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec},
+	 sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax,
+	 &sysctl_intvec, NULL, &zero, &one_hundred },
 	{VM_DIRTY_SYNC, "dirty_sync_ratio", &dirty_sync_ratio,
-	sizeof(dirty_sync_ratio), 0644, NULL, &proc_dointvec},
+	 sizeof(dirty_sync_ratio), 0644, NULL, &proc_dointvec_minmax,
+	 &sysctl_intvec, NULL, &zero, &one_hundred },
 	{VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
-	&dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
-	NULL, &proc_dointvec},
+	 &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
+	 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
+	 /* Here, we define the range of possible values for
+	    dirty_writeback_centisecs.
+
+	    The default value is 5 seconds (500 centisec).  We will use 1
+	    centisec, the smallest possible value that could make any sort of
+	    sense.  If we allowed the user to set the interval to 0 seconds
+	    (which would presumably mean to chew up all of the CPU looking for
+	    dirty pages and writing them out, without taking a break), the
+	    interval would effectively become 1 second (100 centisecs), due to
+	    some nicely documented throttling code in wb_kupdate().
+
+	    There is no maximum legal value for dirty_writeback. */
+	 &one , NULL},
 	{VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs",
-	&dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644,
-	NULL, &proc_dointvec},
+	 &dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644,
+	 NULL, &proc_dointvec},
+	{ VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads",
+	  &nr_pdflush_threads, sizeof nr_pdflush_threads,
+	  0444 /* read-only*/, NULL, &proc_dointvec},
 	{0}
 };
 
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Fri Jul  5 16:42:59 2002
+++ b/kernel/timer.c	Fri Jul  5 16:42:59 2002
@@ -527,8 +527,8 @@
 {
 	unsigned long psecs;
 
-	psecs = (p->times.tms_utime += user);
-	psecs += (p->times.tms_stime += system);
+	psecs = (p->utime += user);
+	psecs += (p->stime += system);
 	if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_cur) {
 		/* Send SIGXCPU every second.. */
 		if (!(psecs % HZ))
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Fri Jul  5 16:42:59 2002
+++ b/mm/filemap.c	Fri Jul  5 16:42:59 2002
@@ -177,8 +177,13 @@
 static void truncate_complete_page(struct page *page)
 {
 	/* Leave it on the LRU if it gets converted into anonymous buffers */
-	if (!PagePrivate(page) || do_invalidatepage(page, 0))
+	if (!PagePrivate(page) || do_invalidatepage(page, 0)) {
 		lru_cache_del(page);
+	} else {
+		if (current->flags & PF_INVALIDATE)
+			printk("%s: buffer heads were leaked\n",
+				current->comm);
+	}
 	ClearPageDirty(page);
 	ClearPageUptodate(page);
 	remove_inode_page(page);
@@ -362,16 +367,18 @@
 	while (curr != head) {
 		page = list_entry(curr, struct page, list);
 
-		if (PageWriteback(page)) {
-			write_unlock(&mapping->page_lock);
-			wait_on_page_writeback(page);
-			unlocked = 1;
-			write_lock(&mapping->page_lock);
-			goto restart;
-		}
 		if (!TestSetPageLocked(page)) {
 			int __unlocked;
 
+			if (PageWriteback(page)) {
+				write_unlock(&mapping->page_lock);
+				wait_on_page_writeback(page);
+				unlocked = 1;
+				write_lock(&mapping->page_lock);
+				unlock_page(page);
+				goto restart;
+			}
+
 			__unlocked = invalidate_this_page2(mapping, page, curr, head);
 			unlock_page(page);
 			unlocked |= __unlocked;
@@ -510,24 +517,32 @@
 }
 
 /*
- * This adds a page to the page cache, starting out as locked,
- * owned by us, but unreferenced, not uptodate and with no errors.
- * The caller must hold a write_lock on the mapping->page_lock.
+ * This adds a page to the page cache, starting out as locked, unreferenced,
+ * not uptodate and with no errors.
+ *
+ * The caller must hold a write_lock on mapping->page_lock.
+ *
+ * This function is used for two things: adding newly allocated pagecache
+ * pages and for moving existing anon pages into swapcache.
+ *
+ * In the case of pagecache pages, the page is new, so we can just run
+ * SetPageLocked() against it.  The other page state flags were set by
+ * rmqueue()
+ *
+ * In the case of swapcache, try_to_swap_out() has already locked the page, so
+ * SetPageLocked() is ugly-but-OK there too.  The required page state has been
+ * set up by swap_out_add_to_swap_cache().
  */
 static int __add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long offset)
 {
-	page_cache_get(page);
-	if (radix_tree_insert(&mapping->page_tree, offset, page) < 0)
-		goto nomem;
-	page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
-			1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked);
-	SetPageLocked(page);
-	ClearPageDirty(page);
-	___add_to_page_cache(page, mapping, offset);
-	return 0;
- nomem:
-	page_cache_release(page);
+	if (radix_tree_insert(&mapping->page_tree, offset, page) == 0) {
+		SetPageLocked(page);
+		ClearPageDirty(page);
+		___add_to_page_cache(page, mapping, offset);
+		page_cache_get(page);
+		return 0;
+	}
 	return -ENOMEM;
 }
 
@@ -1115,8 +1130,6 @@
 
 	retval = -EINVAL;
 	if ((offset & blocksize_mask) || (count & blocksize_mask))
-		goto out_free;
-	if (!mapping->a_ops->direct_IO)
 		goto out_free;
 
 	/*
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Fri Jul  5 16:43:00 2002
+++ b/mm/memory.c	Fri Jul  5 16:43:00 2002
@@ -503,18 +503,18 @@
 			while (!(map = follow_page(mm, start, write))) {
 				spin_unlock(&mm->page_table_lock);
 				switch (handle_mm_fault(mm, vma, start, write)) {
-				case 1:
+				case VM_FAULT_MINOR:
 					tsk->min_flt++;
 					break;
-				case 2:
+				case VM_FAULT_MAJOR:
 					tsk->maj_flt++;
 					break;
-				case 0:
-					if (i) return i;
-					return -EFAULT;
+				case VM_FAULT_SIGBUS:
+					return i ? i : -EFAULT;
+				case VM_FAULT_OOM:
+					return i ? i : -ENOMEM;
 				default:
-					if (i) return i;
-					return -ENOMEM;
+					BUG();
 				}
 				spin_lock(&mm->page_table_lock);
 			}
@@ -612,7 +612,7 @@
 		page = iobuf->maplist[index];
 		
 		if (!PageReserved(page))
-			SetPageDirty(page);
+			set_page_dirty(page);
 
 		remaining -= (PAGE_SIZE - offset);
 		offset = 0;
@@ -968,7 +968,7 @@
 			establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
 			pte_unmap(page_table);
 			spin_unlock(&mm->page_table_lock);
-			return 1;	/* Minor fault */
+			return VM_FAULT_MINOR;
 		}
 	}
 	pte_unmap(page_table);
@@ -1002,16 +1002,21 @@
 	spin_unlock(&mm->page_table_lock);
 	page_cache_release(new_page);
 	page_cache_release(old_page);
-	return 1;	/* Minor fault */
+	return VM_FAULT_MINOR;
 
 bad_wp_page:
 	pte_unmap(page_table);
 	spin_unlock(&mm->page_table_lock);
 	printk(KERN_ERR "do_wp_page: bogus page at address %08lx\n", address);
-	return -1;
+	/*
+	 * This should really halt the system so it can be debugged or
+	 * at least the kernel stops what it's doing before it corrupts
+	 * data, but for the moment just pretend this is OOM.
+	 */
+	return VM_FAULT_OOM;
 no_mem:
 	page_cache_release(old_page);
-	return -1;
+	return VM_FAULT_OOM;
 }
 
 static void vmtruncate_list(list_t *head, unsigned long pgoff)
@@ -1135,7 +1140,7 @@
 	struct page *page;
 	swp_entry_t entry = pte_to_swp_entry(orig_pte);
 	pte_t pte;
-	int ret = 1;
+	int ret = VM_FAULT_MINOR;
 
 	pte_unmap(page_table);
 	spin_unlock(&mm->page_table_lock);
@@ -1148,17 +1153,19 @@
 			 * Back out if somebody else faulted in this pte while
 			 * we released the page table lock.
 			 */
-			int retval;
 			spin_lock(&mm->page_table_lock);
 			page_table = pte_offset_map(pmd, address);
-			retval = pte_same(*page_table, orig_pte) ? -1 : 1;
+			if (pte_same(*page_table, orig_pte))
+				ret = VM_FAULT_OOM;
+			else
+				ret = VM_FAULT_MINOR;
 			pte_unmap(page_table);
 			spin_unlock(&mm->page_table_lock);
-			return retval;
+			return ret;
 		}
 
 		/* Had to read the page from swap area: Major fault */
-		ret = 2;
+		ret = VM_FAULT_MAJOR;
 	}
 
 	lock_page(page);
@@ -1174,7 +1181,7 @@
 		spin_unlock(&mm->page_table_lock);
 		unlock_page(page);
 		page_cache_release(page);
-		return 1;
+		return VM_FAULT_MINOR;
 	}
 
 	/* The page isn't present yet, go ahead with the fault. */
@@ -1232,7 +1239,7 @@
 			pte_unmap(page_table);
 			page_cache_release(page);
 			spin_unlock(&mm->page_table_lock);
-			return 1;
+			return VM_FAULT_MINOR;
 		}
 		mm->rss++;
 		flush_page_to_ram(page);
@@ -1246,10 +1253,10 @@
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
 	spin_unlock(&mm->page_table_lock);
-	return 1;	/* Minor fault */
+	return VM_FAULT_MINOR;
 
 no_mem:
-	return -1;
+	return VM_FAULT_OOM;
 }
 
 /*
@@ -1277,10 +1284,11 @@
 
 	new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, 0);
 
-	if (new_page == NULL)	/* no page was available -- SIGBUS */
-		return 0;
+	/* no page was available -- either SIGBUS or OOM */
+	if (new_page == NOPAGE_SIGBUS)
+		return VM_FAULT_SIGBUS;
 	if (new_page == NOPAGE_OOM)
-		return -1;
+		return VM_FAULT_OOM;
 
 	/*
 	 * Should we do an early C-O-W break?
@@ -1289,7 +1297,7 @@
 		struct page * page = alloc_page(GFP_HIGHUSER);
 		if (!page) {
 			page_cache_release(new_page);
-			return -1;
+			return VM_FAULT_OOM;
 		}
 		copy_user_highpage(page, new_page, address);
 		page_cache_release(new_page);
@@ -1325,13 +1333,13 @@
 		pte_unmap(page_table);
 		page_cache_release(new_page);
 		spin_unlock(&mm->page_table_lock);
-		return 1;
+		return VM_FAULT_MINOR;
 	}
 
 	/* no need to invalidate: a not-present page shouldn't be cached */
 	update_mmu_cache(vma, address, entry);
 	spin_unlock(&mm->page_table_lock);
-	return 2;	/* Major fault */
+	return VM_FAULT_MAJOR;
 }
 
 /*
@@ -1383,7 +1391,7 @@
 	establish_pte(vma, address, pte, entry);
 	pte_unmap(pte);
 	spin_unlock(&mm->page_table_lock);
-	return 1;
+	return VM_FAULT_MINOR;
 }
 
 /*
@@ -1411,7 +1419,7 @@
 			return handle_pte_fault(mm, vma, address, write_access, pte, pmd);
 	}
 	spin_unlock(&mm->page_table_lock);
-	return -1;
+	return VM_FAULT_OOM;
 }
 
 /*
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Fri Jul  5 16:42:56 2002
+++ b/mm/mmap.c	Fri Jul  5 16:42:56 2002
@@ -669,49 +669,53 @@
 struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
 				      struct vm_area_struct **pprev)
 {
-	if (mm) {
-		/* Go through the RB tree quickly. */
-		struct vm_area_struct * vma;
-		rb_node_t * rb_node, * rb_last_right, * rb_prev;
-		
-		rb_node = mm->mm_rb.rb_node;
-		rb_last_right = rb_prev = NULL;
-		vma = NULL;
-
-		while (rb_node) {
-			struct vm_area_struct * vma_tmp;
-
-			vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
-
-			if (vma_tmp->vm_end > addr) {
-				vma = vma_tmp;
-				rb_prev = rb_last_right;
-				if (vma_tmp->vm_start <= addr)
-					break;
-				rb_node = rb_node->rb_left;
-			} else {
-				rb_last_right = rb_node;
-				rb_node = rb_node->rb_right;
-			}
-		}
-		if (vma) {
-			if (vma->vm_rb.rb_left) {
-				rb_prev = vma->vm_rb.rb_left;
-				while (rb_prev->rb_right)
-					rb_prev = rb_prev->rb_right;
-			}
-			*pprev = NULL;
-			if (rb_prev)
-				*pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
-			if ((rb_prev ? (*pprev)->vm_next : mm->mmap) != vma)
-				BUG();
-			return vma;
+	struct vm_area_struct *vma = NULL, *prev = NULL;
+	rb_node_t * rb_node;
+	if (!mm)
+		goto out;
+
+	/* Guard against addr being lower than the first VMA */
+	vma = mm->mmap;
+
+	/* Go through the RB tree quickly. */
+	rb_node = mm->mm_rb.rb_node;
+
+	while (rb_node) {
+		struct vm_area_struct *vma_tmp;
+		vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
+
+		if (addr < vma_tmp->vm_end) {
+			rb_node = rb_node->rb_left;
+		} else {
+			prev = vma_tmp;
+			if (!prev->vm_next || (addr < prev->vm_next->vm_end))
+				break;
+			rb_node = rb_node->rb_right;
 		}
 	}
-	*pprev = NULL;
-	return NULL;
+
+ out:
+	*pprev = prev;
+	return prev ? prev->vm_next : vma;
 }
 
+#ifdef ARCH_STACK_GROWSUP
+struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
+{
+	struct vm_area_struct *vma, *prev;
+
+	addr &= PAGE_MASK;
+	vma = find_vma_prev(mm, addr, &prev);
+	if (vma && (vma->vm_start <= addr))
+		return vma;
+	if (!prev || expand_stack(prev, addr))
+		return NULL;
+	if (prev->vm_flags & VM_LOCKED) {
+		make_pages_present(addr, prev->vm_end);
+	}
+	return prev;
+}
+#else
 struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
 	struct vm_area_struct * vma;
@@ -733,6 +737,7 @@
 	}
 	return vma;
 }
+#endif
 
 /*
  * Try to free as many page directory entries as we can,
diff -Nru a/mm/oom_kill.c b/mm/oom_kill.c
--- a/mm/oom_kill.c	Fri Jul  5 16:42:48 2002
+++ b/mm/oom_kill.c	Fri Jul  5 16:42:48 2002
@@ -72,7 +72,7 @@
 	 * very well in practice. This is not safe against jiffie wraps
 	 * but we don't care _that_ much...
 	 */
-	cpu_time = (p->times.tms_utime + p->times.tms_stime) >> (SHIFT_HZ + 3);
+	cpu_time = (p->utime + p->stime) >> (SHIFT_HZ + 3);
 	run_time = (jiffies - p->start_time) >> (SHIFT_HZ + 10);
 
 	points /= int_sqrt(cpu_time);
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Fri Jul  5 16:42:59 2002
+++ b/mm/page-writeback.c	Fri Jul  5 16:42:59 2002
@@ -19,8 +19,9 @@
 #include <linux/pagemap.h>
 #include <linux/writeback.h>
 #include <linux/init.h>
-#include <linux/sysrq.h>
+//#include <linux/sysrq.h>
 #include <linux/backing-dev.h>
+#include <linux/mpage.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -47,6 +48,8 @@
 #define SYNC_WRITEBACK_PAGES	1500
 
 
+/* The following parameters are exported via /proc/sys/vm */
+
 /*
  * Dirty memory thresholds, in percentages
  */
@@ -67,15 +70,18 @@
 int dirty_sync_ratio = 60;
 
 /*
- * The interval between `kupdate'-style writebacks.
+ * The interval between `kupdate'-style writebacks, in centiseconds
+ * (hundredths of a second)
  */
 int dirty_writeback_centisecs = 5 * 100;
 
 /*
- * The largest amount of time for which data is allowed to remain dirty
+ * The longest amount of time for which data is allowed to remain dirty
  */
 int dirty_expire_centisecs = 30 * 100;
 
+/* End of sysctl-exported parameters */
+
 
 static void background_writeout(unsigned long _min_pages);
 
@@ -233,7 +239,8 @@
 static void wb_timer_fn(unsigned long unused)
 {
 	if (pdflush_operation(wb_kupdate, 0) < 0)
-		mod_timer(&wb_timer, jiffies + HZ);
+		mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
+
 }
 
 static int __init wb_timer_init(void)
@@ -307,108 +314,9 @@
 }
 EXPORT_SYMBOL(generic_vm_writeback);
 
-/**
- * generic_writepages - walk the list of dirty pages of the given
- * address space and writepage() all of them.
- * 
- * @mapping: address space structure to write
- * @nr_to_write: subtract the number of written pages from *@nr_to_write
- *
- * This is a library function, which implements the writepages()
- * address_space_operation.
- *
- * (The next two paragraphs refer to code which isn't here yet, but they
- *  explain the presence of address_space.io_pages)
- *
- * Pages can be moved from clean_pages or locked_pages onto dirty_pages
- * at any time - it's not possible to lock against that.  So pages which
- * have already been added to a BIO may magically reappear on the dirty_pages
- * list.  And generic_writepages() will again try to lock those pages.
- * But I/O has not yet been started against the page.  Thus deadlock.
- *
- * To avoid this, the entire contents of the dirty_pages list are moved
- * onto io_pages up-front.  We then walk io_pages, locking the
- * pages and submitting them for I/O, moving them to locked_pages.
- *
- * This has the added benefit of preventing a livelock which would otherwise
- * occur if pages are being dirtied faster than we can write them out.
- *
- * If a page is already under I/O, generic_writepages() skips it, even
- * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
- * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
- * and msync() need to guarentee that all the data which was dirty at the time
- * the call was made get new I/O started against them.  The way to do this is
- * to run filemap_fdatawait() before calling filemap_fdatawrite().
- *
- * It's fairly rare for PageWriteback pages to be on ->dirty_pages.  It
- * means that someone redirtied the page while it was under I/O.
- */
 int generic_writepages(struct address_space *mapping, int *nr_to_write)
 {
-	int (*writepage)(struct page *) = mapping->a_ops->writepage;
-	int ret = 0;
-	int done = 0;
-	int err;
-
-	write_lock(&mapping->page_lock);
-
-	list_splice(&mapping->dirty_pages, &mapping->io_pages);
-	INIT_LIST_HEAD(&mapping->dirty_pages);
-
-        while (!list_empty(&mapping->io_pages) && !done) {
-		struct page *page = list_entry(mapping->io_pages.prev,
-					struct page, list);
-		list_del(&page->list);
-		if (PageWriteback(page)) {
-			if (PageDirty(page)) {
-				list_add(&page->list, &mapping->dirty_pages);
-				continue;
-			}
-			list_add(&page->list, &mapping->locked_pages);
-			continue;
-		}
-		if (!PageDirty(page)) {
-			list_add(&page->list, &mapping->clean_pages);
-			continue;
-		}
-		list_add(&page->list, &mapping->locked_pages);
-		page_cache_get(page);
-		write_unlock(&mapping->page_lock);
-		lock_page(page);
-
-		/* It may have been removed from swapcache: check ->mapping */
-		if (page->mapping && TestClearPageDirty(page) &&
-					!PageWriteback(page)) {
-			/* FIXME: batch this up */
-			if (!PageActive(page) && PageLRU(page)) {
-				spin_lock(&pagemap_lru_lock);
-				if (!PageActive(page) && PageLRU(page)) {
-					list_del(&page->lru);
-					list_add(&page->lru, &inactive_list);
-				}
-				spin_unlock(&pagemap_lru_lock);
-			}
-			err = writepage(page);
-			if (!ret)
-				ret = err;
-			if (nr_to_write && --(*nr_to_write) <= 0)
-				done = 1;
-		} else {
-			unlock_page(page);
-		}
-
-		page_cache_release(page);
-		write_lock(&mapping->page_lock);
-	}
-	if (!list_empty(&mapping->io_pages)) {
-		/*
-		 * Put the rest back, in the correct order.
-		 */
-		list_splice(&mapping->io_pages, mapping->dirty_pages.prev);
-		INIT_LIST_HEAD(&mapping->io_pages);
-	}
-	write_unlock(&mapping->page_lock);
-	return ret;
+	return mpage_writepages(mapping, nr_to_write, NULL);
 }
 EXPORT_SYMBOL(generic_writepages);
 
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Fri Jul  5 16:42:56 2002
+++ b/mm/page_alloc.c	Fri Jul  5 16:42:56 2002
@@ -86,24 +86,24 @@
 	struct page *base;
 	zone_t *zone;
 
-	if (PagePrivate(page))
-		BUG();
-	if (page->mapping)
-		BUG();
-	if (PageLocked(page))
-		BUG();
-	if (PageLRU(page))
-		BUG();
-	if (PageActive(page))
-		BUG();
-	if (PageWriteback(page))
-		BUG();
-	ClearPageDirty(page);
-	page->flags &= ~(1<<PG_referenced);
-
-	if (current->flags & PF_FREE_PAGES)
-		goto local_freelist;
- back_local_freelist:
+	BUG_ON(PagePrivate(page));
+	BUG_ON(page->mapping != NULL);
+	BUG_ON(PageLocked(page));
+	BUG_ON(PageLRU(page));
+	BUG_ON(PageActive(page));
+	BUG_ON(PageWriteback(page));
+	if (PageDirty(page))
+		ClearPageDirty(page);
+	BUG_ON(page_count(page) != 0);
+
+	if (unlikely(current->flags & PF_FREE_PAGES)) {
+		if (!current->nr_local_pages && !in_interrupt()) {
+			list_add(&page->list, &current->local_pages);
+			page->index = order;
+			current->nr_local_pages++;
+			goto out;
+		}
+	}
 
 	zone = page_zone(page);
 
@@ -113,18 +113,14 @@
 	if (page_idx & ~mask)
 		BUG();
 	index = page_idx >> (1 + order);
-
 	area = zone->free_area + order;
 
 	spin_lock_irqsave(&zone->lock, flags);
-
 	zone->free_pages -= mask;
-
 	while (mask + (1 << (MAX_ORDER-1))) {
 		struct page *buddy1, *buddy2;
 
-		if (area >= zone->free_area + MAX_ORDER)
-			BUG();
+		BUG_ON(area >= zone->free_area + MAX_ORDER);
 		if (!__test_and_change_bit(index, area->map))
 			/*
 			 * the buddy page is still allocated.
@@ -137,11 +133,8 @@
 		 */
 		buddy1 = base + (page_idx ^ -mask);
 		buddy2 = base + page_idx;
-		if (bad_range(zone, buddy1))
-			BUG();
-		if (bad_range(zone, buddy2))
-			BUG();
-
+		BUG_ON(bad_range(zone, buddy1));
+		BUG_ON(bad_range(zone, buddy2));
 		list_del(&buddy1->list);
 		mask <<= 1;
 		area++;
@@ -149,19 +142,9 @@
 		page_idx &= mask;
 	}
 	list_add(&(base + page_idx)->list, &area->free_list);
-
 	spin_unlock_irqrestore(&zone->lock, flags);
+out:
 	return;
-
- local_freelist:
-	if (current->nr_local_pages)
-		goto back_local_freelist;
-	if (in_interrupt())
-		goto back_local_freelist;		
-
-	list_add(&page->list, &current->local_pages);
-	page->index = order;
-	current->nr_local_pages++;
 }
 
 #define MARK_USED(index, order, area) \
@@ -173,8 +156,7 @@
 	unsigned long size = 1 << high;
 
 	while (high > low) {
-		if (bad_range(zone, page))
-			BUG();
+		BUG_ON(bad_range(zone, page));
 		area--;
 		high--;
 		size >>= 1;
@@ -183,11 +165,28 @@
 		index += size;
 		page += size;
 	}
-	if (bad_range(zone, page))
-		BUG();
+	BUG_ON(bad_range(zone, page));
 	return page;
 }
 
+/*
+ * This page is about to be returned from the page allocator
+ */
+static inline void prep_new_page(struct page *page)
+{
+	BUG_ON(page->mapping);
+	BUG_ON(PagePrivate(page));
+	BUG_ON(PageLocked(page));
+	BUG_ON(PageLRU(page));
+	BUG_ON(PageActive(page));
+	BUG_ON(PageDirty(page));
+	BUG_ON(PageWriteback(page));
+	page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
+			1 << PG_referenced | 1 << PG_arch_1 |
+			1 << PG_checked);
+	set_page_count(page, 1);
+}
+
 static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order));
 static struct page * rmqueue(zone_t *zone, unsigned int order)
 {
@@ -206,8 +205,7 @@
 			unsigned int index;
 
 			page = list_entry(curr, struct page, list);
-			if (bad_range(zone, page))
-				BUG();
+			BUG_ON(bad_range(zone, page));
 			list_del(curr);
 			index = page - zone->zone_mem_map;
 			if (curr_order != MAX_ORDER-1)
@@ -217,13 +215,9 @@
 			page = expand(zone, page, index, order, curr_order, area);
 			spin_unlock_irqrestore(&zone->lock, flags);
 
-			set_page_count(page, 1);
 			if (bad_range(zone, page))
 				BUG();
-			if (PageLRU(page))
-				BUG();
-			if (PageActive(page))
-				BUG();
+			prep_new_page(page);
 			return page;	
 		}
 		curr_order++;
@@ -266,16 +260,14 @@
 }
 #endif
 
-static struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *));
-static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed)
+static /* inline */ struct page *
+balance_classzone(zone_t * classzone, unsigned int gfp_mask,
+			unsigned int order, int * freed)
 {
 	struct page * page = NULL;
 	int __freed = 0;
 
-	if (!(gfp_mask & __GFP_WAIT))
-		goto out;
-	if (in_interrupt())
-		BUG();
+	BUG_ON(in_interrupt());
 
 	current->allocation_order = order;
 	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
@@ -298,25 +290,9 @@
 				tmp = list_entry(entry, struct page, list);
 				if (tmp->index == order && memclass(page_zone(tmp), classzone)) {
 					list_del(entry);
-					current->nr_local_pages--;
-					set_page_count(tmp, 1);
 					page = tmp;
-
-					if (PagePrivate(page))
-						BUG();
-					if (page->mapping)
-						BUG();
-					if (PageLocked(page))
-						BUG();
-					if (PageLRU(page))
-						BUG();
-					if (PageActive(page))
-						BUG();
-					if (PageDirty(page))
-						BUG();
-					if (PageWriteback(page))
-						BUG();
-
+					current->nr_local_pages--;
+					prep_new_page(page);
 					break;
 				}
 			} while ((entry = entry->next) != local_pages);
@@ -333,7 +309,6 @@
 		}
 		current->nr_local_pages = 0;
 	}
- out:
 	*freed = __freed;
 	return page;
 }
@@ -380,7 +355,7 @@
 			break;
 
 		local_min = z->pages_min;
-		if (!(gfp_mask & __GFP_WAIT))
+		if (gfp_mask & __GFP_HIGH)
 			local_min >>= 2;
 		min += local_min;
 		if (z->free_pages > min) {
@@ -405,7 +380,7 @@
 				return page;
 		}
 nopage:
-		if (!(current->flags & PF_RADIX_TREE)) {
+		if (!(current->flags & PF_NOWARN)) {
 			printk("%s: page allocation failure."
 				" order:%d, mode:0x%x\n",
 				current->comm, order, gfp_mask);
@@ -441,7 +416,6 @@
 		goto nopage;
 
 	/* Yield for kswapd, and try again */
-	__set_current_state(TASK_RUNNING);
 	yield();
 	goto rebalance;
 }
@@ -800,8 +774,7 @@
 	unsigned long totalpages, offset, realtotalpages;
 	const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
 
-	if (zone_start_paddr & ~PAGE_MASK)
-		BUG();
+	BUG_ON(zone_start_paddr & ~PAGE_MASK);
 
 	totalpages = 0;
 	for (i = 0; i < MAX_NR_ZONES; i++) {
diff -Nru a/mm/page_io.c b/mm/page_io.c
--- a/mm/page_io.c	Fri Jul  5 16:42:56 2002
+++ b/mm/page_io.c	Fri Jul  5 16:42:56 2002
@@ -15,37 +15,26 @@
 #include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <linux/bio.h>
-#include <linux/buffer_head.h>
-#include <asm/pgtable.h>
 #include <linux/swapops.h>
-
-static int
-swap_get_block(struct inode *inode, sector_t iblock,
-		struct buffer_head *bh_result, int create)
-{
-	struct swap_info_struct *sis;
-	swp_entry_t entry;
-
-	entry.val = iblock;
-	sis = get_swap_info_struct(swp_type(entry));
-	bh_result->b_bdev = sis->bdev;
-	bh_result->b_blocknr = map_swap_page(sis, swp_offset(entry));
-	bh_result->b_size = PAGE_SIZE;
-	set_buffer_mapped(bh_result);
-	return 0;
-}
+#include <linux/buffer_head.h>	/* for block_sync_page() */
+#include <asm/pgtable.h>
 
 static struct bio *
 get_swap_bio(int gfp_flags, struct page *page, bio_end_io_t end_io)
 {
 	struct bio *bio;
-	struct buffer_head bh;
 
 	bio = bio_alloc(gfp_flags, 1);
 	if (bio) {
-		swap_get_block(NULL, page->index, &bh, 1);
-		bio->bi_sector = bh.b_blocknr * (PAGE_SIZE >> 9);
-		bio->bi_bdev = bh.b_bdev;
+		struct swap_info_struct *sis;
+		swp_entry_t entry;
+
+		entry.val = page->index;
+		sis = get_swap_info_struct(swp_type(entry));
+
+		bio->bi_sector = map_swap_page(sis, swp_offset(entry)) *
+					(PAGE_SIZE >> 9);
+		bio->bi_bdev = sis->bdev;
 		bio->bi_io_vec[0].bv_page = page;
 		bio->bi_io_vec[0].bv_len = PAGE_SIZE;
 		bio->bi_io_vec[0].bv_offset = 0;
@@ -98,6 +87,7 @@
 	}
 	bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
 	if (bio == NULL) {
+		set_page_dirty(page);
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -129,7 +119,7 @@
  * swapper_space doesn't have a real inode, so it gets a special vm_writeback()
  * so we don't need swap special cases in generic_vm_writeback().
  *
- * Swap pages are PageLocked and PageWriteback while under writeout so that
+ * Swap pages are !PageLocked and PageWriteback while under writeout so that
  * memory allocators will throttle against them.
  */
 static int swap_vm_writeback(struct page *page, int *nr_to_write)
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Fri Jul  5 16:43:00 2002
+++ b/mm/pdflush.c	Fri Jul  5 16:43:00 2002
@@ -15,6 +15,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
+#include <linux/sched.h>	// Needed by writeback.h
+#include <linux/fs.h>		// Needed by writeback.h
+#include <linux/writeback.h>	// Prototypes pdflush_operation()
 
 
 /*
@@ -44,8 +47,11 @@
 /*
  * The count of currently-running pdflush threads.  Protected
  * by pdflush_lock.
+ *
+ * Readable by sysctl, but not writable.  Published to userspace at
+ * /proc/sys/vm/nr_pdflush_threads.
  */
-static int nr_pdflush_threads = 0;
+int nr_pdflush_threads = 0;
 
 /*
  * The time at which the pdflush thread pool last went empty
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Fri Jul  5 16:42:59 2002
+++ b/mm/shmem.c	Fri Jul  5 16:42:59 2002
@@ -426,22 +426,15 @@
 	swap_free(entry);
 	ptr[offset] = (swp_entry_t) {0};
 
-	while (inode && (PageWriteback(page) ||
-			move_from_swap_cache(page, idx, inode->i_mapping))) {
+	while (inode && move_from_swap_cache(page, idx, inode->i_mapping)) {
 		/*
 		 * Yield for kswapd, and try again - but we're still
 		 * holding the page lock - ugh! fix this up later on.
 		 * Beware of inode being unlinked or truncated: just
 		 * leave try_to_unuse to delete_from_swap_cache if so.
-		 *
-		 * AKPM: We now wait on writeback too.  Note that it's
-		 * the page lock which prevents new writeback from starting.
 		 */
 		spin_unlock(&info->lock);
-		if (PageWriteback(page))
-			wait_on_page_writeback(page);
-		else
-			yield();
+		yield();
 		spin_lock(&info->lock);
 		ptr = shmem_swp_entry(info, idx, 0);
 		if (IS_ERR(ptr))
@@ -607,6 +600,7 @@
 			spin_unlock(&info->lock);
 			wait_on_page_writeback(page);
 			unlock_page(page);
+			page_cache_release(page);
 			goto repeat;
 		}
 		error = move_from_swap_cache(page, idx, mapping);
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Fri Jul  5 16:43:00 2002
+++ b/mm/slab.c	Fri Jul  5 16:43:00 2002
@@ -1153,12 +1153,12 @@
 	 * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
 	 * will eventually be caught here (where it matters).
 	 */
-	if (in_interrupt() && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC)
+	if (in_interrupt() && (flags & __GFP_WAIT))
 		BUG();
 
 	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
 	local_flags = (flags & SLAB_LEVEL_MASK);
-	if (local_flags == SLAB_ATOMIC)
+	if (!(local_flags & __GFP_WAIT))
 		/*
 		 * Not allowed to sleep.  Need to tell a constructor about
 		 * this - it might need to know...
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Fri Jul  5 16:42:59 2002
+++ b/mm/swap_state.c	Fri Jul  5 16:42:59 2002
@@ -21,16 +21,9 @@
 /*
  * swapper_inode doesn't do anything much.  It is really only here to
  * avoid some special-casing in other parts of the kernel.
- *
- * We set i_size to "infinity" to keep the page I/O functions happy.  The swap
- * block allocator makes sure that allocations are in-range.  A strange
- * number is chosen to prevent various arith overflows elsewhere.  For example,
- * `lblock' in block_read_full_page().
  */
 static struct inode swapper_inode = {
 	i_mapping:	&swapper_space,
-	i_size:		PAGE_SIZE * 0xffffffffLL,
-	i_blkbits:	PAGE_SHIFT,
 };
 
 extern struct address_space_operations swap_aops;
@@ -160,9 +153,13 @@
 
 		/* Add it to the swap cache */
 		*pslot = page;
-		page->flags &= ~(1 << PG_uptodate | 1 << PG_error
-				| 1 << PG_referenced | 1 << PG_arch_1
-				| 1 << PG_checked);
+		/*
+		 * This code used to clear PG_uptodate, PG_error, PG_arch1,
+		 * PG_referenced and PG_checked.  What _should_ it clear?
+		 */
+		ClearPageUptodate(page);
+		ClearPageReferenced(page);
+
 		SetPageLocked(page);
 		ClearPageDirty(page);
 		___add_to_page_cache(page, &swapper_space, entry.val);
@@ -205,9 +202,14 @@
 		__delete_from_swap_cache(page);
 
 		*pslot = page;
-		page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
-				 1 << PG_referenced | 1 << PG_arch_1 |
-				 1 << PG_checked);
+
+		/*
+		 * This code used to clear PG_uptodate, PG_error, PG_referenced,
+		 * PG_arch_1 and PG_checked.  It's not really clear why.
+		 */
+		ClearPageUptodate(page);
+		ClearPageReferenced(page);
+
 		/*
 		 * ___add_to_page_cache puts the page on ->clean_pages,
 		 * but it's dirty.  If it's on ->clean_pages, it will basically
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Fri Jul  5 16:42:59 2002
+++ b/mm/swapfile.c	Fri Jul  5 16:42:59 2002
@@ -687,11 +687,10 @@
 		if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
 			swap_writepage(page);
 			lock_page(page);
-		}
-		if (PageSwapCache(page)) {
 			wait_on_page_writeback(page);
-			delete_from_swap_cache(page);
 		}
+		if (PageSwapCache(page))
+			delete_from_swap_cache(page);
 
 		/*
 		 * So we could skip searching mms once swap count went
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Fri Jul  5 16:42:59 2002
+++ b/mm/vmscan.c	Fri Jul  5 16:42:59 2002
@@ -52,6 +52,9 @@
  * So PF_MEMALLOC is dropped here.  This causes the slab allocations to fail
  * earlier, so radix-tree nodes will then be allocated from the mempool
  * reserves.
+ *
+ * We're still using __GFP_HIGH for radix-tree node allocations, so some of
+ * the emergency pools are available - just not all of them.
  */
 static inline int
 swap_out_add_to_swap_cache(struct page *page, swp_entry_t entry)
@@ -60,7 +63,9 @@
 	int ret;
 
 	current->flags &= ~PF_MEMALLOC;
-	current->flags |= PF_RADIX_TREE;
+	current->flags |= PF_NOWARN;
+	ClearPageUptodate(page);		/* why? */
+	ClearPageReferenced(page);		/* why? */
 	ret = add_to_swap_cache(page, entry);
 	current->flags = flags;
 	return ret;
diff -Nru a/net/khttpd/Makefile b/net/khttpd/Makefile
--- a/net/khttpd/Makefile	Fri Jul  5 16:43:00 2002
+++ b/net/khttpd/Makefile	Fri Jul  5 16:43:00 2002
@@ -19,4 +19,4 @@
 # Generated files
 
 $(obj)/times.h: $(obj)/make_times_h
-	$< >$@
+	$(obj)/make_times_h >$@
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Fri Jul  5 16:42:59 2002
+++ b/net/socket.c	Fri Jul  5 16:42:59 2002
@@ -465,7 +465,7 @@
 	if (!inode)
 		return NULL;
 
-	inode->i_dev = NODEV;
+	inode->i_dev = 0;
 	sock = SOCKET_I(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
diff -Nru a/sound/oss/maestro.c b/sound/oss/maestro.c
--- a/sound/oss/maestro.c	Fri Jul  5 16:42:59 2002
+++ b/sound/oss/maestro.c	Fri Jul  5 16:42:59 2002
@@ -3573,9 +3573,18 @@
 static void maestro_remove(struct pci_dev *pcidev) {
 	struct ess_card *card = pci_get_drvdata(pcidev);
 	int i;
+	u32 n;
 	
 	/* XXX maybe should force stop bob, but should be all 
 		stopped by _release by now */
+
+	/* Turn off hardware volume control interrupt.
+	   This has to come before we leave the IRQ below,
+	   or a crash results if a button is pressed ! */
+	n = inw(card->iobase+0x18);
+	n&=~(1<<6);
+	outw(n, card->iobase+0x18);
+
 	free_irq(card->irq, card);
 	unregister_sound_mixer(card->dev_mixer);
 	for(i=0;i<NR_DSPS;i++)
