## Automatically generated incremental diff
## From:   linux-2.4.19-pre8
## To:     linux-2.4.19-pre9
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.19-pre8/CREDITS linux-2.4.19-pre9/CREDITS
--- linux-2.4.19-pre8/CREDITS	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/CREDITS	Tue May 28 16:02:27 2002
@@ -635,6 +635,11 @@
 S: NN1 3QT
 S: United Kingdom
 
+N: Stephane Dalton
+E: sdalton@videotron.ca
+D: Tieman Voyager USB Braille display driver.
+S: Québec, Canada
+
 N: Uwe Dannowski
 E: Uwe.Dannowski@ira.uka.de
 W: http://i30www.ira.uka.de/~dannowsk/
@@ -741,6 +746,11 @@
 W: http://www.fsmlabs.com/linuxppcbk.html
 D: PowerPC
 
+N: Stéphane Doyon
+E: s.doyon@videotron.ca
+D: Tieman Voyager USB Braille display driver.
+S: Québec, Canada
+
 N: Oleg Drokin
 E: green@ccssu.crimea.ua
 W: http://www.ccssu.crimea.ua/~green
diff -urN linux-2.4.19-pre8/Documentation/Configure.help linux-2.4.19-pre9/Documentation/Configure.help
--- linux-2.4.19-pre8/Documentation/Configure.help	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/Documentation/Configure.help	Tue May 28 16:02:27 2002
@@ -1106,7 +1106,7 @@
 
   If unsure, say N.
 
-HPT366 chipset support
+HPT366/368/370 chipset support
 CONFIG_BLK_DEV_HPT366
   HPT366 is an Ultra DMA chipset for ATA-66.
   HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
@@ -13296,8 +13296,8 @@
 
 USB Compaq iPAQ Driver
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ or HP Jornada
-  548/568 running Windows CE 3.0 or PocketPC 2002 using a USB
+  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada 548/568
+  or Casio EM500 running Windows CE 3.0 or PocketPC 2002 using a USB
   cradle/cable. For information on using the driver,
   read <file:Documentation/usb/usb-serial.txt>.
 
@@ -13955,6 +13955,17 @@
   The module will be called auerswald.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+Tieman Voyager USB Braille display support
+CONFIG_USB_BRLVOYAGER
+  Say Y here if you want to use the Voyager USB Braille display from
+  Tieman. See <file:Documentation/usb/brlvger.txt> for more
+  information.
+
+  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 brlvger.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 D-Link DSB-R100 FM radio support
 CONFIG_USB_DSBR
   Say Y here if you want to connect this type of radio to your
@@ -19244,15 +19255,17 @@
   Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
   such as the Creative SBLive!, SB PCI512 or Emu-APS.
 
-  For more information on this driver and the degree of support for the
-  different card models please check <http://opensource.creative.com/>.
+  For more information on this driver and the degree of support for
+  the different card models please check:
+
+	<http://sourceforge.net/projects/emu10k1/>
 
   It is now possible to load dsp microcode patches into the EMU10K1
   chip.  These patches are used to implement real time sound
   processing effects which include for example: signal routing,
   bass/treble control, AC3 passthrough, ...
   Userspace tools to create new patches and load/unload them can be
-  found at <http://opensource.creative.com/dist.html>.
+  found in the emu-tools package at the above URL.
 
 Creative SBLive! (EMU10K1) MIDI
 CONFIG_MIDI_EMU10K1
diff -urN linux-2.4.19-pre8/Documentation/IRQ-affinity.txt linux-2.4.19-pre9/Documentation/IRQ-affinity.txt
--- linux-2.4.19-pre8/Documentation/IRQ-affinity.txt	Thu Feb 24 22:41:16 2000
+++ linux-2.4.19-pre9/Documentation/IRQ-affinity.txt	Tue May 28 16:02:27 2002
@@ -8,7 +8,7 @@
 affinity then the value will not change from the default 0xffffffff.
 
 Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting
-the IRQ to CPU4-8 (this is an 8-CPU SMP box):
+the IRQ to CPU4-7 (this is an 8-CPU SMP box):
 
 [root@moon 44]# cat smp_affinity
 ffffffff
diff -urN linux-2.4.19-pre8/Documentation/SubmittingDrivers linux-2.4.19-pre9/Documentation/SubmittingDrivers
--- linux-2.4.19-pre8/Documentation/SubmittingDrivers	Mon Aug 27 08:59:16 2001
+++ linux-2.4.19-pre9/Documentation/SubmittingDrivers	Tue May 28 16:02:27 2002
@@ -3,7 +3,7 @@
 
 This document is intended to explain how to submit device drivers to the
 Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) 
+card drivers you should probably talk to XFree86 (http://www.xfree86.org) 
 instead.
 
 Also read the Documentation/SubmittingPatches document.
diff -urN linux-2.4.19-pre8/Documentation/fb/tridentfb.txt linux-2.4.19-pre9/Documentation/fb/tridentfb.txt
--- linux-2.4.19-pre8/Documentation/fb/tridentfb.txt	Mon Feb 25 11:37:51 2002
+++ linux-2.4.19-pre9/Documentation/fb/tridentfb.txt	Tue May 28 16:02:27 2002
@@ -42,8 +42,14 @@
 bpp  - bits per pixel (8,16 or 32)
 mode - a mode name like 800x600 (as described in Documentation/fb/modedb.txt)
 
+Example:
+video=trident:memsize=2048,800x600
+
 Using insane values for the above parameters will probably result in driver
 misbehaviour so take care(for instance memsize=12345678 or memdiff=23784 or
 nativex=93)
 
-Contact: jani@astechnix.ro
+If you have trouble with the driver you could check http://sf.net/projects/tridentfb
+to see if there's a newer version available.
+
+Contact: jani@iv.ro
diff -urN linux-2.4.19-pre8/Documentation/filesystems/devfs/ChangeLog linux-2.4.19-pre9/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.19-pre8/Documentation/filesystems/devfs/ChangeLog	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/Documentation/filesystems/devfs/ChangeLog	Tue May 28 16:02:27 2002
@@ -1926,3 +1926,13 @@
 
 - Do not put miscellaneous character devices in /dev/misc if they
   specify their own directory (i.e. contain a '/' character)
+===============================================================================
+Changes for patch v199.14
+
+- Copied macro for error messages from fs/devfs/base.c to
+  fs/devfs/util.c and made use of this macro
+
+- Added BKL to <devfs_open> because drivers still need it
+
+- Protected <scan_dir_for_removable> and <get_removable_partition>
+  from changing directory contents
diff -urN linux-2.4.19-pre8/Documentation/kernel-parameters.txt linux-2.4.19-pre9/Documentation/kernel-parameters.txt
--- linux-2.4.19-pre8/Documentation/kernel-parameters.txt	Mon Feb 25 11:37:51 2002
+++ linux-2.4.19-pre9/Documentation/kernel-parameters.txt	Tue May 28 16:02:27 2002
@@ -68,6 +68,8 @@
 	53c7xx=		[HW,SCSI] Amiga SCSI controllers.
 
 	acpi=		[HW,ACPI] Advanced Configuration and Power Interface 
+
+	acpismp=force	[IA-32] Early setup parse and use ACPI SMP table.
  
 	ad1816=		[HW,SOUND]
 
@@ -379,6 +381,8 @@
  
 	no-hlt		[BUGS=ix86]
 
+	noht		[SMP,IA-32] Disables P4 Xeon(tm) HyperThreading.
+
 	noisapnp	[ISAPNP] Disables ISA PnP code.
 
 	noinitrd	[RAM] Tells the kernel not to load any configured
diff -urN linux-2.4.19-pre8/Documentation/networking/skfp.txt linux-2.4.19-pre9/Documentation/networking/skfp.txt
--- linux-2.4.19-pre8/Documentation/networking/skfp.txt	Fri May 12 11:43:26 2000
+++ linux-2.4.19-pre9/Documentation/networking/skfp.txt	Tue May 28 16:02:27 2002
@@ -143,6 +143,10 @@
 (6) HISTORY
 ===========
 
+v2.07 (20020506) (In-Kernel version)
+    Fix: Transmit Descriptor struct
+    Fix: Receive Descriptor struct
+
 v2.06 (20000511) (In-Kernel version)
     New features:
 	- 64 bit support
diff -urN linux-2.4.19-pre8/Documentation/usb/brlvger.txt linux-2.4.19-pre9/Documentation/usb/brlvger.txt
--- linux-2.4.19-pre8/Documentation/usb/brlvger.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre9/Documentation/usb/brlvger.txt	Tue May 28 16:02:27 2002
@@ -0,0 +1,36 @@
+Kernel Driver for the Tieman Voyager Braille Display (USB)
+
+Authors:
+Stéphane Dalton <sdalton@videotron.ca>
+Stéphane Doyon  <s.doyon@videotron.ca>
+
+Version 0.8, April 2002
+
+The brlvger driver supports a Braille display (aka Braille terminal)
+model Voyager from Tieman.
+
+The driver has been in heavy use for about six months now (as of April
+2002) by a very few users (about 3-4), who say it has worked very well
+for them.
+
+We have tested it with a Voyager 44, but it should also support
+the Voyager 70.
+
+This driver implements a character device which allows userspace programs
+access to the braille displays raw functions. You still need a userspace
+program to perform the screen-review functions and control the
+display. Get BRLTTY from http://mielke.cc/brltty/ (version 2.99.8 or
+later). It has a Voyager driver which interfaces with this kernel driver.
+
+The interface is through a character device, major 180, minor 128, called
+"brlvger" under devfs.
+
+Many thanks to the Tieman people: Corand van Strien, Ivar Illing, Daphne
+Vogelaar and Ingrid Vogel. They provided us with a Braille display (as
+well as programming information) so that we could write this driver. They
+replaced the display when it broke and they answered our technical
+questions. It is very motivating when companies take an interest in such
+projects and are so supportive.
+
+Thanks to Andor Demarteau <ademarte@students.cs.uu.nl> who got this whole
+project started and beta-tested all our early buggy attempts.
diff -urN linux-2.4.19-pre8/Documentation/usb/ehci.txt linux-2.4.19-pre9/Documentation/usb/ehci.txt
--- linux-2.4.19-pre8/Documentation/usb/ehci.txt	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/Documentation/usb/ehci.txt	Tue May 28 16:02:27 2002
@@ -1,4 +1,4 @@
-18-Dec-2001
+26-Apr-2002
 
 The EHCI driver is used to talk to high speed USB 2.0 devices using
 USB 2.0-capable host controller hardware.  The USB 2.0 standard is
@@ -19,6 +19,9 @@
 (TT) in the hub, which turns low or full speed transactions into
 high speed "split transactions" that don't waste transfer bandwidth.
 
+At this writing, this driver has been seen to work with implementations
+of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
+
 At this writing, high speed devices are finally beginning to appear.
 While usb-storage devices have been available for some time (working
 quite speedily on the 2.4 version of this driver), hubs have only
@@ -36,7 +39,7 @@
 FUNCTIONALITY
 
 This driver is regularly tested on x86 hardware, and has also been
-used on PPC hardware so big/little endianneess issues should be gone.
+used on PPC hardware so big/little endianness issues should be gone.
 It's believed to do all the right PCI magic so that I/O works even on
 systems with interesting DMA mapping issues.
 
@@ -51,11 +54,13 @@
 connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work.
 Connect them to USB 1.1 hubs, or to a root hub.
 
-Isochronous (ISO) transfer support is not yet working.  No production
+Isochronous (ISO) transfer support is also newly functional.  No production
 high speed devices are available which would need it (though high quality
 webcams are in the works!).  Note that split transaction support for ISO
 transfers can't share much code with the code for high speed ISO transfers,
-since EHCI represents these with a different data structure.
+since EHCI represents these with a different data structure.  So for now,
+most USB audio and video devices have the same restrictions as hubs, mice,
+and keyboards:  don't connect them using high speed USB hubs.
 
 The EHCI root hub code should hand off USB 1.1 devices to its companion
 controller.  This driver doesn't need to know anything about those
@@ -99,6 +104,8 @@
 but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
 High speed devices can do things that full speed (or low speed) ones
 can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
+Also, some values in device descriptors (such as polling intervals for
+periodic transfers) use different encodings when operating at high speed.
 
 
 PERFORMANCE
diff -urN linux-2.4.19-pre8/Documentation/usb/usb-serial.txt linux-2.4.19-pre9/Documentation/usb/usb-serial.txt
--- linux-2.4.19-pre8/Documentation/usb/usb-serial.txt	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/Documentation/usb/usb-serial.txt	Tue May 28 16:02:27 2002
@@ -95,10 +95,10 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ and HP Jornada driver
+Compaq iPAQ, HP Jornada and Casio EM500 driver
 
-  This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs
-  running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
+  This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500
+  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
   has been tested only on the Compaq H3135, but is rumoured to work on
   with the H3600 and later models as well as the Jornada 548 and 568.
   With minor modifications, it may work for other CE based handhelds too.
diff -urN linux-2.4.19-pre8/MAINTAINERS linux-2.4.19-pre9/MAINTAINERS
--- linux-2.4.19-pre8/MAINTAINERS	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/MAINTAINERS	Tue May 28 16:02:27 2002
@@ -673,7 +673,7 @@
 
 i386 BOOT CODE
 P:	Riley H. Williams
-M:	rhw@memalpha.cx
+M:	Riley@Williams.Name
 L:	Linux-Kernel@vger.kernel.org
 S:	Maintained
 
@@ -1530,6 +1530,13 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
+P:	Stephane Dalton
+M:	sdalton@videotron.ca
+P:	Stéphane Doyon
+M:	s.doyon@videotron.ca
+S:	Maintained
+
 TLAN NETWORK DRIVER
 P:	Samuel Chessman
 M:	chessman@tux.org
diff -urN linux-2.4.19-pre8/Makefile linux-2.4.19-pre9/Makefile
--- linux-2.4.19-pre8/Makefile	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/Makefile	Tue May 28 16:02:27 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 19
-EXTRAVERSION = -pre8
+EXTRAVERSION = -pre9
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.19-pre8/arch/alpha/config.in linux-2.4.19-pre9/arch/alpha/config.in
--- linux-2.4.19-pre8/arch/alpha/config.in	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/arch/alpha/config.in	Tue May 28 16:02:27 2002
@@ -278,7 +278,7 @@
 	"ELF		CONFIG_KCORE_ELF	\
 	 A.OUT		CONFIG_KCORE_AOUT" ELF
 fi
-if [ "$CONFIG_PROC_FS" != "n" -a "$CONFIG_ALPHA_SRM" = "y" ]; then
+if [ "$CONFIG_PROC_FS" != "n" ]; then
    tristate 'SRM environment through procfs' CONFIG_SRM_ENV
 fi
  
diff -urN linux-2.4.19-pre8/arch/alpha/kernel/alpha_ksyms.c linux-2.4.19-pre9/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.19-pre8/arch/alpha/kernel/alpha_ksyms.c	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/arch/alpha/kernel/alpha_ksyms.c	Tue May 28 16:02:27 2002
@@ -58,11 +58,12 @@
 EXPORT_SYMBOL(probe_irq_mask);
 EXPORT_SYMBOL(screen_info);
 EXPORT_SYMBOL(perf_irq);
-#ifdef CONFIG_ALPHA_SRM
 EXPORT_SYMBOL(callback_getenv);
 EXPORT_SYMBOL(callback_setenv);
 EXPORT_SYMBOL(callback_save_env);
-#endif /* CONFIG_ALPHA_SRM */
+#ifdef CONFIG_ALPHA_GENERIC
+EXPORT_SYMBOL(alpha_using_srm);
+#endif /* CNFIG_ALPHA_GENERIC */
 
 /* platform dependent support */
 EXPORT_SYMBOL(_inb);
diff -urN linux-2.4.19-pre8/arch/alpha/kernel/srm_env.c linux-2.4.19-pre9/arch/alpha/kernel/srm_env.c
--- linux-2.4.19-pre8/arch/alpha/kernel/srm_env.c	Tue May 28 16:02:14 2002
+++ linux-2.4.19-pre9/arch/alpha/kernel/srm_env.c	Tue May 28 16:02:27 2002
@@ -1,5 +1,5 @@
 /*
- * srm_env.c - Access to SRC environment
+ * srm_env.c - Access to SRM environment
  *             variables through linux' procfs
  *
  * Copyright (C) 2001-2002 Jan-Benedict Glaw <jbglaw@lug-owl.de>
@@ -31,6 +31,11 @@
 
 /*
  * Changelog
+ * ~~~~~~~~~
+ *
+ * Wed, 22 May 2002 00:11:21 +0200
+ * 	- Fix typo on comment (SRC -> SRM)
+ * 	- Call this "Version 0.0.4"
  *
  * Tue,  9 Apr 2002 18:44:40 +0200
  * 	- Implement access by variable name and additionally
@@ -54,7 +59,7 @@
 #define BASE_DIR	"srm_environment"	/* Subdir in /proc/		*/
 #define NAMED_DIR	"named_variables"	/* Subdir for known variables	*/
 #define NUMBERED_DIR	"numbered_variables"	/* Subdir for all variables	*/
-#define VERSION		"0.0.3"			/* Module version		*/
+#define VERSION		"0.0.4"			/* Module version		*/
 #define NAME		"srm_env"		/* Module name			*/
 
 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
diff -urN linux-2.4.19-pre8/arch/cris/drivers/Config.in linux-2.4.19-pre9/arch/cris/drivers/Config.in
--- linux-2.4.19-pre8/arch/cris/drivers/Config.in	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/drivers/Config.in	Tue May 28 16:02:27 2002
@@ -179,7 +179,7 @@
 bool 'ARTPEC-1 support' CONFIG_JULIETTE
 
 if [ "$CONFIG_JULIETTE" = "y" ]; then
-   source arch/cris/drivers/juliette/Config.in
+
 fi
 
 bool 'USB host' CONFIG_ETRAX_USB_HOST
diff -urN linux-2.4.19-pre8/arch/cris/drivers/axisflashmap.c linux-2.4.19-pre9/arch/cris/drivers/axisflashmap.c
--- linux-2.4.19-pre8/arch/cris/drivers/axisflashmap.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/drivers/axisflashmap.c	Tue May 28 16:02:27 2002
@@ -1,7 +1,7 @@
 /*
  * Physical mapping layer for MTD using the Axis partitiontable format
  *
- * Copyright (c) 2001 Axis Communications AB
+ * Copyright (c) 2001, 2002 Axis Communications AB
  *
  * This file is under the GPL.
  *
@@ -11,6 +11,20 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.23  2002/05/13 12:12:28  johana
+ * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
+ * be informative at runtime.
+ *
+ * Revision 1.22  2002/05/13 10:24:44  johana
+ * Added #if checks on MTDRAM CONFIG
+ *
+ * Revision 1.21  2002/05/06 16:05:20  johana
+ * Removed debug printout.
+ *
+ * Revision 1.20  2002/05/06 16:03:00  johana
+ * No more cramfs as root hack in generic code.
+ * It's handled by axisflashmap using mtdram.
+ *
  * Revision 1.19  2002/03/15 17:10:28  bjornw
  * Changed comment about cached access since we changed this before
  *
@@ -87,6 +101,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/mtdram.h>
 
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
@@ -245,6 +260,7 @@
 static int __init
 init_axis_flash(void)
 {
+	int err = 0;
 	int pidx = 0;
 	struct partitiontable_head *ptable_head;
 	struct partitiontable_entry *ptable;
@@ -253,7 +269,6 @@
 
 	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
 	       WINDOW_SIZE, FLASH_CACHED_ADDR);
-
 #ifdef CONFIG_MTD_AMDSTD
 	mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map);
 #endif
@@ -339,8 +354,8 @@
 
 	if (use_default_ptable) {
 		printk(" Using default partition table\n");
-		return add_mtd_partitions(mymtd, axis_default_partitions,
-					  NUM_DEFAULT_PARTITIONS);
+		err = add_mtd_partitions(mymtd, axis_default_partitions,
+		                         NUM_DEFAULT_PARTITIONS);
 	} else {
 		if (romfs_in_flash) {
 			axis_partitions[pidx].name = "romfs";
@@ -354,8 +369,39 @@
 			       axis_partitions[pidx].size);
 			pidx++;
 		}
-		return add_mtd_partitions(mymtd, axis_partitions, pidx);
-	}		
+
+		err = add_mtd_partitions(mymtd, axis_partitions, pidx);
+	}
+	if (!err && !romfs_in_flash) {
+#ifdef CONFIG_MTD_MTDRAM
+		/* Allocate, initialise and forget the mtd ram struct
+		 * when booting from RAM
+		 */
+		struct mtd_info *romfs_mtd = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+		printk("MTD RAM device romfs_start: 0x%08lX len %lu\n",
+		       romfs_start, romfs_length);
+
+#if (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+#error "You must set CONFIG_MTDRAM_TOTAL_SIZE and CONFIG_MTDRAM_ABS_POS to 0"
+#endif
+		err = mtdram_init_device(romfs_mtd, (void*)romfs_start, 
+		                         romfs_length, "romfs in RAM");
+#else
+#warning ######################################
+#warning # You must enable CONFIG_MTD_MTDRAM  #
+#warning # with TOTAL_SIZE 0 and ABS_POS 0 to # 
+#warning # be able to boot with cramfs in RAM #
+#warning ######################################
+/* Maybe overkill to save these bytes in non debug builds, but let's do it..
+ * (No point in printing if we don't have a debug port anyway...)
+ */
+#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
+		printk("## Can't mount romfs in RAM using MTDRAM.\n");
+		printk("## You must enable MTD_MTDRAM with TOTAL_SIZE 0 and ABS_POS 0\n");
+#endif
+#endif /* CONFIG_MTD_MTDRAM */
+	}
+	return err;
 }
 
 /* This adds the above to the kernels init-call chain */
diff -urN linux-2.4.19-pre8/arch/cris/drivers/ethernet.c linux-2.4.19-pre9/arch/cris/drivers/ethernet.c
--- linux-2.4.19-pre8/arch/cris/drivers/ethernet.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/drivers/ethernet.c	Tue May 28 16:02:27 2002
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.28 2002/04/22 11:47:21 johana Exp $
+/* $Id: ethernet.c,v 1.30 2002/05/07 18:50:08 johana Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -6,18 +6,26 @@
  *
  * The outline of this driver comes from skeleton.c.
  *
- * TODO:
- *   - Transmit-buffers should go into a DMA queue instead of treating
- *     them one by one by interrupts
- *   - Received buffers should not be a static buffer, but allocated using
- *     alloc_skb, so we can send the big ones straight up into the net code.
- *     Smaller buffers will be copied to avoid wasting too much memory though.
- *   - Received buffers that should go back into the DMA or newly allocated
- *     receivebuffers should go into a queue, and when the queue gets over a
- *     threshold, the cache is flushed (to counter the Etrax RX dma bug) and
- *     they are added to the live DMA rx list.
- *
  * $Log: ethernet.c,v $
+ * Revision 1.30  2002/05/07 18:50:08  johana
+ * Correct spelling in comments.
+ *
+ * Revision 1.29  2002/05/06 05:38:49  starvik
+ * Performance improvements:
+ *    Large packets are not copied (breakpoint set to 256 bytes)
+ *    The cache bug workaround is delayed until half of the receive list
+ *      has been used
+ *    Added transmit list
+ *    Transmit interrupts are only enabled when transmit queue is full
+ *
+ * Revision 1.28.2.1  2002/04/30 08:15:51  starvik
+ * Performance improvements:
+ *   Large packets are not copied (breakpoint set to 256 bytes)
+ *   The cache bug workaround is delayed until half of the receive list
+ *     has been used.
+ *   Added transmit list
+ *   Transmit interrupts are only enabled when transmit queue is full
+ *
  * Revision 1.28  2002/04/22 11:47:21  johana
  * Fix according to 2.4.19-pre7. time_after/time_before and
  * missing end of comment.
@@ -185,6 +193,11 @@
 	spinlock_t lock;
 };
 
+typedef struct etrax_eth_descr
+{
+	etrax_dma_descr descr;
+	struct sk_buff* skb;
+} etrax_eth_descr;
 
 /* Duplex settings */
 enum duplex
@@ -196,8 +209,6 @@
 
 /* Dma descriptors etc. */
 
-#define RX_BUF_SIZE 32768
-
 #define MAX_MEDIA_DATA_SIZE 1518
 
 #define MIN_PACKET_LEN      46
@@ -238,9 +249,17 @@
 #define NO_NETWORK_ACTIVITY 0
 #define NETWORK_ACTIVITY    1
 
-#define RX_DESC_BUF_SIZE   256
-#define NBR_OF_RX_DESC     (RX_BUF_SIZE / \
-                            RX_DESC_BUF_SIZE)
+#define NBR_OF_RX_DESC     64
+#define NBR_OF_TX_DESC     256
+
+/* Large packets are sent directly to upper layers while small packets are */
+/* copied (to reduce memory waste). The following constant decides the breakpoint */
+#define RX_COPYBREAK 256
+
+/* Due to a chip bug we need to flush the cache when descriptors are returned */
+/* to the DMA. To decrease performance impact we return descriptors in chunks. */
+/* The following constant determines the number of descriptors to return. */
+#define RX_QUEUE_THRESHOLD  NBR_OF_RX_DESC/2
 
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
@@ -250,17 +269,17 @@
 #define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
 					  IO_STATE(##reg##, field, val)
 
-static etrax_dma_descr *myNextRxDesc;  /* Points to the next descriptor to
+static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
-static etrax_dma_descr *myLastRxDesc;  /* The last processed descriptor */
-static etrax_dma_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
+static etrax_eth_descr *myLastRxDesc;  /* The last processed descriptor */
+static etrax_eth_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
 
-static unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned(32)));
+static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
 
-static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
-static etrax_dma_descr TxDesc __attribute__ ((aligned(32)));
-
-static struct sk_buff *tx_skb;
+static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */
+static etrax_eth_descr* myLastTxDesc;  /* End of send queue */
+static etrax_eth_descr* myNextTxDesc;  /* Next descriptor to use */
+static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
 
 static unsigned int network_rec_config_shadow = 0;
 
@@ -271,6 +290,7 @@
 static int current_speed_selection; /* Speed selected by user */
 static int led_next_time;
 static int led_active;
+static int rx_queue_len;
 
 /* Duplex */
 static struct timer_list duplex_timer;
@@ -326,7 +346,6 @@
 etrax_ethernet_init(struct net_device *dev)
 {
 	int i;
-	int anOffset = 0;
 
 	printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n");
 
@@ -379,30 +398,44 @@
 
 	/* Initialise receive descriptors */
 
-	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
-		RxDescList[i].ctrl   = 0;
-		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-		RxDescList[i].next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].buf    = virt_to_phys(RxBuf + anOffset);
-		RxDescList[i].status = 0;
-		RxDescList[i].hw_len = 0;
-		prepare_rx_descriptor(&RxDescList[i]);
-		anOffset += RX_DESC_BUF_SIZE;
-	}
-
-	RxDescList[i].ctrl   = d_eol;
-	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-	RxDescList[i].next   = virt_to_phys(&RxDescList[0]);
-	RxDescList[i].buf    = virt_to_phys(RxBuf + anOffset);
-	RxDescList[i].status = 0;
-	RxDescList[i].hw_len = 0;
-	prepare_rx_descriptor(&RxDescList[i]);
+	for (i = 0; i < NBR_OF_RX_DESC; i++) {
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		RxDescList[i].descr.ctrl   = 0;
+		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
+		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
+		RxDescList[i].descr.buf    = virt_to_phys(RxDescList[i].skb->data);
+		RxDescList[i].descr.status = 0;
+		RxDescList[i].descr.hw_len = 0;
+             
+		prepare_rx_descriptor(&RxDescList[i].descr);
+	}
+
+	RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl   = d_eol;
+	RxDescList[NBR_OF_RX_DESC - 1].descr.next   = virt_to_phys(&RxDescList[0]);
+	rx_queue_len = 0;
+
+	/* Initialize transmit descriptors */
+	for (i = 0; i < NBR_OF_TX_DESC; i++) {
+		TxDescList[i].descr.ctrl   = 0;
+		TxDescList[i].descr.sw_len = 0;
+		TxDescList[i].descr.next   = virt_to_phys(&TxDescList[i + 1].descr);
+		TxDescList[i].descr.buf    = 0;
+		TxDescList[i].descr.status = 0;
+		TxDescList[i].descr.hw_len = 0;
+		TxDescList[i].skb = 0;
+	}
 
+	TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl   = d_eol;
+	TxDescList[NBR_OF_TX_DESC - 1].descr.next   = virt_to_phys(&TxDescList[0].descr);
+        
 	/* Initialise initial pointers */
 
-	myNextRxDesc = &RxDescList[0];
-	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
-	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+	myNextRxDesc  = &RxDescList[0];
+	myLastRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+	myPrevRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+	myFirstTxDesc = &TxDescList[0];
+	myNextTxDesc  = &TxDescList[0];
+	myLastTxDesc  = &TxDescList[NBR_OF_TX_DESC - 1];
 
 	/* Initialize speed indicator stuff. */
 
@@ -563,14 +596,14 @@
 		IO_STATE(R_NETWORK_GEN_CONFIG, phy,    mii_clk) |
 		IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
 
-        *R_NETWORK_TR_CTRL = 
-                IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) |
-                IO_STATE(R_NETWORK_TR_CTRL, delay, none) |
-                IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) |
-                IO_STATE(R_NETWORK_TR_CTRL, cd, enable) |
-                IO_STATE(R_NETWORK_TR_CTRL, retry, enable) |
-                IO_STATE(R_NETWORK_TR_CTRL, pad, enable) |
-                IO_STATE(R_NETWORK_TR_CTRL, crc, enable);
+	*R_NETWORK_TR_CTRL = 
+		IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) |
+		IO_STATE(R_NETWORK_TR_CTRL, delay, none) |
+		IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) |
+		IO_STATE(R_NETWORK_TR_CTRL, cd, enable) |
+		IO_STATE(R_NETWORK_TR_CTRL, retry, enable) |
+		IO_STATE(R_NETWORK_TR_CTRL, pad, enable) |
+		IO_STATE(R_NETWORK_TR_CTRL, crc, enable);
 
 	save_flags(flags);
 	cli();
@@ -578,16 +611,13 @@
 	/* enable the irq's for ethernet DMA */
 
 	*R_IRQ_MASK2_SET =
-		IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+		IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); 
 
 	*R_IRQ_MASK0_SET =
 		IO_STATE(R_IRQ_MASK0_SET, overrun,       set) |
 		IO_STATE(R_IRQ_MASK0_SET, underrun,      set) |
 		IO_STATE(R_IRQ_MASK0_SET, excessive_col, set);
 
-	tx_skb = 0;
-
 	/* make sure the irqs are cleared */
 
 	*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
@@ -603,6 +633,11 @@
 	*R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc);
 	*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
 
+	/* Set up transmit DMA channel so it can be restarted later */
+        
+	*R_DMA_CH0_FIRST = 0;
+	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+
 	restore_flags(flags);
 	
 	/* We are now ready to accept transmit requeusts from
@@ -872,11 +907,18 @@
 	
 	e100_reset_tranceiver();
 	
-	/* and get rid of the packet that never got an interrupt */
-	
-	dev_kfree_skb(tx_skb);
-	tx_skb = 0;
-	
+	/* and get rid of the packets that never got an interrupt */
+	while (myFirstTxDesc != myNextTxDesc)
+	{
+		dev_kfree_skb(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
+
+	/* Set up transmit DMA channel so it can be restarted later */
+	*R_DMA_CH0_FIRST = 0;
+	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);	
+
 	/* tell the upper layers we're ok again */
 	
 	netif_wake_queue(dev);
@@ -901,17 +943,36 @@
 #endif
 	spin_lock_irq(&np->lock);  /* protect from tx_interrupt and ourself */
 
-	tx_skb = skb; /* remember it so we can free it in the tx irq handler later */
+	myNextTxDesc->skb = skb;
+
 	dev->trans_start = jiffies;
 	
 	e100_hardware_send_packet(buf, length);
 
-	/* this simple TX driver has only one send-descriptor so we're full
-	 * directly. If this had a send-ring instead, we would only do this if
-	 * the ring got full.
-	 */
+	myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
 
-	netif_stop_queue(dev);
+	/* Stop queue if full */
+	if (myNextTxDesc == myFirstTxDesc) {
+		/* Enable transmit interrupt to wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);		
+		*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
+		netif_stop_queue(dev);
+	}
+	else {
+	  /* Report any packets that have been sent */
+		while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+		       myFirstTxDesc != myNextTxDesc)
+		{
+			np->stats.tx_bytes += myFirstTxDesc->skb->len;
+			np->stats.tx_packets++;
+
+			/* dma is ready with the transmission of the data in tx_skb, so now
+			   we can release the skb memory */
+			dev_kfree_skb(myFirstTxDesc->skb);
+			myFirstTxDesc->skb = 0;
+			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);				
+		}
+	}
 
 	spin_unlock_irq(&np->lock);
 
@@ -969,25 +1030,28 @@
 	struct net_local *np = (struct net_local *)dev->priv;
 
 	/* check for a dma0_eop interrupt */
-	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { 
-		
-		/* acknowledge the eop interrupt */
-
-		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
+		/* Report all sent packets */
+		do {
+			/* acknowledge the eop interrupt */
+			*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
 
-		if (*R_DMA_CH0_FIRST == 0 && tx_skb) {
-			np->stats.tx_bytes += tx_skb->len;
+			np->stats.tx_bytes += myFirstTxDesc->skb->len;
 			np->stats.tx_packets++;
+
 			/* dma is ready with the transmission of the data in tx_skb, so now
 			   we can release the skb memory */
-			dev_kfree_skb_irq(tx_skb);
-			tx_skb = 0;
-			netif_wake_queue(dev);
-		} else {
-			printk(KERN_WARNING "%s: tx weird interrupt\n",
-			       cardname);
-		}
+			dev_kfree_skb_irq(myFirstTxDesc->skb);
+			myFirstTxDesc->skb = 0;
 
+			if (netif_queue_stopped(dev)) {
+			  	/* Queue is running, disable tx IRQ */
+			  	*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
+				netif_wake_queue(dev);
+			}
+			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+		} while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+		         myFirstTxDesc != myNextTxDesc);
 	}
 }
 
@@ -1016,7 +1080,6 @@
 		np->stats.tx_errors++;
 		D(printk("ethernet excessive collisions!\n"));
 	}
-
 }
 
 /* We have a good packet(s), get it/them out of the buffers. */
@@ -1025,9 +1088,7 @@
 {
 	struct sk_buff *skb;
 	int length = 0;
-	int remain;
 	struct net_local *np = (struct net_local *)dev->priv;
-	struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
 	unsigned char *skb_data_ptr;
 #ifdef ETHDEBUG
 	int i;
@@ -1043,25 +1104,13 @@
 		mod_timer(&clear_led_timer, jiffies + HZ/10);
 	}
 
-	/* If the packet is broken down in many small packages then merge
-	 * count how much space we will need to alloc with skb_alloc() for
-	 * it to fit.
-	 */
-
-	while (!(myNextRxDesc->status & d_eop)) {
-		length += myNextRxDesc->sw_len; /* use sw_len for the first descs */
-		myNextRxDesc->status = 0;
-		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
-	}
-
-	length += myNextRxDesc->hw_len; /* use hw_len for the last descr */
-	length -= 4; /* Exclude last 4 bytes which is the Ethernet checksum. */
+	length = myNextRxDesc->descr.hw_len - 4;
 	((struct net_local *)dev->priv)->stats.rx_bytes += length;
 
 #ifdef ETHDEBUG
 	printk("Got a packet of length %d:\n", length);
 	/* dump the first bytes in the packet */
-	skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf);
+	skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf);
 	for (i = 0; i < 8; i++) {
 		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
 		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
@@ -1070,58 +1119,55 @@
 	}
 #endif
 
-	skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
-	if (!skb) {
-		np->stats.rx_errors++;
-		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
-		       dev->name);
-		return;
-	}
+	if (length < RX_COPYBREAK) {
+		/* Small packet, copy data */
+		skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
+		if (!skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
 
-	skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
-	skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
+		skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
+		skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
 
 #ifdef ETHDEBUG
-	printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
-	       skb->head, skb->data, skb->tail, skb->end);
-	printk("copying packet to 0x%x.\n", skb_data_ptr);
+		printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
+		  skb->head, skb->data, skb->tail, skb->end);
+		printk("copying packet to 0x%x.\n", skb_data_ptr);
 #endif
-
-	/* this loop can be made using max two memcpy's if optimized */
-
-	/* Make sure we don't copy the last 4 bytes which is the checksum. */
-	remain = length;
-	while (mySaveRxDesc != myNextRxDesc) {
-		memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
-		       min((int)mySaveRxDesc->sw_len, remain));
-		skb_data_ptr += mySaveRxDesc->sw_len;
-		prepare_rx_descriptor(mySaveRxDesc);
-		mySaveRxDesc = phys_to_virt(mySaveRxDesc->next);
-		remain -= min((int)mySaveRxDesc->sw_len, remain);
-	}
-
-	memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
-	       min((int)mySaveRxDesc->hw_len, remain));
-	prepare_rx_descriptor(mySaveRxDesc);
+          
+		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
+	}
+	else {
+		/* Large packet, send directly to upper layers and allocate new memory */		 
+		skb = myNextRxDesc->skb;
+		skb_put(skb, length);
+		myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data);
+	}
 
 	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 
 	/* Send the packet to the upper layers */
-
 	netif_rx(skb);
 
 	/* Prepare for next packet */
-
-	myNextRxDesc->status = 0;
+	myNextRxDesc->descr.status = 0;
 	myPrevRxDesc = myNextRxDesc;
-	myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+	myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
 
-	myPrevRxDesc->ctrl |= d_eol;
-	myLastRxDesc->ctrl &= ~d_eol;
-	myLastRxDesc = myPrevRxDesc;
+	rx_queue_len++;
 
-	return;
+	/* Check if descriptors should be returned */
+	if (rx_queue_len == RX_QUEUE_THRESHOLD) {
+		flush_etrax_cache();
+		myPrevRxDesc->descr.ctrl |= d_eol;
+		myLastRxDesc->descr.ctrl &= ~d_eol;
+		myLastRxDesc = myPrevRxDesc;
+		rx_queue_len = 0;
+	}
 }
 
 /* The inverse routine to net_open(). */
@@ -1342,15 +1388,16 @@
 	}
 
 	/* configure the tx dma descriptor */
+	myNextTxDesc->descr.sw_len = length;
+	myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait;
+	myNextTxDesc->descr.buf = virt_to_phys(buf);
+
+        /* Move end of list */
+        myLastTxDesc->descr.ctrl &= ~d_eol;
+        myLastTxDesc = myNextTxDesc;
 
-	TxDesc.sw_len = length;
-	TxDesc.ctrl = d_eop | d_eol | d_wait;
-	TxDesc.buf = virt_to_phys(buf);
-
-	/* setup the dma channel and start it */
-
-	*R_DMA_CH0_FIRST = virt_to_phys(&TxDesc);
-	*R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+	/* Restart DMA channel */
+	*R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart);
 }
 
 static void
diff -urN linux-2.4.19-pre8/arch/cris/drivers/gpio.c linux-2.4.19-pre9/arch/cris/drivers/gpio.c
--- linux-2.4.19-pre8/arch/cris/drivers/gpio.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/drivers/gpio.c	Tue May 28 16:02:27 2002
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.14 2002/04/12 12:01:53 johana Exp $
+/* $Id: gpio.c,v 1.15 2002/05/06 13:19:13 johana Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,9 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.15  2002/05/06 13:19:13  johana
+ * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
+ *
  * Revision 1.14  2002/04/12 12:01:53  johana
  * Use global r_port_g_data_shadow.
  * Moved gpio_init_port_g() closer to gpio_init() and marked it __init.
@@ -395,13 +398,15 @@
 			return dir_g_shadow | dir_g_out_bits;
 		}
 	case IO_SETINPUT:
-		/* Set direction 0=unchanged 1=input */
+		/* Set direction 0=unchanged 1=input, 
+		 * return mask with 1=input 
+		 */
 		if (USE_PORTS(priv)) {
 			save_flags(flags); cli();
 			*priv->dir = *priv->dir_shadow &= 
 			~((unsigned char)arg & priv->changeable_dir);
 			restore_flags(flags);
-			return *priv->dir_shadow;
+			return ~(*priv->dir_shadow);
 		} else if (priv->minor == GPIO_MINOR_G) {
 			/* We must fiddle with R_GEN_CONFIG to change dir */
 			if (((arg & dir_g_in_bits) != arg) && 
@@ -443,7 +448,9 @@
 		return 0;
 
 	case IO_SETOUTPUT:
-		/* Set direction 0=unchanged 1=output, returns */
+		/* Set direction 0=unchanged 1=output, 
+		 * return mask with 1=output 
+		 */
 		if (USE_PORTS(priv)) {
 			save_flags(flags); cli();
 			*priv->dir = *priv->dir_shadow |= 
diff -urN linux-2.4.19-pre8/arch/cris/drivers/parport.c linux-2.4.19-pre9/arch/cris/drivers/parport.c
--- linux-2.4.19-pre8/arch/cris/drivers/parport.c	Mon Oct  8 11:43:54 2001
+++ linux-2.4.19-pre9/arch/cris/drivers/parport.c	Tue May 28 16:02:27 2002
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.8 2001/09/26 11:51:52 bjornw Exp $
+/* $Id: parport.c,v 1.9 2002/05/15 12:30:24 starvik Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -204,7 +204,7 @@
 	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd,
 	     (control & PARPORT_CONTROL_AUTOFD) > 0);
 	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init,
-	     (control & PARPORT_CONTROL_INIT) > 0);
+	     (control & PARPORT_CONTROL_INIT) == 0);
 	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli,
 	     (control & PARPORT_CONTROL_SELECT) > 0);
 
@@ -223,7 +223,7 @@
 		ret |= PARPORT_CONTROL_STROBE;
 	if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow))
 		ret |= PARPORT_CONTROL_AUTOFD;
-	if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow))
+	if (!IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow))
 		ret |= PARPORT_CONTROL_INIT;
 	if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow))
 		ret |= PARPORT_CONTROL_SELECT;
@@ -258,7 +258,7 @@
 		ret |= PARPORT_STATUS_ERROR;
 	if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data))
 		ret |= PARPORT_STATUS_SELECT;
-	if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data))
+	if (IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data))
 		ret |= PARPORT_STATUS_PAPEROUT;
 	if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data))
 		ret |= PARPORT_STATUS_ACK;
diff -urN linux-2.4.19-pre8/arch/cris/drivers/serial.c linux-2.4.19-pre9/arch/cris/drivers/serial.c
--- linux-2.4.19-pre8/arch/cris/drivers/serial.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/drivers/serial.c	Tue May 28 16:02:27 2002
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.31 2002/04/22 11:20:03 johana Exp $
+/* $Id: serial.c,v 1.32 2002/05/22 13:58:00 johana Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,12 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.32  2002/05/22 13:58:00  johana
+ * Renamed rs_write() to raw_write() and made it inline.
+ * New rs_write() handles RS-485 if configured and enabled
+ * (moved code from e100_write_rs485()).
+ * RS-485 ioctl's uses copy_from_user() instead of verify_area().
+ *
  * Revision 1.31  2002/04/22 11:20:03  johana
  * Updated copyright years.
  *
@@ -297,7 +303,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.31 $";
+static char *serial_version = "$Revision: 1.32 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -328,7 +334,7 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
-#include <asm/delay.h>
+#include <linux/delay.h>
 
 #include <asm/svinto.h>
 
@@ -396,6 +402,10 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
                     const unsigned char *buf, int count);
+static inline int raw_write(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
+static int e100_write_rs485(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
 static int 
 get_lsr_info(struct e100_serial * info, unsigned int *value);
 
@@ -836,12 +846,12 @@
 e100_rts(struct e100_serial *info, int set)
 {
 #ifndef CONFIG_SVINTO_SIM
-#ifdef SERIAL_DEBUG_IO  
-	printk("ser%i rts %i\n", info->line, set);
-#endif
 	info->rx_ctrl &= ~E100_RTS_MASK;
 	info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
+#ifdef SERIAL_DEBUG_IO  
+	printk("ser%i rts %i\n", info->line, set);
+#endif
 #endif
 }
 
@@ -994,61 +1004,32 @@
 	info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
 	info->rs485.delay_rts_before_send = r->delay_rts_before_send;
 	info->rs485.enabled = r->enabled;
-	
+/*	printk("rts: on send = %i, after = %i, enabled = %i",
+		    info->rs485.rts_on_send,
+		    info->rs485.rts_after_sent,
+		    info->rs485.enabled
+	);
+*/		
 	return 0;
 }
 
 static int
-e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
+e100_write_rs485(struct tty_struct *tty, int from_user, 
+                 const unsigned char *buf, int count)
 {
-	int total;
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+	int old_enabled = info->rs485.enabled;
 
-	/* If we are in RS-485 mode, we need to toggle RTS and disable
-	 * the receiver before initiating a DMA transfer
-	 */
-	e100_rts(info, info->rs485.rts_on_send);
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-	e100_disable_rx(info);
-	e100_disable_rxdma_irq(info);
-#endif
-
-	if (info->rs485.delay_rts_before_send > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
-	}
-	total = rs_write(tty, 1, (*r).outc, (*r).outc_size);
-
-	/* If we are in RS-485 mode the following things has to be done:
-	 * wait until DMA is ready
-	 * wait on transmit shift register
-	 * wait to toggle RTS
-	 * enable the receiver
-	 */	
-
-	/* Sleep until all sent */
-	tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
-	/* Now sleep a little more so that shift register is empty */
-	schedule_usleep(info->char_time_usec * 2);
-#else
-	{
-		unsigned int val;
-		/* wait on transmit shift register */
-		do{
-			get_lsr_info(info, &val);
-		}while (!(val & TIOCSER_TEMT));
-	}
-#endif
-
-	e100_rts(info, info->rs485.rts_after_sent);
-	
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-	e100_enable_rx(info);
-	e100_enable_rxdma_irq(info);
-#endif
-
-	return total;
+	/* rs485 is always implicitly enabled if we're using the ioctl() 
+	 * but it doesn't have to be set in the rs485_control
+	 * (to be backward compatible with old apps)
+	 * So we store, set and restore it.
+	 */
+	info->rs485.enabled = 1;
+	/* rs_write now deals with RS485 if enabled */
+	count = rs_write(tty, from_user, buf, count);
+	info->rs485.enabled = old_enabled;
+	return count;
 }
 #endif
 
@@ -1193,26 +1174,6 @@
 		/* our job here is done, don't schedule any new DMA transfer */
 		info->tr_running = 0;
 
-#if defined(CONFIG_ETRAX_RS485)
-		/* Check if we should toggle RTS now */
-		if (info->rs485.enabled) {
-			/* Make sure fifo is empty */
-			int in_fifo = 0;
-
-			do {
-				in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail,
-						     *info->ostatusadr);
-			}  while (in_fifo > 0);
-			/* Any way to really check transmitter empty? (TEMT) */
-			/* Control RTS to set to RX mode */
-			e100_rts(info, info->rs485.rts_after_sent); 
-#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
-			e100_enable_rx(info);
-			e100_enable_rxdma_irq(info);
-#endif
-		}
-#endif /* RS485 */
-
 		return;
 	}
 
@@ -2359,8 +2320,8 @@
 	restore_flags(flags);
 }
 
-static int 
-rs_write(struct tty_struct * tty, int from_user,
+static inline int 
+raw_write(struct tty_struct * tty, int from_user,
 	 const unsigned char *buf, int count)
 {
 	int	c, ret = 0;
@@ -2374,7 +2335,7 @@
 	
 #ifdef SERIAL_DEBUG_DATA
 	if (info->line == SERIAL_DEBUG_LINE)
-		printk("rs_write (%d), status %d\n", 
+		printk("raw_write (%d), status %d\n", 
 		       count, info->port[REG_STATUS]);
 #endif
 
@@ -2460,8 +2421,70 @@
 	}
  	
 	return ret;
+} /* raw_write() */
+
+static int 
+rs_write(struct tty_struct * tty, int from_user,
+	 const unsigned char *buf, int count)
+{
+#if defined(CONFIG_ETRAX_RS485)
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+	if (info->rs485.enabled)
+	{
+		/* If we are in RS-485 mode, we need to toggle RTS and disable
+		 * the receiver before initiating a DMA transfer
+		 */
+		e100_rts(info, info->rs485.rts_on_send);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+		e100_disable_rx(info);
+		e100_disable_rxdma_irq(info);
+#endif
+
+		if (info->rs485.delay_rts_before_send > 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
+		}
+	}
+#endif /* CONFIG_ETRAX_RS485 */
+
+	count = raw_write(tty, from_user, buf, count);
+
+#if defined(CONFIG_ETRAX_RS485)
+	if (info->rs485.enabled)
+	{
+		unsigned int val;
+		/* If we are in RS-485 mode the following has to be done:
+		 * wait until DMA is ready
+		 * wait on transmit shift register
+		 * toggle RTS
+		 * enable the receiver
+		 */	
+
+		/* Sleep until all sent */
+		tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+		/* Now sleep a little more so that shift register is empty */
+		schedule_usleep(info->char_time_usec * 2);
+#endif
+		/* wait on transmit shift register */
+		do{
+			get_lsr_info(info, &val);
+		}while (!(val & TIOCSER_TEMT));
+
+		e100_rts(info, info->rs485.rts_after_sent);
+	
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+		e100_enable_rx(info);
+		e100_enable_rxdma_irq(info);
+#endif
+	}
+#endif /* CONFIG_ETRAX_RS485 */
+
+	return count;
 }
 
+
 /* how much space is available in the xmit buffer? */
 
 static int 
@@ -2889,7 +2912,7 @@
 	 unsigned int cmd, unsigned long arg)
 {
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
-#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 	int error;
 #endif
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
@@ -2966,22 +2989,22 @@
 
 #if defined(CONFIG_ETRAX_RS485)
 		case TIOCSERSETRS485:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-					sizeof(struct rs485_control));
-			
-			if (error)
-				return error;
-			
-			return e100_enable_rs485(tty, (struct rs485_control *) arg);
+		{
+			struct rs485_control rs485ctrl;
+			if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl)))
+				return -EFAULT;
+
+			return e100_enable_rs485(tty, &rs485ctrl);
+		}
 
 		case TIOCSERWRRS485:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-					sizeof(struct rs485_write));
-			
-			if (error)
-				return error;
-			
-			return e100_write_rs485(tty, (struct rs485_write *) arg);
+		{
+			struct rs485_write rs485wr;
+			if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
+				return -EFAULT;
+
+			return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
+		}
 #endif
 			
 		default:
@@ -3525,8 +3548,8 @@
 static void 
 show_serial_version(void)
 {
-	printk("ETRAX 100LX serial-driver %s, (c) 2000, 2001, 2002 Axis Communications AB\r\n",
-	       serial_version);
+	printk("ETRAX 100LX serial-driver %s, (c) 2000-2002 Axis Communications AB\r\n",
+	       &serial_version[11]); /* "$Revision: x.yy" */
 }
 
 /* rs_init inits the driver at boot (using the module_init chain) */
diff -urN linux-2.4.19-pre8/arch/cris/mm/fault.c linux-2.4.19-pre9/arch/cris/mm/fault.c
--- linux-2.4.19-pre8/arch/cris/mm/fault.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre9/arch/cris/mm/fault.c	Tue May 28 16:02:27 2002
@@ -437,7 +437,7 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	info.si_code = SIGBUS;
+	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRERR;
 	info.si_addr = (void *)address;
diff -urN linux-2.4.19-pre8/arch/cris/mm/init.c linux-2.4.19-pre9/arch/cris/mm/init.c
--- linux-2.4.19-pre8/arch/cris/mm/init.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/cris/mm/init.c	Tue May 28 16:02:27 2002
@@ -7,6 +7,9 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.35  2002/05/17 05:33:59  starvik
+ *  Limit cache flush range to the size of the cache
+ *
  *  Revision 1.34  2002/04/22 11:48:51  johana
  *  Added KERN_INFO (2.4.19-pre7)
  *
@@ -475,6 +478,8 @@
 	volatile short *flushadr = (volatile short *)(((unsigned long)startadr & ~PAGE_MASK) |
 						      CACHED_BOOTROM);
 
+	length = length > 8192 ? 8192 : length;  /* No need to flush more than cache size */
+
 	while(length > 0) {
 		short tmp = *flushadr;           /* dummy read to flush */
 		flushadr += (32/sizeof(short));  /* a cacheline is 32 bytes */
diff -urN linux-2.4.19-pre8/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre9/arch/i386/kernel/dmi_scan.c
--- linux-2.4.19-pre8/arch/i386/kernel/dmi_scan.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/i386/kernel/dmi_scan.c	Tue May 28 16:02:27 2002
@@ -418,7 +418,7 @@
 	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
 	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
 	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
-#ifdef CONFIG_X86_UP_APIC
+#ifdef CONFIG_X86_IO_APIC
 	skip_ioapic_setup = 0;
 #endif
 	return 0;
diff -urN linux-2.4.19-pre8/arch/i386/kernel/io_apic.c linux-2.4.19-pre9/arch/i386/kernel/io_apic.c
--- linux-2.4.19-pre8/arch/i386/kernel/io_apic.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/i386/kernel/io_apic.c	Tue May 28 16:02:27 2002
@@ -191,11 +191,7 @@
 #define MAX_PIRQS 8
 int pirq_entries [MAX_PIRQS];
 int pirqs_enabled;
-#ifdef CONFIG_X86_UP_APIC
-int skip_ioapic_setup=1;
-#else
-int skip_ioapic_setup=0;
-#endif
+int skip_ioapic_setup;
 
 static int __init noioapic_setup(char *str)
 {
@@ -654,7 +650,14 @@
 		}
 
 		irq = pin_2_irq(idx, apic, pin);
-		add_pin_to_irq(irq, apic, pin);
+		/*
+		 * skip adding the timer int on secondary nodes, which causes
+		 * a small but painful rift in the time-space continuum
+		 */
+		if (clustered_apic_mode && (apic != 0) && (irq == 0))
+			continue;
+		else
+			add_pin_to_irq(irq, apic, pin);
 
 		if (!apic && !IO_APIC_IRQ(irq))
 			continue;
diff -urN linux-2.4.19-pre8/arch/i386/kernel/setup.c linux-2.4.19-pre9/arch/i386/kernel/setup.c
--- linux-2.4.19-pre8/arch/i386/kernel/setup.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/i386/kernel/setup.c	Tue May 28 16:02:27 2002
@@ -166,6 +166,7 @@
 
 static int disable_x86_serial_nr __initdata = 1;
 static int disable_x86_fxsr __initdata = 0;
+static int disable_x86_ht __initdata = 0;
 
 int enable_acpi_smp_table;
 
@@ -416,14 +417,14 @@
 
 static void __init limit_regions (unsigned long long size)
 {
+	unsigned long long current_addr = 0;
 	int i;
-	unsigned long long current_size = 0;
 
 	for (i = 0; i < e820.nr_map; i++) {
 		if (e820.map[i].type == E820_RAM) {
-			current_size += e820.map[i].size;
-			if (current_size >= size) {
-				e820.map[i].size -= current_size-size;
+			current_addr = e820.map[i].addr + e820.map[i].size;
+			if (current_addr >= size) {
+				e820.map[i].size -= current_addr-size;
 				e820.nr_map = i + 1;
 				return;
 			}
@@ -727,7 +728,7 @@
 } /* setup_memory_region */
 
 
-static void __init parse_mem_cmdline (char ** cmdline_p)
+static void __init parse_cmdline_early (char ** cmdline_p)
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
@@ -738,6 +739,8 @@
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
 	for (;;) {
+		if (c != ' ')
+			goto nextchar;
 		/*
 		 * "mem=nopentium" disables the 4MB page tables.
 		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
@@ -745,7 +748,7 @@
 		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
 		 * <start> to <start>+<mem>, overriding the bios size.
 		 */
-		if (c == ' ' && !memcmp(from, "mem=", 4)) {
+		if (!memcmp(from, "mem=", 4)) {
 			if (to != command_line)
 				to--;
 			if (!memcmp(from+4, "nopentium", 9)) {
@@ -774,17 +777,23 @@
 				}
 			}
 		}
-		/* acpismp=force forces parsing and use of the ACPI SMP table */
-		if (c == ' ' && !memcmp(from, "acpismp=force", 13))
-			 enable_acpi_smp_table = 1;
+
+		/* "noht" disables HyperThreading (2 logical cpus per Xeon) */
+		else if (!memcmp(from, "noht", 4))
+			disable_x86_ht = 1;
+
+		/* "acpismp=force" forces parsing and use of the ACPI SMP table */
+		else if (!memcmp(from, "acpismp=force", 13))
+			enable_acpi_smp_table = 1;
+
 		/*
 		 * highmem=size forces highmem to be exactly 'size' bytes.
 		 * This works even on boxes that have no highmem otherwise.
 		 * This also works to reduce highmem size on bigger boxes.
 		 */
-		if (c == ' ' && !memcmp(from, "highmem=", 8))
+		else if (!memcmp(from, "highmem=", 8))
 			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
-	
+nextchar:
 		c = *(from++);
 		if (!c)
 			break;
@@ -841,7 +850,7 @@
 	data_resource.start = virt_to_bus(&_etext);
 	data_resource.end = virt_to_bus(&_edata)-1;
 
-	parse_mem_cmdline(cmdline_p);
+	parse_cmdline_early(cmdline_p);
 
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
@@ -1025,6 +1034,17 @@
 	}
 #endif
 
+	/*
+	 * If enable_acpi_smp_table and HT feature present, acpitable.c
+	 * will find all logical cpus despite disable_x86_ht: so if both
+	 * "noht" and "acpismp=force" are specified, let "noht" override
+	 * "acpismp=force" cleanly.  Why retain "acpismp=force"? because
+	 * parsing ACPI SMP table might prove useful on some non-HT cpu.
+	 */
+	if (disable_x86_ht) {
+		clear_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]);
+		enable_acpi_smp_table = 0;
+	}
 	if (test_bit(X86_FEATURE_HT, &boot_cpu_data.x86_capability[0]))
 		enable_acpi_smp_table = 1;
 	
@@ -2267,7 +2287,7 @@
 		strcpy(c->x86_model_id, p);
 	
 #ifdef CONFIG_SMP
-	if (test_bit(X86_FEATURE_HT, &c->x86_capability)) {
+	if (test_bit(X86_FEATURE_HT, &c->x86_capability) && !disable_x86_ht) {
 		extern	int phys_proc_id[NR_CPUS];
 		
 		u32 	eax, ebx, ecx, edx;
@@ -2718,6 +2738,10 @@
 		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
 #endif
 
+	/* HT disabled? */
+	if (disable_x86_ht)
+		clear_bit(X86_FEATURE_HT, &c->x86_capability);
+
 	/* FXSR disabled? */
 	if (disable_x86_fxsr) {
 		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
diff -urN linux-2.4.19-pre8/arch/mips/kernel/signal.c linux-2.4.19-pre9/arch/mips/kernel/signal.c
--- linux-2.4.19-pre8/arch/mips/kernel/signal.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/mips/kernel/signal.c	Tue May 28 16:02:28 2002
@@ -13,6 +13,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/kernel.h>
+#include <linux/personality.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
@@ -21,6 +22,7 @@
 
 #include <asm/asm.h>
 #include <asm/bitops.h>
+#include <asm/cpu.h>
 #include <asm/pgalloc.h>
 #include <asm/stackframe.h>
 #include <asm/uaccess.h>
@@ -76,8 +78,7 @@
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 save_static_function(sys_sigsuspend);
-static_unused int
-_sys_sigsuspend(struct pt_regs regs)
+static_unused int _sys_sigsuspend(struct pt_regs regs)
 {
 	sigset_t *uset, saveset, newset;
 
@@ -102,10 +103,8 @@
 	}
 }
 
-
 save_static_function(sys_rt_sigsuspend);
-static_unused int
-_sys_rt_sigsuspend(struct pt_regs regs)
+static_unused int _sys_rt_sigsuspend(struct pt_regs regs)
 {
 	sigset_t *unewset, saveset, newset;
         size_t sigsetsize;
@@ -136,8 +135,8 @@
 	}
 }
 
-asmlinkage int 
-sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+asmlinkage int sys_sigaction(int sig, const struct sigaction *act,
+	struct sigaction *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
@@ -177,8 +176,7 @@
 	return ret;
 }
 
-asmlinkage int
-sys_sigaltstack(struct pt_regs regs)
+asmlinkage int sys_sigaltstack(struct pt_regs regs)
 {
 	const stack_t *uss = (const stack_t *) regs.regs[4];
 	stack_t *uoss = (stack_t *) regs.regs[5];
@@ -187,8 +185,57 @@
 	return do_sigaltstack(uss, uoss, usp);
 }
 
-asmlinkage int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+static inline int restore_thread_fp_context(struct sigcontext *sc)
+{
+	u64 *pfreg = &current->thread.fpu.soft.regs[0];
+	int err = 0;
+
+	/* 
+	 * Copy all 32 64-bit values, for two reasons.  First, the R3000 and
+	 * R4000/MIPS32 kernels use the thread FP register storage differently,
+	 * such that a full copy is essentially necessary to support both.
+	 */
+
+#define restore_fpr(i) 						\
+	do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+	restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3);
+	restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7);
+	restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11);
+	restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15);
+	restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19);
+	restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23);
+	restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27);
+	restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31);
+
+	err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+	return err;
+}
+
+static inline int save_thread_fp_context(struct sigcontext *sc)
+{
+	u64 *pfreg = &current->thread.fpu.soft.regs[0];
+	int err = 0;
+
+#define save_fpr(i) 							\
+	do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0)
+
+	save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3);
+	save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7);
+	save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11);
+	save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15);
+	save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19);
+	save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23);
+	save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27);
+	save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31);
+
+	err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+
+	return err;
+}
+
+static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 {
 	int owned_fp;
 	int err = 0;
@@ -219,11 +266,24 @@
 #undef restore_gp_reg
 
 	err |= __get_user(owned_fp, &sc->sc_ownedfp);
+	err |= __get_user(current->used_math, &sc->sc_used_math);
+
 	if (owned_fp) {
 		err |= restore_fp_context(sc);
-		last_task_used_math = current;
+		goto out;
+	}
+
+	if (current == last_task_used_math) {
+		/* Signal handler acquired FPU - give it back */
+		last_task_used_math = NULL;
+		regs->cp0_status &= ~ST0_CU1;
+	}
+	if (current->used_math) {
+		/* Undo possible contamination of thread state */
+		err |= restore_thread_fp_context(sc);
 	}
 
+out:
 	return err;
 }
 
@@ -241,8 +301,7 @@
 	struct ucontext rs_uc;
 };
 
-asmlinkage void
-sys_sigreturn(struct pt_regs regs)
+asmlinkage void sys_sigreturn(struct pt_regs regs)
 {
 	struct sigframe *frame;
 	sigset_t blocked;
@@ -278,8 +337,7 @@
 	force_sig(SIGSEGV, current);
 }
 
-asmlinkage void
-sys_rt_sigreturn(struct pt_regs regs)
+asmlinkage void sys_rt_sigreturn(struct pt_regs regs)
 {
 	struct rt_sigframe *frame;
 	sigset_t set;
@@ -320,21 +378,21 @@
 	force_sig(SIGSEGV, current);
 }
 
-static int inline
-setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+static int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 {
 	int owned_fp;
 	int err = 0;
 	u64 reg;
 
-	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+	reg = regs->cp0_epc; err |= __put_user(reg, &sc->sc_pc);
 	err |= __put_user(regs->cp0_status, &sc->sc_status);
 
 #define save_gp_reg(i) {						\
 	reg = regs->regs[i];						\
 	err |= __put_user(reg, &sc->sc_regs[i]);			\
 } while(0)
-	__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
+	reg = 0; err |= __put_user(reg, &sc->sc_regs[0]);
+	save_gp_reg(1); save_gp_reg(2);
 	save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
 	save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
 	save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
@@ -345,36 +403,53 @@
 	save_gp_reg(31);
 #undef save_gp_reg
 
-	err |= __put_user(regs->hi, &sc->sc_mdhi);
-	err |= __put_user(regs->lo, &sc->sc_mdlo);
+	reg = regs->hi; err |= __put_user(reg, &sc->sc_mdhi);
+	reg = regs->lo; err |= __put_user(reg, &sc->sc_mdlo);
 	err |= __put_user(regs->cp0_cause, &sc->sc_cause);
 	err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
 
 	owned_fp = (current == last_task_used_math);
 	err |= __put_user(owned_fp, &sc->sc_ownedfp);
+	err |= __put_user(current->used_math, &sc->sc_used_math);
 
-	if (current->used_math) {	/* fp is active.  */
-		set_cp0_status(ST0_CU1);
+	if (!current->used_math)
+		goto out;
+
+	/* There exists FP thread state that may be trashed by signal */
+	if (owned_fp) {	
+		/* fp is active.  Save context from FPU */
 		err |= save_fp_context(sc);
-		last_task_used_math = NULL;
-		regs->cp0_status &= ~ST0_CU1;
-		current->used_math = 0;
+		goto out;
 	}
 
+	/* 
+	 * Someone else has FPU. 
+	 * Copy Thread context into signal context 
+	 */
+	err |= save_thread_fp_context(sc);
+
+out:
 	return err;
 }
 
 /*
  * Determine which stack to use..
  */
-static inline void *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+static inline void * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+	size_t frame_size)
 {
 	unsigned long sp;
 
 	/* Default to using normal stack */
 	sp = regs->regs[29];
 
+	/* 
+ 	 * FPU emulator may have it's own trampoline active just
+ 	 * above the user stack, 16-bytes before the next lowest
+ 	 * 16 byte boundary.  Try to avoid trashing it.
+ 	 */
+ 	sp -= 32;
+
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
                 sp = current->sas_ss_sp + current->sas_ss_size;
@@ -382,9 +457,8 @@
 	return (void *)((sp - frame_size) & ALMASK);
 }
 
-static void inline
-setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
-            int signr, sigset_t *set)
+static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+	int signr, sigset_t *set)
 {
 	struct sigframe *frame;
 	int err = 0;
@@ -445,9 +519,8 @@
 	force_sig(SIGSEGV, current);
 }
 
-static void inline
-setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
-               int signr, sigset_t *set, siginfo_t *info)
+static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+	int signr, sigset_t *set, siginfo_t *info)
 {
 	struct rt_sigframe *frame;
 	int err = 0;
@@ -521,8 +594,7 @@
 	force_sig(SIGSEGV, current);
 }
 
-static inline void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
+static inline void handle_signal(unsigned long sig, struct k_sigaction *ka,
 	siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	if (ka->sa.sa_flags & SA_SIGINFO)
@@ -541,8 +613,7 @@
 	}
 }
 
-static inline void
-syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
 {
 	switch(regs->regs[0]) {
 	case ERESTARTNOHAND:
@@ -661,7 +732,10 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
 				/* NOTREACHED */
 			}
 		}
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/Makefile linux-2.4.19-pre9/arch/ppc/kernel/Makefile
--- linux-2.4.19-pre8/arch/ppc/kernel/Makefile	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/Makefile	Tue May 28 16:02:28 2002
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.40 04/09/02 21:01:57 paulus
+# BK Id: SCCS/s.Makefile 1.41 04/16/02 20:08:22 paulus
 #
 #
 # Makefile for the linux kernel.
@@ -15,6 +15,9 @@
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
 
+# Extra CFLAGS so we don't have to do relative includes
+CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/arch/$(ARCH)/mm -I$(TOPDIR)/drivers/scsi
+
 # Code in these files is used before the kernel is moved to its final position
 CFLAGS_prom_init.o	+= -mrelocatable-lib
 CFLAGS_btext.o		+= -mrelocatable-lib
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/cputable.c linux-2.4.19-pre9/arch/ppc/kernel/cputable.c
--- linux-2.4.19-pre8/arch/ppc/kernel/cputable.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/cputable.c	Tue May 28 16:02:28 2002
@@ -28,6 +28,8 @@
 extern void __setup_cpu_7400(int cpu_nr);
 extern void __setup_cpu_7410(int cpu_nr);
 extern void __setup_cpu_7450(int cpu_nr);
+extern void __setup_cpu_7450_23(int cpu_nr);
+extern void __setup_cpu_7455(int cpu_nr);
 extern void __setup_cpu_power3(int cpu_nr);
 extern void __setup_cpu_power4(int cpu_nr);
 extern void __setup_cpu_8xx(int cpu_nr);
@@ -185,8 +187,8 @@
 	32, 32,
 	__setup_cpu_7450
     },
-    {	/* 7450 others */
-    	0xffff0000, 0x80000000, "7450",
+    {	/* 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_HPTE_TABLE | CPU_FTR_SPEC7450,
@@ -194,6 +196,15 @@
 	32, 32,
 	__setup_cpu_7450
     },
+    {	/* 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_HPTE_TABLE | CPU_FTR_SPEC7450,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7450_23
+    },
     {	/* 7455 */
     	0xffff0000, 0x80010000, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
@@ -201,7 +212,7 @@
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
-	__setup_cpu_7450
+	__setup_cpu_7455
     },
     {	/* 82xx (8240, 8245, 8260 are all 603e cores) */
 	0x7fff0000, 0x00810000, "82xx",
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/head.S linux-2.4.19-pre9/arch/ppc/kernel/head.S
--- linux-2.4.19-pre8/arch/ppc/kernel/head.S	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/head.S	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.37 04/09/02 21:43:09 paulus
+ * BK Id: SCCS/s.head.S 1.39 05/06/02 01:37:30 benh
  */
 /*
  *  PowerPC version 
@@ -1373,6 +1373,18 @@
 	bl	setup_7450_hid0
 	mtlr	r4
 	blr
+_GLOBAL(__setup_cpu_7450_23)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_7450_23_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7455)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_7455_hid0
+	mtlr	r4
+	blr
 _GLOBAL(__setup_cpu_power3)
 	blr
 _GLOBAL(__setup_cpu_power4)
@@ -1442,21 +1454,53 @@
  */
 setup_7450_hid0:
 	/* We check for the presence of an L3 cache setup by
-	 * the firmware. If any, we disable DOZE capability
+	 * the firmware. If any, we disable NAP capability as
+	 * it's known to be bogus on rev 2.1 and earlier
 	 */
 	mfspr	r11,SPRN_L3CR
 	andis.	r11,r11,L3CR_L3E@h
 	beq	1f
-	li	r7,CPU_FTR_CAN_DOZE
+	li	r7,CPU_FTR_CAN_NAP
 	lwz	r6,CPU_SPEC_FEATURES(r5)
 	andc	r6,r6,r7
 	stw	r6,CPU_SPEC_FEATURES(r5)
 1:	
+setup_7450_23_hid0:
+	mfspr	r11,HID0
+
+	/* All of the bits we have to set.....
+	*/
+	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
+	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+
+	/* All of the bits we have to clear....
+	*/
+	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
+	andc	r11,r11,r3		/* clear SPD: enable speculative */
+ 	li	r3,0
+
+ 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+	isync
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 7450
+ * Enable Store Gathering (SGE), Branch Folding (FOLD)
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Ensure our data cache instructions really operate.
+ * Timebase has to be running or we wouldn't have made it here,
+ * just ensure we don't disable it.
+ * Clear Instruction cache throttling (ICTC)
+ */
+setup_7455_hid0:
 	mfspr	r11,HID0
 
 	/* All of the bits we have to set.....
 	*/
-	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC
+	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
 	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
 
 	/* All of the bits we have to clear....
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/pci.c linux-2.4.19-pre9/arch/ppc/kernel/pci.c
--- linux-2.4.19-pre8/arch/ppc/kernel/pci.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/pci.c	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pci.c 1.40 01/25/02 15:15:24 benh
+ * BK Id: SCCS/s.pci.c 1.43 05/08/02 15:01:15 benh
  */
 /*
  * Common pmac/prep/chrp pci routines. -- Cort
@@ -46,6 +46,7 @@
 static void pcibios_fixup_resources(struct pci_dev* dev);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static void fixup_rev1_53c810(struct pci_dev* dev);
+static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_ALL_PPC
 static void pcibios_fixup_cardbus(struct pci_dev* dev);
 static u8* pci_to_OF_bus_map;
@@ -64,6 +65,7 @@
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,	PCI_ANY_ID,			fixup_broken_pcnet32 },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	fixup_rev1_53c810 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CPC710_PCI64,	fixup_cpc710_pci64},
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pcibios_fixup_resources },
 #ifdef CONFIG_ALL_PPC
 	/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
@@ -95,6 +97,18 @@
 	}
 }
 
+static void
+fixup_cpc710_pci64(struct pci_dev* dev)
+{
+	/* Hide the PCI64 BARs from the kernel as their content doesn't
+	 * fit well in the resource management
+	 */
+	dev->resource[0].start = dev->resource[0].end = 0;
+	dev->resource[0].flags = 0;
+	dev->resource[1].start = dev->resource[1].end = 0;
+	dev->resource[1].flags = 0;
+}
+
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			     struct resource *res, int resource)
@@ -179,14 +193,24 @@
 	if (_machine != _MACH_Pmac)
 		return;
 	/*
-	 * Fix the interrupt routing on the TI1211 chip on the 1999
-	 * G3 powerbook, which doesn't get initialized properly by OF.
-	 * Same problem with the 1410 of the new titanium pbook which
-	 * has the same register.
+	 * Fix the interrupt routing on the various cardbus bridges
+	 * used on powerbooks
 	 */
-	if (dev->vendor == PCI_VENDOR_ID_TI
-	    && (dev->device == PCI_DEVICE_ID_TI_1211 ||
-	        dev->device == PCI_DEVICE_ID_TI_1410)) {
+	if (dev->vendor != PCI_VENDOR_ID_TI)
+		return;
+	if (dev->device == PCI_DEVICE_ID_TI_1130 ||
+	    dev->device == PCI_DEVICE_ID_TI_1131) {
+		u8 val;
+	    	/* Enable PCI interrupt */
+		if (pci_read_config_byte(dev, 0x91, &val) == 0)
+			pci_write_config_byte(dev, 0x91, val | 0x30);
+		/* Disable ISA interrupt mode */	
+		if (pci_read_config_byte(dev, 0x92, &val) == 0)
+			pci_write_config_byte(dev, 0x92, val & ~0x06);
+	}
+	if (dev->device == PCI_DEVICE_ID_TI_1210 ||
+	    dev->device == PCI_DEVICE_ID_TI_1211 ||
+	    dev->device == PCI_DEVICE_ID_TI_1410) {
 		u8 val;
 		/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
 		   signal out the MFUNC0 pin */
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/pmac_pci.c linux-2.4.19-pre9/arch/ppc/kernel/pmac_pci.c
--- linux-2.4.19-pre8/arch/ppc/kernel/pmac_pci.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/pmac_pci.c	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pci.c 1.33 03/19/02 15:53:55 benh
+ * BK Id: SCCS/s.pmac_pci.c 1.35 05/06/02 01:37:30 benh
  */
 /*
  * Support for PCI bridges found on Power Macintoshes.
@@ -482,26 +482,16 @@
 {	
 	struct pci_dev* dev;
 	
-	pci_for_each_dev(dev)
-	{
-		/*
-		 * Open Firmware often doesn't initialize the,
-		 * PCI_INTERRUPT_LINE config register properly, so we
-		 * should find the device node and se if it has an
-		 * AAPL,interrupts property.
-		 */
-		unsigned char pin;
-		struct device_node* node;
-			
-		if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || !pin)
-			continue; /* No interrupt generated -> no fixup */
-		node = pci_device_to_OF_node(dev);
-		if (!node) {
-			printk("No OF node for device %x:%x\n", dev->bus->number, dev->devfn >> 3);
-			continue;
-		}
+	/*
+	 * Open Firmware often doesn't initialize the
+	 * PCI_INTERRUPT_LINE config register properly, so we
+	 * should find the device node and apply the interrupt
+	 * obtained from the OF device-tree
+	 */
+	pci_for_each_dev(dev) {
+		struct device_node* node = pci_device_to_OF_node(dev);
 		/* this is the node, see if it has interrupts */
-		if (node->n_intrs > 0) 
+		if (node && node->n_intrs > 0)
 			dev->irq = node->intrs[0].line;
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 	}
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/pmac_setup.c linux-2.4.19-pre9/arch/ppc/kernel/pmac_setup.c
--- linux-2.4.19-pre8/arch/ppc/kernel/pmac_setup.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/pmac_setup.c	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_setup.c 1.53 04/09/02 21:01:58 paulus
+ * BK Id: SCCS/s.pmac_setup.c 1.54 04/16/02 20:08:22 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -50,6 +50,8 @@
 #include <linux/cuda.h>
 #include <linux/pmu.h>
 #include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
 
 #include <asm/processor.h>
 #include <asm/sections.h>
@@ -67,14 +69,14 @@
 #include <asm/bootx.h>
 #include <asm/cputable.h>
 #include <asm/btext.h>
-
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
+
 #include "local_irq.h"
 #include "pmac_pic.h"
-#include "../mm/mem_pieces.h"
-
-#undef SHOW_GATWICK_IRQS
+#include "mem_pieces.h"
+#include "scsi.h" /* sd_find_target */
+#include "sd.h"
 
 extern long pmac_time_init(void);
 extern unsigned long pmac_get_rtc_time(void);
@@ -267,16 +269,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_SCSI
-/* Find the device number for the disk (if any) at target tgt
-   on host adaptor host.  We just need to get the prototype from
-   sd.h */
-#include <linux/blkdev.h>
-#include "../../../drivers/scsi/scsi.h"
-#include "../../../drivers/scsi/sd.h"
-
-#endif
-
 #ifdef CONFIG_VT
 /*
  * Dummy mksound function that does nothing.
@@ -431,6 +423,34 @@
 	pmac_feature_late_init();
 }
 
+/* That include would have to be in include/linux/ ideally */
+#include "../../../fs/partitions/mac.h"
+
+/* Borrowed from fs/partition/check.c */
+static unsigned char* __init
+read_one_block(struct block_device *bdev, unsigned long n, struct page **v)
+{
+	struct address_space *mapping = bdev->bd_inode->i_mapping;
+	int sect = PAGE_CACHE_SIZE / 512;
+	struct page *page;
+
+	page = read_cache_page(mapping, n/sect,
+			(filler_t *)mapping->a_ops->readpage, NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page(page);
+		if (!Page_Uptodate(page))
+			goto fail;
+		if (PageError(page))
+			goto fail;
+		*v = page;
+		return (unsigned char *)page_address(page) + 512 * (n % sect);
+fail:
+		page_cache_release(page);
+	}
+	*v = NULL;
+	return NULL;
+}
+
 #ifdef CONFIG_SCSI
 void __init
 note_scsi_host(struct device_node *node, void *host)
@@ -496,32 +516,132 @@
 #endif
 }
 
-/* can't be __init - can be called whenever a disk is first accessed */
-void __pmac
-note_bootable_part(kdev_t dev, int part, int goodness)
+static void __init
+check_bootable_part(kdev_t dev, int blk, struct mac_partition *part)
 {
-	static int found_boot = 0;
-	char *p;
+	int goodness = 0;
+
+	macpart_fix_string(part->processor, 16);
+	macpart_fix_string(part->name, 32);
+	macpart_fix_string(part->type, 32);					
+    
+	if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+	    && strcasecmp(part->processor, "powerpc") == 0)
+		goodness++;
+
+	if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+	    || (strnicmp(part->type, "Linux", 5) == 0
+	    && strcasecmp(part->type, "Linux_swap") != 0)) {
+		int i, l;
+
+		goodness++;
+		l = strlen(part->name);
+		if (strcmp(part->name, "/") == 0)
+			goodness++;
+		for (i = 0; i <= l - 4; ++i) {
+			if (strnicmp(part->name + i, "root",
+				     4) == 0) {
+				goodness += 2;
+				break;
+			}
+		}
+		if (strnicmp(part->name, "swap", 4) == 0)
+			goodness--;
+	}
+
+	if (goodness > current_root_goodness) {
+		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + blk);
+		current_root_goodness = goodness;
+	}
+}
 
-	/* Do nothing if the root has been mounted already. */
-	if (init_task.fs->rootmnt != NULL)
+static void __init
+check_bootable_disk(kdev_t dev, struct block_device *bdev)
+{
+	struct mac_partition *part;
+	struct mac_driver_desc *md;
+	struct page* pg;
+	unsigned secsize, blocks_in_map, blk;
+	unsigned char* data;
+	
+	/* Check driver descriptor */
+	md = (struct mac_driver_desc *) read_one_block(bdev, 0, &pg);
+	if (!md)
 		return;
-	if ((goodness <= current_root_goodness) &&
-	    (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
+	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
+		goto fail;
+	secsize = be16_to_cpu(md->block_size);
+	page_cache_release(pg);
+	
+	/* Check if it looks like a mac partition map */
+	data = read_one_block(bdev, secsize/512, &pg);
+	if (!data)
+		goto fail;
+	part = (struct mac_partition *) (data + secsize%512);
+	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+		goto fail;
+
+	/* Iterate the partition map */
+	blocks_in_map = be32_to_cpu(part->map_count);
+	for (blk = 1; blk <= blocks_in_map; ++blk) {
+		int pos = blk * secsize;
+		page_cache_release(pg);
+		data = read_one_block(bdev, pos/512, &pg);
+		if (!data)
+			break;
+		part = (struct mac_partition *) (data + pos%512);
+		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+			break;
+		check_bootable_part(dev, blk, part);
+	}
+fail:
+	if (pg)	
+		page_cache_release(pg);
+}
+
+static int __init
+walk_bootable(struct gendisk *hd, void *data)
+{
+	int drive;
+	
+	for (drive=0; drive<hd->nr_real; drive++) {
+		kdev_t dev;
+		struct block_device *bdev;
+		int rc;
+
+		dev = MKDEV(hd->major, drive << hd->minor_shift);
+		if (boot_dev && boot_dev != dev)
+			continue;
+		bdev = bdget(kdev_t_to_nr(dev));
+		if (bdev == NULL)
+			continue;
+		rc = blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW);
+		if (rc == 0) {
+			check_bootable_disk(dev, bdev);
+			blkdev_put(bdev, BDEV_RAW);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_discover_root(void)
+{
+	char* p;
+
+	/* Check if root devices already got selected by other ways */
+	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
 		return;
 	p = strstr(saved_command_line, "root=");
 	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
 		return;
 
-	if (!found_boot) {
-		find_boot_device();
-		found_boot = 1;
-	}
-	if (boot_dev == 0 || dev == boot_dev) {
-		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
-		boot_dev = NODEV;
-		current_root_goodness = goodness;
-	}
+	/* Find the device used for booting if we can */
+	find_boot_device();
+
+	/* Try to locate a partition */
+	walk_gendisk(walk_bootable, NULL);
 }
 
 void __pmac
@@ -788,6 +908,8 @@
 	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
 	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
 
+	ppc_md.discover_root  = pmac_discover_root;
+
 	ppc_md.restart        = pmac_restart;
 	ppc_md.power_off      = pmac_power_off;
 	ppc_md.halt           = pmac_halt;
diff -urN linux-2.4.19-pre8/arch/ppc/kernel/setup.c linux-2.4.19-pre9/arch/ppc/kernel/setup.c
--- linux-2.4.19-pre8/arch/ppc/kernel/setup.c	Tue May 28 16:02:15 2002
+++ linux-2.4.19-pre9/arch/ppc/kernel/setup.c	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.setup.c 1.74 04/09/02 21:01:58 paulus
+ * BK Id: SCCS/s.setup.c 1.75 04/16/02 20:08:22 paulus
  */
 /*
  * Common prep/pmac/chrp boot and setup code.
@@ -523,6 +523,12 @@
 }
 __setup("l2cr=", ppc_setup_l2cr);
 
+void __init arch_discover_root(void)
+{
+	if (ppc_md.discover_root != NULL)
+		ppc_md.discover_root();
+}
+
 void __init ppc_init(void)
 {
 	/* clear the progress line */
diff -urN linux-2.4.19-pre8/arch/ppc/lib/string.S linux-2.4.19-pre9/arch/ppc/lib/string.S
--- linux-2.4.19-pre8/arch/ppc/lib/string.S	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre9/arch/ppc/lib/string.S	Tue May 28 16:02:28 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.string.S 1.9 10/25/01 10:08:51 trini
+ * BK Id: SCCS/s.string.S 1.11 05/21/02 21:44:32 paulus
  */
 /*
  * String handling functions for PowerPC.
@@ -468,7 +468,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"
@@ -477,7 +477,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)
@@ -621,11 +623,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
@@ -634,14 +636,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
 
 	.globl	__strncpy_from_user
diff -urN linux-2.4.19-pre8/arch/sparc/defconfig linux-2.4.19-pre9/arch/sparc/defconfig
--- linux-2.4.19-pre8/arch/sparc/defconfig	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc/defconfig	Tue May 28 16:02:28 2002
@@ -163,6 +163,11 @@
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 CONFIG_DECNET=m
 CONFIG_DECNET_SIOCGIFCONF=y
 # CONFIG_DECNET_ROUTER is not set
@@ -180,6 +185,11 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
 # CONFIG_IDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -248,6 +258,7 @@
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -290,7 +301,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
diff -urN linux-2.4.19-pre8/arch/sparc/kernel/check_asm.sh linux-2.4.19-pre9/arch/sparc/kernel/check_asm.sh
--- linux-2.4.19-pre8/arch/sparc/kernel/check_asm.sh	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre9/arch/sparc/kernel/check_asm.sh	Tue May 28 16:02:28 2002
@@ -11,7 +11,7 @@
     echo "	sizeof(struct $2_struct)," >> $4
   ;;
   -ints)
-    sed -n -e '/check_asm_data:/,/\.size/p' <$2 | sed -e 's/check_asm_data://' -e 's/\.size.*//' -e 's/\.ident.*//' -e 's/\.long[ 	]\([0-9]*\)/\1,/' >>$3
+    sed -n -e '/check_asm_data:/,/\.size/p' <$2 | sed -e 's/check_asm_data://' -e 's/\.size.*//' -e 's/\.ident.*//' -e 's/\.global.*//' -e 's/\.long[ 	]\([0-9]*\)/\1,/' >>$3
   ;;
   *)
     exit 1
diff -urN linux-2.4.19-pre8/arch/sparc/kernel/ioport.c linux-2.4.19-pre9/arch/sparc/kernel/ioport.c
--- linux-2.4.19-pre8/arch/sparc/kernel/ioport.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc/kernel/ioport.c	Tue May 28 16:02:28 2002
@@ -351,7 +351,7 @@
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len, int direction)
+dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
 {
 #if 0 /* This is the version that abuses consistent space */
 	unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
@@ -398,7 +398,7 @@
 #endif
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n, int direction)
+void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
 {
 #if 0 /* This is the version that abuses consistent space */
 	struct resource *res;
@@ -445,7 +445,7 @@
 
 /*
  */
-void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int direction)
+void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
 {
 #if 0
 	unsigned long va;
diff -urN linux-2.4.19-pre8/arch/sparc/kernel/ptrace.c linux-2.4.19-pre9/arch/sparc/kernel/ptrace.c
--- linux-2.4.19-pre8/arch/sparc/kernel/ptrace.c	Tue Sep 18 17:03:51 2001
+++ linux-2.4.19-pre9/arch/sparc/kernel/ptrace.c	Tue May 28 16:02:28 2002
@@ -234,29 +234,13 @@
 
 #ifdef DEBUG_PTRACE
 char *pt_rq [] = {
-"TRACEME",
-"PEEKTEXT",
-"PEEKDATA",
-"PEEKUSR",
-"POKETEXT",
-"POKEDATA",
-"POKEUSR",
-"CONT",
-"KILL",
-"SINGLESTEP",
-"SUNATTACH",
-"SUNDETACH",
-"GETREGS",
-"SETREGS",
-"GETFPREGS",
-"SETFPREGS",
-"READDATA",
-"WRITEDATA",
-"READTEXT",
-"WRITETEXT",
-"GETFPAREGS",
-"SETFPAREGS",
-""
+	/* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
+	/* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
+	/* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
+	/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
+	/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
+	/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
+	/* 24 */ "SYSCALL", ""
 };
 #endif
 
@@ -284,7 +268,7 @@
 	{
 		char *s;
 
-		if ((request > 0) && (request < 21))
+		if ((request >= 0) && (request <= 24))
 			s = pt_rq [request];
 		else
 			s = "unknown";
diff -urN linux-2.4.19-pre8/arch/sparc/kernel/sys_sunos.c linux-2.4.19-pre9/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.19-pre8/arch/sparc/kernel/sys_sunos.c	Tue Aug 14 19:57:28 2001
+++ linux-2.4.19-pre9/arch/sparc/kernel/sys_sunos.c	Tue May 28 16:02:28 2002
@@ -1049,8 +1049,8 @@
 	return ret;
 }
 
-extern asmlinkage int sys_read(unsigned int fd,char *buf,int count);
-extern asmlinkage int sys_write(unsigned int fd,char *buf,int count);
+extern asmlinkage ssize_t sys_read(unsigned int fd,char *buf,int count);
+extern asmlinkage ssize_t sys_write(unsigned int fd,char *buf,int count);
 extern asmlinkage int sys_recv(int fd, void * ubuf, int size, unsigned flags);
 extern asmlinkage int sys_send(int fd, void * buff, int len, unsigned flags);
 extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);
diff -urN linux-2.4.19-pre8/arch/sparc/kernel/systbls.S linux-2.4.19-pre9/arch/sparc/kernel/systbls.S
--- linux-2.4.19-pre8/arch/sparc/kernel/systbls.S	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc/kernel/systbls.S	Tue May 28 16:02:28 2002
@@ -55,7 +55,7 @@
 /*170*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
 /*175*/	.long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-/*185*/	.long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*185*/	.long sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
@@ -70,7 +70,7 @@
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_nis_syscall, sys_nis_syscall, sys_tkill
+/*255*/	.long sys_nis_syscall, sys_nis_syscall
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
diff -urN linux-2.4.19-pre8/arch/sparc/mm/srmmu.c linux-2.4.19-pre9/arch/sparc/mm/srmmu.c
--- linux-2.4.19-pre8/arch/sparc/mm/srmmu.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc/mm/srmmu.c	Tue May 28 16:02:28 2002
@@ -394,7 +394,6 @@
 
 static pte_t *srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	BUG();
 	return NULL;
 }
 
diff -urN linux-2.4.19-pre8/arch/sparc/mm/sun4c.c linux-2.4.19-pre9/arch/sparc/mm/sun4c.c
--- linux-2.4.19-pre8/arch/sparc/mm/sun4c.c	Tue Nov 13 09:16:05 2001
+++ linux-2.4.19-pre9/arch/sparc/mm/sun4c.c	Tue May 28 16:02:28 2002
@@ -1902,19 +1902,6 @@
 	}
 }
 
-static void sun4c_set_pte(pte_t *ptep, pte_t pte)
-{
-	*ptep = pte;
-}
-
-static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-}
-
-static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
-}
-
 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
 		     int bus_type, int rdonly)
 {
@@ -2093,6 +2080,20 @@
 #define PGD_DIRTY    0x040
 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
+static void sun4c_set_pte(pte_t *ptep, pte_t pte)
+{
+	*ptep = pte;
+}
+
+static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+}
+
+static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+	*pmdp = (PGD_TABLE | (unsigned long) ptep);
+}
+
 static int sun4c_pte_present(pte_t pte)
 {
 	return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2508,6 +2509,7 @@
 #else
 	BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM);
 #endif
+	BTFIXUPSET_CALL(pmd_set, sun4c_pmd_set, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
@@ -2568,5 +2570,4 @@
 	/* These should _never_ get called with two level tables. */
 	BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(pgd_page, sun4c_pgd_page, BTFIXUPCALL_RETO0);
-	BTFIXUPSET_CALL(pmd_set, sun4c_pmd_set, BTFIXUPCALL_NOP);
 }
diff -urN linux-2.4.19-pre8/arch/sparc64/defconfig linux-2.4.19-pre9/arch/sparc64/defconfig
--- linux-2.4.19-pre8/arch/sparc64/defconfig	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/defconfig	Tue May 28 16:02:28 2002
@@ -202,6 +202,11 @@
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 CONFIG_DECNET=m
 CONFIG_DECNET_SIOCGIFCONF=y
 # CONFIG_DECNET_ROUTER is not set
@@ -438,14 +443,6 @@
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
 CONFIG_EQUALIZER=m
@@ -868,12 +865,17 @@
 #
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
 
 #
 # Bluetooth device drivers
 #
 CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_USB_FW_LOAD=y
+CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+# CONFIG_BLUEZ_HCIDTL1 is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/Makefile linux-2.4.19-pre9/arch/sparc64/kernel/Makefile
--- linux-2.4.19-pre8/arch/sparc64/kernel/Makefile	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre9/arch/sparc64/kernel/Makefile	Tue May 28 16:02:28 2002
@@ -1,19 +1,11 @@
 # $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
 SH = $(CONFIG_SHELL)
 
-.S.s:
-	$(CPP) $(AFLAGS) -ansi $< -o $*.s
-
-.S.o:
-	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
+EXTRA_AFLAGS := -ansi
 
 all: kernel.o head.o init_task.o
 
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/process.c linux-2.4.19-pre9/arch/sparc64/kernel/process.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/process.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/process.c	Tue May 28 16:02:28 2002
@@ -581,13 +581,6 @@
  * under SunOS are nothing short of bletcherous:
  * Parent -->  %o0 == childs  pid, %o1 == 0
  * Child  -->  %o0 == parents pid, %o1 == 1
- *
- * NOTE: We have a separate fork kpsr/kwim because
- *       the parent could change these values between
- *       sys_fork invocation and when we reach here
- *       if the parent should sleep while trying to
- *       allocate the task_struct and kernel stack in
- *       do_fork().
  */
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		unsigned long unused,
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/ptrace.c linux-2.4.19-pre9/arch/sparc64/kernel/ptrace.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/ptrace.c	Mon Oct  1 09:19:56 2001
+++ linux-2.4.19-pre9/arch/sparc64/kernel/ptrace.c	Tue May 28 16:02:28 2002
@@ -80,29 +80,13 @@
 
 #ifdef DEBUG_PTRACE
 char *pt_rq [] = {
-"TRACEME",
-"PEEKTEXT",
-"PEEKDATA",
-"PEEKUSR",
-"POKETEXT",
-"POKEDATA",
-"POKEUSR",
-"CONT",
-"KILL",
-"SINGLESTEP",
-"SUNATTACH",
-"SUNDETACH",
-"GETREGS",
-"SETREGS",
-"GETFPREGS",
-"SETFPREGS",
-"READDATA",
-"WRITEDATA",
-"READTEXT",
-"WRITETEXT",
-"GETFPAREGS",
-"SETFPAREGS",
-""
+	/* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
+	/* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
+	/* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
+	/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
+	/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
+	/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
+	/* 24 */ "SYSCALL", ""
 };
 #endif
 
@@ -135,7 +119,7 @@
 	{
 		char *s;
 
-		if ((request > 0) && (request < 21))
+		if ((request >= 0) && (request <= 24))
 			s = pt_rq [request];
 		else
 			s = "unknown";
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/signal.c linux-2.4.19-pre9/arch/sparc64/kernel/signal.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/signal.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/signal.c	Tue May 28 16:02:28 2002
@@ -411,6 +411,7 @@
 	struct rt_signal_frame *sf;
 	unsigned long tpc, tnpc, tstate;
 	__siginfo_fpu_t *fpu_save;
+	mm_segment_t old_fs;
 	sigset_t set;
 	stack_t st;
 	int err;
@@ -455,7 +456,10 @@
 	
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	do_sigaltstack(&st, NULL, (unsigned long)sf);
+	set_fs(old_fs);
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/signal32.c linux-2.4.19-pre9/arch/sparc64/kernel/signal32.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/signal32.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/signal32.c	Tue May 28 16:02:28 2002
@@ -394,6 +394,7 @@
 	struct rt_signal_frame32 *sf;
 	unsigned int psr;
 	unsigned pc, npc, fpu_save;
+	mm_segment_t old_fs;
 	sigset_t set;
 	sigset_t32 seta;
 	stack_t st;
@@ -451,7 +452,10 @@
 		
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	do_sigaltstack(&st, NULL, (unsigned long)sf);
+	set_fs(old_fs);
 	
 	switch (_NSIG_WORDS) {
 		case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
@@ -1025,6 +1029,7 @@
 {
 	struct thread_struct *tp = &current->thread;
 	svr4_gregset_t  *gr;
+	mm_segment_t old_fs;
 	u32 pc, npc, psr;
 	sigset_t set;
 	svr4_sigset_t setv;
@@ -1078,7 +1083,10 @@
 		
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	do_sigaltstack(&st, NULL, regs->u_regs[UREG_I6]);
+	set_fs(old_fs);
 	
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.19-pre9/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/sparc64_ksyms.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/sparc64_ksyms.c	Tue May 28 16:02:28 2002
@@ -360,6 +360,10 @@
 /* RAID code needs this */
 EXPORT_SYMBOL_NOVERS(VISenter);
 
+extern void batten_down_hatches(void);
+/* for input/keybdev */
+EXPORT_SYMBOL(batten_down_hatches);
+
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(do_BUG);
 #endif
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/sys_sunos32.c linux-2.4.19-pre9/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.19-pre8/arch/sparc64/kernel/sys_sunos32.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/sys_sunos32.c	Tue May 28 16:02:28 2002
@@ -1199,8 +1199,8 @@
 	return ret;
 }
 
-extern asmlinkage int sys_read(unsigned int fd, char *buf, unsigned long count);
-extern asmlinkage int sys_write(unsigned int fd, char *buf, unsigned long count);
+extern asmlinkage ssize_t sys_read(unsigned int fd, char *buf, unsigned long count);
+extern asmlinkage ssize_t sys_write(unsigned int fd, char *buf, unsigned long count);
 extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
 extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
 extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);
diff -urN linux-2.4.19-pre8/arch/sparc64/kernel/systbls.S linux-2.4.19-pre9/arch/sparc64/kernel/systbls.S
--- linux-2.4.19-pre8/arch/sparc64/kernel/systbls.S	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/kernel/systbls.S	Tue May 28 16:02:28 2002
@@ -56,7 +56,7 @@
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
@@ -70,7 +70,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib, sys_tkill
+	.word sys_aplib
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -115,7 +115,7 @@
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
+	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
@@ -129,7 +129,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib, sys_tkill
+	.word sys_aplib
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
diff -urN linux-2.4.19-pre8/arch/sparc64/lib/Makefile linux-2.4.19-pre9/arch/sparc64/lib/Makefile
--- linux-2.4.19-pre8/arch/sparc64/lib/Makefile	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/lib/Makefile	Tue May 28 16:02:28 2002
@@ -2,13 +2,8 @@
 # Makefile for Sparc64 library files..
 #
 
-.S.s:
-	$(CPP) $(AFLAGS) -ansi $< -o $*.s
-
-.S.o:
-	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
-
-CFLAGS := $(CFLAGS)
+USE_STANDARD_AS_RULE := true
+EXTRA_AFLAGS := -ansi
 
 L_TARGET = lib.a
 obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
diff -urN linux-2.4.19-pre8/arch/sparc64/mm/Makefile linux-2.4.19-pre9/arch/sparc64/mm/Makefile
--- linux-2.4.19-pre8/arch/sparc64/mm/Makefile	Fri Dec 29 14:07:21 2000
+++ linux-2.4.19-pre9/arch/sparc64/mm/Makefile	Tue May 28 16:02:28 2002
@@ -1,17 +1,9 @@
 # $Id: Makefile,v 1.8 2000/12/14 22:57:25 davem Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-.S.s:
-	$(CPP) $(AFLAGS) -ansi $< -o $*.s
 
-.S.o:
-	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
+USE_STANDARD_AS_RULE := true
+EXTRA_AFLAGS := -ansi
 
 O_TARGET := mm.o
 obj-y    := ultra.o fault.o init.o generic.o extable.o modutil.o
diff -urN linux-2.4.19-pre8/arch/sparc64/prom/Makefile linux-2.4.19-pre9/arch/sparc64/prom/Makefile
--- linux-2.4.19-pre8/arch/sparc64/prom/Makefile	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/arch/sparc64/prom/Makefile	Tue May 28 16:02:28 2002
@@ -2,22 +2,14 @@
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
+
+USE_STANDARD_AS_RULE := true
+EXTRA_AFLAGS := -ansi
 
 L_TARGET = promlib.a
 obj-y   := bootstr.o devops.o init.o memory.o misc.o \
 	   tree.o console.o printf.o p1275.o map.o
 
-.S.s:
-	$(CPP) $(AFLAGS) -ansi $< -o $*.s
-
-.S.o:
-	$(CC) $(AFLAGS) -ansi -c $< -o $*.o
-
 include $(TOPDIR)/Rules.make
 
 %.o: %.c
diff -urN linux-2.4.19-pre8/arch/sparc64/solaris/Makefile linux-2.4.19-pre9/arch/sparc64/solaris/Makefile
--- linux-2.4.19-pre8/arch/sparc64/solaris/Makefile	Fri Dec 29 14:07:21 2000
+++ linux-2.4.19-pre9/arch/sparc64/solaris/Makefile	Tue May 28 16:02:28 2002
@@ -7,16 +7,13 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+USE_STANDARD_AS_RULE := true
+EXTRA_AFLAGS := -ansi
+
 ifeq ($(CONFIG_SOLARIS_EMUL),m)
-CPPFLAGS = $(MODFLAGS)
+  EXTRA_AFLAGS += $(MODFLAGS)
 endif
 
-.S.s:
-	$(CPP) $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
-
-.S.o:
-	$(CC) $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
-
 list-multi := solaris.o
 
 solaris-objs := entry64.o fs.o misc.o signal.o systbl.o socket.o \
diff -urN linux-2.4.19-pre8/drivers/block/genhd.c linux-2.4.19-pre9/drivers/block/genhd.c
--- linux-2.4.19-pre8/drivers/block/genhd.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/block/genhd.c	Tue May 28 16:02:28 2002
@@ -130,6 +130,32 @@
 EXPORT_SYMBOL(get_gendisk);
 
 
+/**
+ * walk_gendisk - issue a command for every registered gendisk
+ * @walk: user-specified callback
+ * @data: opaque data for the callback
+ *
+ * This function walks through the gendisk chain and calls back
+ * into @walk for every element.
+ */
+int
+walk_gendisk(int (*walk)(struct gendisk *, void *), void *data)
+{
+	struct gendisk *gp;
+	int error = 0;
+
+	read_lock(&gendisk_lock);
+	for (gp = gendisk_head; gp; gp = gp->next)
+		if ((error = walk(gp, data)))
+			break;
+	read_unlock(&gendisk_lock);
+
+	return error;
+}
+
+EXPORT_SYMBOL(walk_gendisk);
+
+
 #ifdef CONFIG_PROC_FS
 int
 get_partition_list(char *page, char **start, off_t offset, int count)
@@ -187,26 +213,16 @@
 
 
 extern int blk_dev_init(void);
-#ifdef CONFIG_FUSION_BOOT
-extern int fusion_init(void);
-#endif
 extern int net_dev_init(void);
 extern void console_map_init(void);
 extern int soc_probe(void);
 extern int atmdev_init(void);
-extern int i2o_init(void);
 
 int __init device_init(void)
 {
 	rwlock_init(&gendisk_lock);
 	blk_dev_init();
 	sti();
-#ifdef CONFIG_I2O
-	i2o_init();
-#endif
-#ifdef CONFIG_FUSION_BOOT
-	fusion_init();
-#endif
 #ifdef CONFIG_FC4_SOC
 	/* This has to be done before scsi_dev_init */
 	soc_probe();
diff -urN linux-2.4.19-pre8/drivers/block/ll_rw_blk.c linux-2.4.19-pre9/drivers/block/ll_rw_blk.c
--- linux-2.4.19-pre8/drivers/block/ll_rw_blk.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/block/ll_rw_blk.c	Tue May 28 16:02:28 2002
@@ -666,7 +666,6 @@
 			hd->wr_merges++;
 		hd->wr_sectors += sectors;
 		break;
-	default:
 	}
 	if (!merge)
 		up_ios(hd);
@@ -684,7 +683,6 @@
 		hd->wr_ticks += duration;
 		hd->wr_ios++;
 		break;
-	default:
 	}
 	down_ios(hd);
 }
diff -urN linux-2.4.19-pre8/drivers/block/umem.c linux-2.4.19-pre9/drivers/block/umem.c
--- linux-2.4.19-pre8/drivers/block/umem.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/block/umem.c	Tue May 28 16:02:29 2002
@@ -39,6 +39,7 @@
 #include <linux/ioctl.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
@@ -947,26 +948,6 @@
 	unlock_buffer(bh);
 }
 
-/* following copied from buffer.c
- * when it gets exported, as it should be, this
- * can be removed.
- */
-/* #define avoids compiler complaints */
-#define set_bh_page mm_set_bh_page
-static void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
-{
-	bh->b_page = page;
-	if (offset >= PAGE_SIZE)
-		BUG();
-	if (PageHighMem(page))
-		/*
-		 * This catches illegal uses and preserves the offset:
-		 */
-		bh->b_data = (char *)(0 + offset);
-	else
-		bh->b_data = page_address(page) + offset;
-}
-
  
 static int __devinit mm_init_mem(struct cardinfo *card)
 {
diff -urN linux-2.4.19-pre8/drivers/char/Config.in linux-2.4.19-pre9/drivers/char/Config.in
--- linux-2.4.19-pre8/drivers/char/Config.in	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/Config.in	Tue May 28 16:02:29 2002
@@ -260,7 +260,9 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
-   dep_bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 $CONFIG_IA64
+   if [ "$CONFIG_IA64" = "y" ]; then
+      bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
+   fi
 fi
 
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
diff -urN linux-2.4.19-pre8/drivers/char/advantechwdt.c linux-2.4.19-pre9/drivers/char/advantechwdt.c
--- linux-2.4.19-pre8/drivers/char/advantechwdt.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre9/drivers/char/advantechwdt.c	Tue May 28 16:02:29 2002
@@ -13,10 +13,10 @@
  *	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.
- *	
- *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
- *	warranty for any of this software. This material is provided 
- *	"AS-IS" and at no charge.	
+ *
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
@@ -24,14 +24,11 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <asm/io.h>
@@ -40,41 +37,67 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
-static int advwdt_is_open;
-static spinlock_t advwdt_lock;
+static unsigned long advwdt_is_open;
+static char adv_expect_close;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
  *
  *	To enable or restart, write the timeout value in seconds (1 to 63)
- *	to I/O port WDT_START.  To disable, read I/O port WDT_STOP.
+ *	to I/O port wdt_start.  To disable, read I/O port wdt_stop.
  *	Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
  *	check your manual (at least the PCA-6159 seems to be different -
- *	the manual says WDT_STOP is 0x43, not 0x443).
+ *	the manual says wdt_stop is 0x43, not 0x443).
  *	(0x43 is also a write-only control register for the 8254 timer!)
- *
- *	TODO: module parameters to set the I/O port addresses and NOWAYOUT
- *	option at load time.
  */
  
-#define WDT_STOP 0x443
-#define WDT_START 0x443
+static int wdt_stop = 0x443;
+static int wdt_start = 0x443;
 
-#define WD_TIMO 60		/* 1 minute */
-static int wd_margin = WD_TIMO;
+static int wd_margin = 60; /* 60 sec default timeout */
 
 /*
  *	Kernel methods.
  */
- 
+
+#ifndef MODULE
+
+static int __init adv_setup(char *str)
+{
+	int ints[4];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if(ints[0] > 0){
+		wdt_stop = ints[1];
+		if(ints[0] > 1)
+			wdt_start = ints[2];
+	}
+
+	return 1;
+}
+
+__setup("advwdt=", adv_setup);
+
+#endif /* !MODULE */
+
+MODULE_PARM(wdt_stop, "i");
+MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
+MODULE_PARM(wdt_start, "i");
+MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
+
 static void
 advwdt_ping(void)
 {
 	/* Write a watchdog value */
-	outb_p(wd_margin, WDT_START);
+	outb_p(wd_margin, wdt_start);
+}
+
+static void
+advwdt_disable(void)
+{
+	inb_p(wdt_stop);
 }
 
 static ssize_t
@@ -85,16 +108,19 @@
 		return -ESPIPE;
 
 	if (count) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t i;
+
+		adv_expect_close = 0;
+
+		for (i = 0; i != count; i++) {
+			if (buf[i] == 'V')
+				adv_expect_close = 42;
+		}
+#endif
 		advwdt_ping();
-		return 1;
 	}
-	return 0;
-}
-
-static ssize_t
-advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
-	return -EINVAL;
+	return count;
 }
 
 static int
@@ -103,19 +129,20 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 1, "Advantech WDT"
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		firmware_version:	0,
+		identity:		"Advantech WDT"
 	};
-	
+
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 	  if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
 	    return -EFAULT;
 	  break;
-	  
+
 	case WDIOC_GETSTATUS:
-	  if (copy_to_user((int *)arg, &advwdt_is_open,  sizeof(int)))
-	    return -EFAULT;
-	  break;
+	case WDIOC_GETBOOTSTATUS:
+	  return put_user(0, (int *)arg);
 
 	case WDIOC_KEEPALIVE:
 	  advwdt_ping();
@@ -132,7 +159,26 @@
 
 	case WDIOC_GETTIMEOUT:
 	  return put_user(wd_margin, (int *)arg);
-	  break;
+
+	case WDIOC_SETOPTIONS:
+	{
+	  int options, retval = -EINVAL;
+
+	  if (get_user(options, (int *)arg))
+	    return -EFAULT;
+
+	  if (options & WDIOS_DISABLECARD) {
+	    advwdt_disable();
+	    retval = 0;
+	  }
+
+	  if (options & WDIOS_ENABLECARD) {
+	    advwdt_ping();
+	    retval = 0;
+	  }
+
+	  return retval;
+	}
 
 	default:
 	  return -ENOTTY;
@@ -143,39 +189,27 @@
 static int
 advwdt_open(struct inode *inode, struct file *file)
 {
-	switch (MINOR(inode->i_rdev)) {
-		case WATCHDOG_MINOR:
-			spin_lock(&advwdt_lock);
-			if (advwdt_is_open) {
-				spin_unlock(&advwdt_lock);
-				return -EBUSY;
-			}
-			/*
-			 *	Activate 
-			 */
-	 
-			advwdt_is_open = 1;
-			advwdt_ping();
-			spin_unlock(&advwdt_lock);
-			return 0;
-		default:
-			return -ENODEV;
-	}
+	if (test_and_set_bit(0, &advwdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+
+	advwdt_ping();
+	return 0;
 }
 
 static int
 advwdt_close(struct inode *inode, struct file *file)
 {
-	lock_kernel();
-	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
-		spin_lock(&advwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_STOP);
-#endif		
-		advwdt_is_open = 0;
-		spin_unlock(&advwdt_lock);
+	if (adv_expect_close == 42) {
+		advwdt_disable();
+	} else {
+		printk(KERN_CRIT "advancetechwdt: Unexpected close, not stopping watchdog!\n");
+		advwdt_ping();
 	}
-	unlock_kernel();
+	clear_bit(0, &advwdt_is_open);
+	adv_expect_close = 0;
 	return 0;
 }
 
@@ -189,7 +223,7 @@
 {
 	if (code == SYS_DOWN || code == SYS_HALT) {
 		/* Turn the WDT off */
-		inb_p(WDT_STOP);
+		advwdt_disable();
 	}
 	return NOTIFY_DONE;
 }
@@ -200,7 +234,7 @@
  
 static struct file_operations advwdt_fops = {
 	owner:		THIS_MODULE,
-	read:		advwdt_read,
+	llseek:		no_llseek,
 	write:		advwdt_write,
 	ioctl:		advwdt_ioctl,
 	open:		advwdt_open,
@@ -208,14 +242,14 @@
 };
 
 static struct miscdevice advwdt_miscdev = {
-	WATCHDOG_MINOR,
-	"watchdog",
-	&advwdt_fops
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&advwdt_fops,
 };
 
 /*
  *	The WDT needs to learn about soft shutdowns in order to
- *	turn the timebomb registers off. 
+ *	turn the timebomb registers off.
  */
  
 static struct notifier_block advwdt_notifier = {
@@ -227,14 +261,12 @@
 static int __init
 advwdt_init(void)
 {
-	printk("WDT driver for Advantech single board computer initialising.\n");
+	printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
 
-	spin_lock_init(&advwdt_lock);
 	misc_register(&advwdt_miscdev);
-#if WDT_START != WDT_STOP
-	request_region(WDT_STOP, 1, "Advantech WDT");
-#endif
-	request_region(WDT_START, 1, "Advantech WDT");
+	if(wdt_stop != wdt_start)
+		request_region(wdt_stop, 1, "Advantech WDT");
+	request_region(wdt_start, 1, "Advantech WDT");
 	register_reboot_notifier(&advwdt_notifier);
 	return 0;
 }
@@ -244,16 +276,18 @@
 {
 	misc_deregister(&advwdt_miscdev);
 	unregister_reboot_notifier(&advwdt_notifier);
-#if WDT_START != WDT_STOP
-	release_region(WDT_STOP,1);
-#endif
-	release_region(WDT_START,1);
+	if(wdt_stop != wdt_start)
+		release_region(wdt_stop,1);
+	release_region(wdt_start,1);
 }
 
 module_init(advwdt_init);
 module_exit(advwdt_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
+MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
+EXPORT_NO_SYMBOLS;
 
 /* end of advantechwdt.c */
 
diff -urN linux-2.4.19-pre8/drivers/char/agp/agp.h linux-2.4.19-pre9/drivers/char/agp/agp.h
--- linux-2.4.19-pre8/drivers/char/agp/agp.h	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/agp/agp.h	Tue May 28 16:02:29 2002
@@ -172,6 +172,12 @@
 #ifndef PCI_DEVICE_ID_INTEL_810_0
 #define PCI_DEVICE_ID_INTEL_810_0       0x7120
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_845_G_0
+#define PCI_DEVICE_ID_INTEL_845_G_0	0x2560
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_845_G_1
+#define PCI_DEVICE_ID_INTEL_845_G_1     0x2562
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_830_M_0
 #define PCI_DEVICE_ID_INTEL_830_M_0	0x3575
 #endif
diff -urN linux-2.4.19-pre8/drivers/char/agp/agpgart_be.c linux-2.4.19-pre9/drivers/char/agp/agpgart_be.c
--- linux-2.4.19-pre8/drivers/char/agp/agpgart_be.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/agp/agpgart_be.c	Tue May 28 16:02:29 2002
@@ -3948,6 +3948,12 @@
 		"Intel",
 		"i830M",
 		intel_830mp_setup },
+    { PCI_DEVICE_ID_INTEL_845_G_0,
+		 PCI_VENDOR_ID_INTEL,
+		 INTEL_I845_G,
+		 "Intel",
+		 "i845G",
+		 intel_830mp_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -4274,6 +4280,28 @@
 			agp_bridge.type = INTEL_I810;
 			return intel_i810_setup(i810_dev);
 
+		case PCI_DEVICE_ID_INTEL_845_G_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_845_G_1, NULL);
+			if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+				i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_845_G_1, i810_dev);
+			}
+
+			if (i810_dev == NULL) {
+                                /* 
+                                 * We probably have a I845 G chipset
+                                 * with an external graphics
+                                 * card. It will be initialized later 
+                                 */
+				agp_bridge.type = INTEL_I845_G;
+				break;
+			}
+			printk(KERN_INFO PFX "Detected an Intel "
+				   "845G Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i830_setup(i810_dev);
+		   
 		case PCI_DEVICE_ID_INTEL_830_M_0:
 			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
 					PCI_DEVICE_ID_INTEL_830_M_1, NULL);
diff -urN linux-2.4.19-pre8/drivers/char/sc1200wdt.c linux-2.4.19-pre9/drivers/char/sc1200wdt.c
--- linux-2.4.19-pre8/drivers/char/sc1200wdt.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/sc1200wdt.c	Tue May 28 16:02:29 2002
@@ -18,11 +18,14 @@
  *	20020221 Zwane Mwaikambo	Cleanups as suggested by Jeff Garzik and Alan Cox.
  *	20020222 Zwane Mwaikambo	Added probing.
  *	20020225 Zwane Mwaikambo	Added ISAPNP support.
+ *	20020412 Rob Radez		Broke out start/stop functions
+ *		 <rob@osinvestor.com>	Return proper status instead of temperature warning
+ *					Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
+ *					Fix CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
@@ -55,10 +58,6 @@
 #define	WDCF		0x06	/* Watchdog config register */
 #define WDST		0x07	/* Watchdog status register */
 
-/* WDO Status */
-#define WDO_ENABLED	0x00	
-#define WDO_DISABLED	0x01	
-
 /* WDCF bitfields - which devices assert WDO */
 #define KBC_IRQ		0x01	/* Keyboard Controller */
 #define MSE_IRQ		0x02	/* Mouse */
@@ -71,12 +70,15 @@
 static int io = -1;
 static int io_len = 2;		/* for non plug and play */
 struct semaphore open_sem;
-static int expect_close = 0;
+static char expect_close;
 spinlock_t sc1200wdt_lock;	/* io port access serialisation */
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
 static int isapnp = 1;
 static struct pci_dev *wdt_dev;
+
+MODULE_PARM(isapnp, "i");
+MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
 #endif
 
 MODULE_PARM(io, "i");
@@ -84,10 +86,6 @@
 MODULE_PARM(timeout, "i");
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
-#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-MODULE_PARM(isapnp, "i");
-MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
-#endif
 
 
 /* Read from Data Register */
@@ -110,41 +108,51 @@
 }
 
 
-/* This returns the status of the WDO signal, inactive high.
- * returns WDO_ENABLED or WDO_DISABLED
- */
+static void sc1200wdt_start(void)
+{
+	unsigned char reg;
+
+	sc1200wdt_read_data(WDCF, &reg);
+	/* assert WDO when any of the following interrupts are triggered too */
+	reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
+	sc1200wdt_write_data(WDCF, reg);
+	/* set the timeout and get the ball rolling */
+	sc1200wdt_write_data(WDTO, timeout);
+}
+
+
+static void sc1200wdt_stop(void)
+{
+	sc1200wdt_write_data(WDTO, 0);
+}
+
+
+/* This returns the status of the WDO signal, inactive high. */
 static inline int sc1200wdt_status(void)
 {
 	unsigned char ret;
 
 	sc1200wdt_read_data(WDST, &ret);
-	return (ret & 0x01);		/* bits 1 - 7 are undefined */
+	/* If the bit is inactive, the watchdog is enabled, so return
+	 * KEEPALIVEPING which is a bit of a kludge because there's nothing
+	 * else for enabled/disabled status
+	 */
+	return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;	/* bits 1 - 7 are undefined */
 }
 
 
 static int sc1200wdt_open(struct inode *inode, struct file *file)
 {
-	unsigned char reg;
-
 	/* allow one at a time */
 	if (down_trylock(&open_sem))
 		return -EBUSY;
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	
-	MOD_INC_USE_COUNT;
-#endif
-
 	if (timeout > MAX_TIMEOUT)
 		timeout = MAX_TIMEOUT;
 
-	sc1200wdt_read_data(WDCF, &reg);
-	/* assert WDO when any of the following interrupts are triggered too */
-	reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
-	sc1200wdt_write_data(WDCF, reg);
-	/* set the timeout and get the ball rolling */
-	sc1200wdt_write_data(WDTO, timeout);
+	sc1200wdt_start();
 	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
-	
+
 	return 0;
 }
 
@@ -153,7 +161,8 @@
 {
 	int new_timeout;
 	static struct watchdog_info ident = {
-		options:		WDIOF_SETTIMEOUT,
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		firmware_version:	0,
 		identity:		"PC87307/PC97307"
 	};
 
@@ -168,7 +177,10 @@
 
 		case WDIOC_GETSTATUS:
 			return put_user(sc1200wdt_status(), (int *)arg);
-	
+
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *)arg);
+
 		case WDIOC_KEEPALIVE:
 			sc1200wdt_write_data(WDTO, timeout);
 			return 0;
@@ -188,22 +200,41 @@
 
 		case WDIOC_GETTIMEOUT:
 			return put_user(timeout * 60, (int *)arg);
+
+		case WDIOC_SETOPTIONS:
+		{
+			int options, retval = -EINVAL;
+
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+
+			if (options & WDIOS_DISABLECARD) {
+				sc1200wdt_stop();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				sc1200wdt_start();
+				retval = 0;
+			}
+
+			return retval;
+		}
 	}
 }
 
 
 static int sc1200wdt_release(struct inode *inode, struct file *file)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if (expect_close) {
-		sc1200wdt_write_data(WDTO, 0);
+	if (expect_close == 42) {
+		sc1200wdt_stop();
 		printk(KERN_INFO PFX "Watchdog disabled\n");
 	} else {
 		sc1200wdt_write_data(WDTO, timeout);
 		printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
-	}	
-#endif
+	}
 	up(&open_sem);
+	expect_close = 0;
 
 	return 0;
 }
@@ -223,7 +254,7 @@
 		for (i = 0; i != len; i++)
 		{
 			if (data[i] == 'V')
-				expect_close = 1;
+				expect_close = 42;
 		}
 #endif
 		sc1200wdt_write_data(WDTO, timeout);
@@ -237,7 +268,7 @@
 static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
 {
 	if (code == SYS_DOWN || code == SYS_HALT)
-		sc1200wdt_write_data(WDTO, 0);
+		sc1200wdt_stop();
 
 	return NOTIFY_DONE;
 }
@@ -261,7 +292,7 @@
 {
 	minor:		WATCHDOG_MINOR,
 	name:		"watchdog",
-	fops:		&sc1200wdt_fops
+	fops:		&sc1200wdt_fops,
 };
 
 
diff -urN linux-2.4.19-pre8/drivers/char/serial.c linux-2.4.19-pre9/drivers/char/serial.c
--- linux-2.4.19-pre8/drivers/char/serial.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/serial.c	Tue May 28 16:02:29 2002
@@ -4263,6 +4263,7 @@
 	pbn_b0_bt_2_115200,
 	pbn_b0_bt_1_460800,
 	pbn_b0_bt_2_460800,
+	pbn_b0_bt_2_921600,
 
 	pbn_b1_1_115200,
 	pbn_b1_2_115200,
@@ -4341,6 +4342,7 @@
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
 
 	{ SPCI_FL_BASE1, 1, 115200 },		/* pbn_b1_1_115200 */
 	{ SPCI_FL_BASE1, 2, 115200 },		/* pbn_b1_2_115200 */
@@ -4676,7 +4678,7 @@
 		pbn_b0_4_115200 },
 	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
-		pbn_b0_2_115200 },
+		pbn_b0_bt_2_921600 },
 
 	/* Digitan DS560-558, from jimd@esoft.com */
 	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
@@ -5635,7 +5637,7 @@
 	if (state->info && state->info->tty)
 		tty_hangup(state->info->tty);
 	state->type = PORT_UNKNOWN;
-	printk(KERN_INFO "tty%02d unloaded\n", state->line);
+	printk(KERN_INFO "ttyS%02d unloaded\n", state->line);
 	/* These will be hidden, because they are devices that will no longer
 	 * be available to the system. (ie, PCMCIA modems, once ejected)
 	 */
diff -urN linux-2.4.19-pre8/drivers/char/stallion.c linux-2.4.19-pre9/drivers/char/stallion.c
--- linux-2.4.19-pre8/drivers/char/stallion.c	Fri Sep 21 10:55:23 2001
+++ linux-2.4.19-pre9/drivers/char/stallion.c	Tue May 28 16:02:29 2002
@@ -188,14 +188,6 @@
  */
 static char		stl_unwanted[SC26198_RXFIFOSIZE];
 
-/*
- *	Keep track of what interrupts we have requested for us.
- *	We don't need to request an interrupt twice if it is being
- *	shared with another Stallion board.
- */
-static int	stl_gotintrs[STL_MAXBRDS];
-static int	stl_numintrs;
-
 /*****************************************************************************/
 
 static stlbrd_t		*stl_brds[STL_MAXBRDS];
@@ -520,7 +512,6 @@
 
 static int	stl_brdinit(stlbrd_t *brdp);
 static int	stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int	stl_mapirq(int irq, char *name);
 static void	stl_getserial(stlport_t *portp, struct serial_struct *sp);
 static int	stl_setserial(stlport_t *portp, struct serial_struct *sp);
 static int	stl_getbrdstats(combrd_t *bp);
@@ -836,6 +827,7 @@
 			}
 			kfree(panelp);
 		}
+		free_irq(brdp->irq, brdp);
 
 		release_region(brdp->ioaddr1, brdp->iosize1);
 		if (brdp->iosize2 > 0)
@@ -844,10 +836,6 @@
 		kfree(brdp);
 		stl_brds[i] = (stlbrd_t *) NULL;
 	}
-
-	for (i = 0; (i < stl_numintrs); i++)
-		free_irq(stl_gotintrs[i], NULL);
-
 	restore_flags(flags);
 }
 
@@ -2083,19 +2071,12 @@
 static void stl_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	stlbrd_t	*brdp;
-	int		i;
 
 #if DEBUG
 	printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);
 #endif
-
-	for (i = 0; (i < stl_nrbrds); i++) {
-		if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
-			continue;
-		if (brdp->state == 0)
-			continue;
-		(* brdp->isr)(brdp);
-	}
+	brdp = (stlbrd_t *) dev_id;
+	(* brdp->isr)(brdp);
 }
 
 /*****************************************************************************/
@@ -2270,39 +2251,6 @@
 /*****************************************************************************/
 
 /*
- *	Map in interrupt vector to this driver. Check that we don't
- *	already have this vector mapped, we might be sharing this
- *	interrupt across multiple boards.
- */
-
-static int __init stl_mapirq(int irq, char *name)
-{
-	int	rc, i;
-
-#if DEBUG
-	printk("stl_mapirq(irq=%d,name=%s)\n", irq, name);
-#endif
-
-	rc = 0;
-	for (i = 0; (i < stl_numintrs); i++) {
-		if (stl_gotintrs[i] == irq)
-			break;
-	}
-	if (i >= stl_numintrs) {
-		if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
-			printk("STALLION: failed to register interrupt "
-				"routine for %s irq=%d\n", name, irq);
-			rc = -ENODEV;
-		} else {
-			stl_gotintrs[stl_numintrs++] = irq;
-		}
-	}
-	return(rc);
-}
-
-/*****************************************************************************/
-
-/*
  *	Initialize all the ports on a panel.
  */
 
@@ -2484,7 +2432,12 @@
 	brdp->nrpanels = 1;
 	brdp->state |= BRD_FOUND;
 	brdp->hwid = status;
-	rc = stl_mapirq(brdp->irq, name);
+	if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) {
+		printk("STALLION: failed to register interrupt "
+		       "routine for %s irq=%d\n", name, brdp->irq);
+		rc = -ENODEV;
+	}
+
 	return(rc);
 }
 
@@ -2684,7 +2637,12 @@
 		outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
 
 	brdp->state |= BRD_FOUND;
-	i = stl_mapirq(brdp->irq, name);
+	if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) {
+		printk("STALLION: failed to register interrupt "
+		       "routine for %s irq=%d\n", name, brdp->irq);
+		i = -ENODEV;
+	}
+
 	return(i);
 }
 
diff -urN linux-2.4.19-pre8/drivers/char/sysrq.c linux-2.4.19-pre9/drivers/char/sysrq.c
--- linux-2.4.19-pre8/drivers/char/sysrq.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/char/sysrq.c	Tue May 28 16:02:29 2002
@@ -186,7 +186,7 @@
  * block devices and malfunctional network filesystems.
  */
 
-int emergency_sync_scheduled;
+volatile int emergency_sync_scheduled;
 
 void do_emergency_sync(void) {
 	struct super_block *sb;
diff -urN linux-2.4.19-pre8/drivers/i2c/i2c-core.c linux-2.4.19-pre9/drivers/i2c/i2c-core.c
--- linux-2.4.19-pre8/drivers/i2c/i2c-core.c	Mon Nov  5 18:15:40 2001
+++ linux-2.4.19-pre9/drivers/i2c/i2c-core.c	Tue May 28 16:02:29 2002
@@ -381,10 +381,10 @@
 						printk("i2c-core.o: while "
 						       "unregistering driver "
 						       "`%s', the client at "
-						       "address %02x of
-						       adapter `%s' could not
-						       be detached; driver
-						       not unloaded!",
+						       "address %02x of "
+						       "adapter `%s' could not"
+						       "be detached; driver"
+						       "not unloaded!",
 						       driver->name,
 						       client->addr,
 						       adap->name);
diff -urN linux-2.4.19-pre8/drivers/ide/Config.in linux-2.4.19-pre9/drivers/ide/Config.in
--- linux-2.4.19-pre8/drivers/ide/Config.in	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/ide/Config.in	Tue May 28 16:02:29 2002
@@ -71,7 +71,7 @@
 	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
   	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
 	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
diff -urN linux-2.4.19-pre8/drivers/isdn/hisax/Makefile linux-2.4.19-pre9/drivers/isdn/hisax/Makefile
--- linux-2.4.19-pre8/drivers/isdn/hisax/Makefile	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/isdn/hisax/Makefile	Tue May 28 16:02:29 2002
@@ -10,7 +10,7 @@
 
 # Objects that export symbols.
 
-export-objs	  := config.o fsm.o hisax_isac.o
+export-objs	  := config.o hisax_isac.o
 
 # Multipart objects.
 
diff -urN linux-2.4.19-pre8/drivers/isdn/hisax/config.c linux-2.4.19-pre9/drivers/isdn/hisax/config.c
--- linux-2.4.19-pre8/drivers/isdn/hisax/config.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre9/drivers/isdn/hisax/config.c	Tue May 28 16:02:29 2002
@@ -2150,3 +2150,11 @@
 
 module_init(HiSax_init);
 module_exit(HiSax_exit);
+
+EXPORT_SYMBOL(FsmNew);
+EXPORT_SYMBOL(FsmFree);
+EXPORT_SYMBOL(FsmEvent);
+EXPORT_SYMBOL(FsmChangeState);
+EXPORT_SYMBOL(FsmInitTimer);
+EXPORT_SYMBOL(FsmDelTimer);
+EXPORT_SYMBOL(FsmRestartTimer);
diff -urN linux-2.4.19-pre8/drivers/isdn/hisax/fsm.c linux-2.4.19-pre9/drivers/isdn/hisax/fsm.c
--- linux-2.4.19-pre8/drivers/isdn/hisax/fsm.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre9/drivers/isdn/hisax/fsm.c	Tue May 28 16:02:29 2002
@@ -21,14 +21,6 @@
 
 #define FSM_TIMER_DEBUG 0
 
-EXPORT_SYMBOL(FsmNew);
-EXPORT_SYMBOL(FsmFree);
-EXPORT_SYMBOL(FsmEvent);
-EXPORT_SYMBOL(FsmChangeState);
-EXPORT_SYMBOL(FsmInitTimer);
-EXPORT_SYMBOL(FsmDelTimer);
-EXPORT_SYMBOL(FsmRestartTimer);
-
 int __init
 FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
 {
diff -urN linux-2.4.19-pre8/drivers/isdn/hisax/md5sums.asc linux-2.4.19-pre9/drivers/isdn/hisax/md5sums.asc
--- linux-2.4.19-pre8/drivers/isdn/hisax/md5sums.asc	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre9/drivers/isdn/hisax/md5sums.asc	Tue May 28 16:02:29 2002
@@ -21,13 +21,13 @@
 3d22d2f2fe9af693eb3b471beecf596d  elsa.c
 fd6aedade5b5bbd73683a3de878b76d2  diva.c
 def8d69efd25186878dc123df73d9319  sedlbauer.c
-6c5bd0fdc59f33319823fa5367357983  hfc_pci.c
+8200d818771e3cbdef2a3c3e818d25ac  hfc_pci.c
 # end of md5sums
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.0.6 (GNU/Linux)
 Comment: For info see http://www.gnupg.org
 
-iD8DBQE8UYO9DiY0VZsg4ukRAqLzAKCKK7rFSNAWpBMtpJZ0kYvF+y+b1wCZAY8u
-hf6AL732sGhUsfRpwwdENVU=
-=B3yd
+iD8DBQE86l0pDiY0VZsg4ukRAt5eAKCjKt86NE4seQTp88McDaifcz8O8gCguMp3
+56AcQOgPpMtw0OpcYCY+iS8=
+=tfsn
 -----END PGP SIGNATURE-----
diff -urN linux-2.4.19-pre8/drivers/isdn/isdn_ppp.c linux-2.4.19-pre9/drivers/isdn/isdn_ppp.c
--- linux-2.4.19-pre8/drivers/isdn/isdn_ppp.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre9/drivers/isdn/isdn_ppp.c	Tue May 28 16:02:29 2002
@@ -1786,8 +1786,10 @@
 	memset(&t, 0, sizeof(struct ppp_stats));
 	if (dev->flags & IFF_UP) {
 		t.p.ppp_ipackets = lp->stats.rx_packets;
+		t.p.ppp_ibytes = lp->stats.rx_bytes;
 		t.p.ppp_ierrors = lp->stats.rx_errors;
 		t.p.ppp_opackets = lp->stats.tx_packets;
+		t.p.ppp_obytes = lp->stats.tx_bytes;
 		t.p.ppp_oerrors = lp->stats.tx_errors;
 #ifdef CONFIG_ISDN_PPP_VJ
 		if (slot >= 0 && ippp_table[slot]->slcomp) {
diff -urN linux-2.4.19-pre8/drivers/md/md.c linux-2.4.19-pre9/drivers/md/md.c
--- linux-2.4.19-pre8/drivers/md/md.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/md/md.c	Tue May 28 16:02:29 2002
@@ -3332,6 +3332,10 @@
 	wake_up(&mddev->recovery_wait);
 	if (!ok) {
 		// stop recovery, signal do_sync ....
+		if (mddev->pers->stop_resync)
+			mddev->pers->stop_resync(mddev);
+		if (mddev->recovery_running)
+			md_interrupt_thread(md_recovery_thread);
 	}
 }
 
diff -urN linux-2.4.19-pre8/drivers/media/video/planb.c linux-2.4.19-pre9/drivers/media/video/planb.c
--- linux-2.4.19-pre8/drivers/media/video/planb.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre9/drivers/media/video/planb.c	Tue May 28 16:02:29 2002
@@ -1,14 +1,17 @@
 /* 
-    planb - PlanB frame grabber driver
+    planb - v4l-compatible frame grabber driver for the PlanB hardware
 
     PlanB is used in the 7x00/8x00 series of PowerMacintosh
     Computers as video input DMA controller.
 
-    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+    Copyright (C) 1998 - 2002  Michel Lanners <mailto:mlan@cpu.lu>
 
-    Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
+    Based largely on the old bttv driver by Ralph Metzler
+
+    Additional debugging and coding by Takashi Oe <mailto:toe@unlserve.unl.edu>
+
+    For more information, see <http://www.cpu.lu/~mlan/planb.html>
 
-    Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
 
     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
@@ -25,7 +28,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
+/* $Id: planb.c,v 2.11 2002/04/03 15:57:57 mlan Exp mlan $ */
 
 #include <linux/version.h>
 #include <linux/init.h>
@@ -40,6 +43,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/poll.h>
 #include <linux/wrapper.h>
 #include <linux/tqueue.h>
 #include <linux/videodev.h>
@@ -52,37 +56,41 @@
 #include <asm/irq.h>
 #include <asm/semaphore.h>
 
-#include "planb.h"
-#include "saa7196.h"
+/* Define these to get general / interrupt debugging */
+#undef DEBUG
+#undef IDEBUG
 
-/* Would you mind for some ugly debugging? */
-#if 0
-#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
+//#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(KERN_DEBUG ## x)
 #else
-#define DEBUG(x...) 		/* Don't debug driver */
+#define DBG(x...)
 #endif
-
-#if 0
-#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
+#ifdef IDEBUG
+#define IDBG(x...) printk(KERN_DEBUG ## x)
 #else
-#define IDEBUG(x...) 		/* Don't debug interrupt part */
+#define IDBG(x...)
 #endif
 
-/* Ever seen a Mac with more than 1 of these? */
-#define PLANB_MAX 1
+#include "planb.h"
+#include "saa7196.h"
 
-static int planb_num;
-static struct planb planbs[PLANB_MAX];
+static struct planb planbs;
 static volatile struct planb_registers *planb_regs;
 
 static int def_norm = PLANB_DEF_NORM;	/* default norm */
 static int video_nr = -1;
+static int vbi_nr = -1;
 
 MODULE_PARM(def_norm, "i");
 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
 MODULE_PARM(video_nr,"i");
-MODULE_LICENSE("GPL");
+MODULE_PARM(vbi_nr,"i");
 
+MODULE_DESCRIPTION("planb - v4l driver module for Apple PlanB video in");
+MODULE_AUTHOR("Michel Lanners & Takashi Oe - see: http://www.cpu.lu/planb.html");
+MODULE_LICENSE("GPL");
 
 /* ------------------ PlanB Exported Functions ------------------ */
 static long planb_write(struct video_device *, const char *, unsigned long, int);
@@ -92,12 +100,23 @@
 static int planb_ioctl(struct video_device *, unsigned int, void *);
 static int planb_mmap(struct video_device *, const char *, unsigned long);
 static void planb_irq(int, void *, struct pt_regs *);
+static int planb_vbi_open(struct video_device *, int);
+static void planb_vbi_close(struct video_device *);
+static long planb_vbi_read(struct video_device *, char *, unsigned long, int);
+static unsigned int planb_vbi_poll(struct video_device *, struct file *,
+	poll_table *);
+static int planb_vbi_ioctl(struct video_device *, unsigned int, void *);
 static void release_planb(void);
-static int init_planbs(void);
+static int __init init_planbs(void);
+static void __exit exit_planbs(void);
 
 /* ------------------ PlanB Internal Functions ------------------ */
 static int planb_prepare_open(struct planb *);
+static int planb_prepare_vbi(struct planb *);
+static int planb_prepare_video(struct planb *);
 static void planb_prepare_close(struct planb *);
+static void planb_close_vbi(struct planb *);
+static void planb_close_video(struct planb *);
 static void saa_write_reg(unsigned char, unsigned char);
 static unsigned char saa_status(int, struct planb *);
 static void saa_set(unsigned char, unsigned char, struct planb *);
@@ -107,28 +126,41 @@
 static void add_clip(struct planb *, struct video_clip *);
 static void fill_cmd_buff(struct planb *);
 static void cmd_buff(struct planb *);
-static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
+static dbdma_cmd_ptr setup_grab_cmd(int, struct planb *);
 static void overlay_start(struct planb *);
 static void overlay_stop(struct planb *);
-static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
-	unsigned int);
-static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
-	unsigned int);
-static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
-	unsigned short, unsigned int, unsigned int);
+static inline void tab_cmd_dbdma(dbdma_cmd_ptr, unsigned short, unsigned int);
+static inline void tab_cmd_store(dbdma_cmd_ptr, unsigned int, unsigned int);
+static inline void tab_cmd_gen(dbdma_cmd_ptr, unsigned short, unsigned short,
+	unsigned int, unsigned int);
 static int init_planb(struct planb *);
 static int find_planb(void);
-static void planb_pre_capture(int, int, struct planb *);
-static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
-					int, int, int, int, int, struct planb *);
-static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
-static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
+static void planb_pre_capture(int, struct planb *);
+static dbdma_cmd_ptr cmd_geo_setup(dbdma_cmd_ptr, int, int, int, int, int,
+	struct planb *);
+static inline void planb_dbdma_stop(dbdma_regs_ptr);
+static inline void planb_dbdma_restart(dbdma_regs_ptr);
+static void saa_geo_setup(int, int, int, int, struct planb *);
 static inline int overlay_is_active(struct planb *);
 
 /*******************************/
 /* Memory management functions */
 /*******************************/
 
+/* I know this is not the right way to allocate memory. Whoever knows
+ * the right way to allocate a huge buffer for DMA that can be mapped
+ * to user space, please tell me... or better, fix the code and send
+ * patches.
+ *
+ *					Michel Lanners (mlan@cpu.lu)
+ */
+/* FIXME: As subsequent calls to __get_free_pages don't necessarily return
+ * contiguous pages, we need to do horrible things later on when setting
+ * up DMA, to make sure a single DMA transfer doesn't cross a page boundary.
+ * At least, I hope it's done right later on ;-) ......
+ * Anyway, there should be a way to get hold of a large buffer of contiguous
+ * pages for DMA....
+ */
 static int grabbuf_alloc(struct planb *pb)
 {
 	int i, npage;
@@ -142,14 +174,14 @@
 				* sizeof(unsigned long), GFP_KERNEL)) == 0)
 		return -ENOMEM;
 	for (i = 0; i < npage; i++) {
-		pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
-								|GFP_DMA, 0);
+		pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL |
+								GFP_DMA, 0);
 		if (!pb->rawbuf[i])
 			break;
 		mem_map_reserve(virt_to_page(pb->rawbuf[i]));
 	}
 	if (i-- < npage) {
-		printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
+		DBG("PlanB: init_grab: grab buffer not allocated\n");
 		for (; i > 0; i--) {
 			mem_map_unreserve(virt_to_page(pb->rawbuf[i]));
 			free_pages((unsigned long)pb->rawbuf[i], 0);
@@ -157,7 +189,7 @@
 		kfree(pb->rawbuf);
 		return -ENOBUFS;
 	}
-	pb->rawbuf_size = npage;
+	pb->rawbuf_nchunks = npage;
 	return 0;
 }
 
@@ -181,12 +213,7 @@
 
 	/* Let's wait 30msec for this one */
 	current->state = TASK_INTERRUPTIBLE;
-#if LINUX_VERSION_CODE >= 0x02017F
 	schedule_timeout(30 * HZ / 1000);
-#else
-	current->timeout = jiffies + 30 * HZ / 1000;	/* 30 ms */;
-	schedule();
-#endif
 
 	return (unsigned char)in_8 (&planb_regs->saa_status);
 }
@@ -208,25 +235,15 @@
 		saa_write_reg (i, saa_regs[pb->win.norm][i]);
 }
 
-static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
-	struct planb *pb)
+static void saa_geo_setup(int width, int height, int interlace,
+	int fmt, struct planb *pb)
 {
 	int ht, norm = pb->win.norm;
 
-	switch(bpp) {
-	case 2:
-		/* RGB555+a 1x16-bit + 16-bit transparent */
-		saa_regs[norm][SAA7196_FMTS] &= ~0x3;
-		break;
-	case 1:
-	case 4:
-		/* RGB888 1x24-bit + 8-bit transparent */
-		saa_regs[norm][SAA7196_FMTS] &= ~0x1;
-		saa_regs[norm][SAA7196_FMTS] |= 0x2;
-		break;
-	default:
-		return -EINVAL;
-	}
+	/* bits FS0, FS1 according to format spec */
+	saa_regs[norm][SAA7196_FMTS] &= ~0x3;
+	saa_regs[norm][SAA7196_FMTS] |= (palette2fmt[fmt].saa_fmt & 0x3);
+
 	ht = (interlace ? height / 2 : height);
 	saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);
 	saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)
@@ -240,93 +257,99 @@
 					: (saa_regs[norm][SAA7196_FMTS] | 0x60);
 	/* transparent mode; extended format enabled */
 	saa_regs[norm][SAA7196_DPATH] |= 0x3;
-
-	return 0;
+	/* bits LLV, MCT according to format spec */
+	saa_regs[norm][SAA7196_DPATH] &= ~0x30;
+	saa_regs[norm][SAA7196_DPATH] |= (palette2fmt[fmt].saa_fmt & 0x30);
 }
 
 /***************************/
 /* DBDMA support functions */
 /***************************/
 
-static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
+static inline void planb_dbdma_restart(dbdma_regs_ptr ch)
 {
-	out_le32(&ch->control, PLANB_CLR(RUN));
-	out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
+	writel(PLANB_CLR(RUN), &ch->control);
+	writel(PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE), &ch->control);
 }
 
-static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
+static inline void planb_dbdma_stop(dbdma_regs_ptr ch)
 {
 	int i = 0;
 
-	out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));
-	while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
-		IDEBUG("PlanB: waiting for DMA to stop\n");
+	writel(PLANB_CLR(RUN) | PLANB_SET(FLUSH), &ch->control);
+	while((readl(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
+		IDBG("PlanB: waiting for DMA to stop\n");
 		i++;
 	}
 }
 
-static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
-	unsigned short command, unsigned int cmd_dep)
+static inline void tab_cmd_dbdma(dbdma_cmd_ptr ch, unsigned short command,
+	unsigned int cmd_dep)
 {
 	st_le16(&ch->command, command);
+	st_le16(&ch->req_count, 0);
+	st_le32(&ch->phy_addr, 0);
 	st_le32(&ch->cmd_dep, cmd_dep);
+	/* really clears res_count & xfer_status */
+	st_le32((unsigned int *)&ch->res_count, 0);
 }
 
-static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
-	unsigned int phy_addr, unsigned int cmd_dep)
+static inline void tab_cmd_store(dbdma_cmd_ptr ch, unsigned int phy_addr,
+	unsigned int cmd_dep)
 {
 	st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);
 	st_le16(&ch->req_count, 4);
 	st_le32(&ch->phy_addr, phy_addr);
 	st_le32(&ch->cmd_dep, cmd_dep);
+	st_le32((unsigned int *)&ch->res_count, 0);
 }
 
-static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,
-	unsigned short command, unsigned short req_count,
-	unsigned int phy_addr, unsigned int cmd_dep)
+static inline void tab_cmd_gen(dbdma_cmd_ptr ch, unsigned short command,
+	unsigned short req_count, unsigned int phy_addr, unsigned int cmd_dep)
 {
 	st_le16(&ch->command, command);
 	st_le16(&ch->req_count, req_count);
 	st_le32(&ch->phy_addr, phy_addr);
 	st_le32(&ch->cmd_dep, cmd_dep);
+	st_le32((unsigned int *)&ch->res_count, 0);
 }
 
-static volatile struct dbdma_cmd *cmd_geo_setup(
-	volatile struct dbdma_cmd *c1, int width, int height, int interlace,
-	int bpp, int clip, struct planb *pb)
+static dbdma_cmd_ptr cmd_geo_setup(dbdma_cmd_ptr c1, int width, int height,
+	int interlace, int fmt, int clip, struct planb *pb)
 {
 	int norm = pb->win.norm;
 
-	if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)
-		return (volatile struct dbdma_cmd *)NULL;
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
-							SAA7196_FMTS);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
-					saa_regs[norm][SAA7196_FMTS]);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
-							SAA7196_DPATH);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
-					saa_regs[norm][SAA7196_DPATH]);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),
-					bpp | ((clip)? PLANB_CLIPMASK: 0));
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),
-					bpp | ((clip)? PLANB_CLIPMASK: 0));
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
-							SAA7196_OUTPIX);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
-					saa_regs[norm][SAA7196_OUTPIX]);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
-							SAA7196_HFILT);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
-					saa_regs[norm][SAA7196_HFILT]);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+	saa_geo_setup(width, height, interlace, fmt, pb);
+	/* if the number of DBDMA commands here (14) changes, lots of
+	 * things need to be corrected accordingly... */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
+								SAA7196_FMTS);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
+						saa_regs[norm][SAA7196_FMTS]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
+								SAA7196_DPATH);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
+						saa_regs[norm][SAA7196_DPATH]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->even),
+			palette2fmt[fmt].pb_fmt | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->odd),
+			palette2fmt[fmt].pb_fmt | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
+								SAA7196_OUTPIX);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
+						saa_regs[norm][SAA7196_OUTPIX]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
+								SAA7196_HFILT);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
+						saa_regs[norm][SAA7196_HFILT]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
 							SAA7196_OUTLINE);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
 					saa_regs[norm][SAA7196_OUTLINE]);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
-							SAA7196_VYP);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
-					saa_regs[norm][SAA7196_VYP]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_addr),
+								SAA7196_VYP);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->saa_regval),
+						saa_regs[norm][SAA7196_VYP]);
 	return c1;
 }
 
@@ -336,11 +359,13 @@
 
 static inline void planb_lock(struct planb *pb)
 {
+	DBG("PlanB: planb_lock\n");
 	down(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
+	DBG("PlanB: planb_unlock\n");
 	up(&pb->lock);
 }
 
@@ -348,47 +373,116 @@
 /* Driver Core */
 /***************/
 
+/* number of entries in the circular DBDMA command buffer
+ * initial stop, odd/even vbi, odd/even video, branch back */
+#define NUMJUMPS 6
 static int planb_prepare_open(struct planb *pb)
 {
+	dbdma_cmd_ptr	c;
+	int		size, i;
+
+	size = (NUMJUMPS + 1) * sizeof(struct dbdma_cmd);
+
+	if((pb->jump_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0)
+		return -ENOMEM;
+	memset(pb->jump_raw, 0, size);
+	c = pb->jumpbuf = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->jump_raw);
+
+	/* circular DBDMA command buffer, to hold jumps to transfer commands */
+	tab_cmd_dbdma(c++, DBDMA_STOP, 0);
+	for (i=1; i<NUMJUMPS-1; i++)
+		tab_cmd_dbdma(c++, DBDMA_NOP, 0);
+	tab_cmd_dbdma(c, DBDMA_NOP|BR_ALWAYS,
+		(unsigned int)pb->jumpbuf);
+
+	DBG("PlanB: planb_prepare_open, jumpbuffer at 0x%08x, length %d.\n",
+		(unsigned int)pb->jumpbuf, size); 
+	return 0;
+}
+
+#define VBIDUMMY 40	/* must be even !! */
+static int planb_prepare_vbi(struct planb *pb)
+{
+	int	size;
+
+	/* allocate VBI comand buffer memory
+	   (2 fields * VBI_MAXLINES + 40 handling + alignment) */
+	size = (2*VBI_MAXLINES + VBIDUMMY + 1) * sizeof(struct dbdma_cmd);
+
+	if ((pb->vbi_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0)
+		return -ENOMEM;
+	memset (pb->vbi_raw, 0, size);
+	size = (VBI_MAXLINES + VBIDUMMY/2) * sizeof(struct dbdma_cmd);
+	pb->vbi_cbo.start = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->vbi_raw);
+	pb->vbi_cbo.size = pb->vbi_cbe.size = size;
+	pb->vbi_cbe.start = pb->vbi_cbo.start + pb->vbi_cbo.size;
+	pb->vbi_cbo.jumpaddr = pb->jumpbuf + 1;
+	pb->vbi_cbe.jumpaddr = pb->jumpbuf + 3;
+
+	DBG("PlanB: planb_prepare_vbi, dbdma cmd_buf at 0x%08x, length %d.\n",
+		(unsigned int)pb->vbi_cbo.start, 2*size); 
+	return 0;
+}
+
+static int planb_prepare_video(struct planb *pb)
+{
 	int	i, size;
 
+	/* FIXME: This is stressing kmalloc to its limits...
+		  We really should allocate smaller chunks. */
+
 	/* allocate memory for two plus alpha command buffers (size: max lines,
 	   plus 40 commands handling, plus 1 alignment), plus dummy command buf,
 	   plus clipmask buffer, plus frame grabbing status */
-	size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS
-		* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
-		+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
-		+MAX_GBUFFERS*sizeof(unsigned int);
-	if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+	size = (pb->tab_size * (2 + MAX_GBUFFERS * TAB_FACTOR)
+		    + MAX_GBUFFERS * PLANB_DUMMY + 1) * sizeof(struct dbdma_cmd)
+		+ (PLANB_MAXLINES * ((PLANB_MAXPIXELS + 7) & ~7)) / 8
+		+ MAX_GBUFFERS * sizeof(unsigned int);
+	if ((pb->vid_raw = kmalloc (size, GFP_KERNEL|GFP_DMA)) == 0)
 		return -ENOMEM;
-	memset ((void *) pb->priv_space, 0, size);
-	pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
-						DBDMA_ALIGN (pb->priv_space);
-	pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
-	pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
-	pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
-	pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
+	memset (pb->vid_raw, 0, size);
+	pb->vid_cbo.start = (dbdma_cmd_ptr) DBDMA_ALIGN (pb->vid_raw);
+	pb->vid_cbo.size = pb->vid_cbe.size = pb->tab_size/2;
+	pb->vid_cbe.start = pb->vid_cbo.start + pb->vid_cbo.size;
+	pb->vid_cbo.jumpaddr = pb->jumpbuf + 2;
+	pb->vid_cbe.jumpaddr = pb->jumpbuf + 4;
+	pb->overlay_last1 = pb->vid_cbo.start;
+	pb->vid_cbo.bus = virt_to_bus(pb->vid_cbo.start);
+	pb->vid_cbe.bus = virt_to_bus(pb->vid_cbe.start);
+	pb->clip_cbo.start = pb->vid_cbe.start + pb->vid_cbe.size;
+	pb->clip_cbo.size = pb->clip_cbe.size = pb->tab_size/2;
+	pb->clip_cbe.start = pb->clip_cbo.start + pb->clip_cbo.size;
+	pb->overlay_last2 = pb->clip_cbo.start;
+	pb->clip_cbo.bus = virt_to_bus(pb->clip_cbo.start);
+	pb->clip_cbe.bus = virt_to_bus(pb->clip_cbe.start);
+	pb->gbuf[0].cap_cmd = pb->clip_cbe.start + pb->clip_cbe.size;
+	pb->gbuf[0].pre_cmd = pb->gbuf[0].cap_cmd + pb->tab_size * TAB_FACTOR;
 	for (i = 1; i < MAX_GBUFFERS; i++) {
-		pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
-		pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
-	}
-	pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
-						+ PLANB_DUMMY);
-	pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
+		pb->gbuf[i].cap_cmd = pb->gbuf[i-1].pre_cmd + PLANB_DUMMY;
+		pb->gbuf[i].pre_cmd = pb->gbuf[i].cap_cmd +
+						pb->tab_size * TAB_FACTOR;
+	}
+	pb->gbuf[0].status = (volatile unsigned int *)
+			(pb->gbuf[MAX_GBUFFERS-1].pre_cmd + PLANB_DUMMY);
+	for (i = 1; i < MAX_GBUFFERS; i++)
+		pb->gbuf[i].status = pb->gbuf[i-1].status;
+	pb->mask = (unsigned char *)(pb->gbuf[MAX_GBUFFERS-1].status + 1);
 
 	pb->rawbuf = NULL;
-	pb->rawbuf_size = 0;
+	pb->rawbuf_nchunks = 0;
 	pb->grabbing = 0;
 	for (i = 0; i < MAX_GBUFFERS; i++) {
-		pb->frame_stat[i] = GBUFFER_UNUSED;
-		pb->gwidth[i] = 0;
-		pb->gheight[i] = 0;
-		pb->gfmt[i] = 0;
-		pb->gnorm_switch[i] = 0;
+		gbuf_ptr	gbuf = &pb->gbuf[i];
+
+		*gbuf->status = GBUFFER_UNUSED;
+		gbuf->width = 0;
+		gbuf->height = 0;
+		gbuf->fmt = 0;
+		gbuf->norm_switch = 0;
 #ifndef PLANB_GSCANLINE
-		pb->lsize[i] = 0;
-		pb->lnum[i] = 0;
-#endif /* PLANB_GSCANLINE */
+		gbuf->lsize = 0;
+		gbuf->lnum = 0;
+#endif
 	}
 	pb->gcount = 0;
 	pb->suspend = 0;
@@ -399,30 +493,74 @@
 	planb_dbdma_stop(&pb->planb_base->ch2);
 	planb_dbdma_stop(&pb->planb_base->ch1);
 
+	DBG("PlanB: planb_prepare_video, dbdma cmd_buf at 0x%08x, "
+		"length %d.\n", (unsigned int)pb->vid_cbo.start, 2*size);
 	return 0;
 }
 
 static void planb_prepare_close(struct planb *pb)
 {
-	int i;
-
 	/* make sure the dma's are idle */
 	planb_dbdma_stop(&pb->planb_base->ch2);
 	planb_dbdma_stop(&pb->planb_base->ch1);
-	/* free kernel memory of command buffers */
-	if(pb->priv_space != 0) {
-		kfree (pb->priv_space);
-		pb->priv_space = 0;
+
+	if(pb->jump_raw != 0) {
+		kfree(pb->jump_raw);
+		pb->jump_raw = 0;
+	}
+	return;
+}
+
+static void planb_close_vbi(struct planb *pb)
+{
+	/* FIXME: stop running DMA */
+
+	/* Make sure the DMA controller doesn't jump here anymore */
+	tab_cmd_dbdma(pb->vbi_cbo.jumpaddr, DBDMA_NOP, 0);
+	tab_cmd_dbdma(pb->vbi_cbe.jumpaddr, DBDMA_NOP, 0);
+
+	if(pb->vbi_raw != 0) {
+		kfree (pb->vbi_raw);
+		pb->vbi_raw = 0;
+	}
+
+	/* FIXME: deallocate VBI data buffer */
+
+	/* FIXME: restart running DMA if app. */
+	return;
+}
+
+static void planb_close_video(struct planb *pb)
+{
+	int i;
+
+	/* FIXME: stop running DMA */
+
+	/* Make sure the DMA controller doesn't jump here anymore */
+	tab_cmd_dbdma(pb->vid_cbo.jumpaddr, DBDMA_NOP, 0);
+	tab_cmd_dbdma(pb->vid_cbe.jumpaddr, DBDMA_NOP, 0);
+/* No clipmask jumpbuffer yet  */
+#if 0
+	tab_cmd_dbdma(pb->clip_cbo.jumpaddr, DBDMA_NOP, 0);
+	tab_cmd_dbdma(pb->clip_cbe.jumpaddr, DBDMA_NOP, 0);
+#endif
+
+	if(pb->vid_raw != 0) {
+		kfree (pb->vid_raw);
+		pb->vid_raw = 0;
 		pb->cmd_buff_inited = 0;
 	}
 	if(pb->rawbuf) {
-		for (i = 0; i < pb->rawbuf_size; i++) {
+		for (i = 0; i < pb->rawbuf_nchunks; i++) {
 			mem_map_unreserve(virt_to_page(pb->rawbuf[i]));
 			free_pages((unsigned long)pb->rawbuf[i], 0);
 		}
 		kfree(pb->rawbuf);
 	}
 	pb->rawbuf = NULL;
+
+	/* FIXME: restart running DMA if app. */
+	return;
 }
 
 /*****************************/
@@ -431,43 +569,37 @@
 
 static void overlay_start(struct planb *pb)
 {
+	DBG("PlanB: overlay_start()\n");
 
-	DEBUG("PlanB: overlay_start()\n");
-
-	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+	if(ACTIVE & readl(&pb->planb_base->ch1.status)) {
 
-		DEBUG("PlanB: presumably, grabbing is in progress...\n");
+		DBG("PlanB: presumably, grabbing is in progress...\n");
 
 		planb_dbdma_stop(&pb->planb_base->ch2);
-		out_le32 (&pb->planb_base->ch2.cmdptr,
-						virt_to_bus(pb->ch2_cmd));
+		writel(pb->clip_cbo.bus, &pb->planb_base->ch2.cmdptr);
 		planb_dbdma_restart(&pb->planb_base->ch2);
-		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
-		tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
-					DBDMA_NOP | BR_ALWAYS,
-					virt_to_bus(pb->ch1_cmd));
+		st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP);
+		tab_cmd_dbdma(pb->gbuf[pb->last_fr].last_cmd,
+			DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus);
 		eieio();
 		pb->prev_last_fr = pb->last_fr;
 		pb->last_fr = -2;
-		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
-			IDEBUG("PlanB: became inactive "
+		if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) {
+			IDBG("PlanB: became inactive "
 				"in the mean time... reactivating\n");
 			planb_dbdma_stop(&pb->planb_base->ch1);
-			out_le32 (&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->ch1_cmd));
+			writel(pb->vid_cbo.bus, &pb->planb_base->ch1.cmdptr);
 			planb_dbdma_restart(&pb->planb_base->ch1);
 		}
 	} else {
 
-		DEBUG("PlanB: currently idle, so can do whatever\n");
+		DBG("PlanB: currently idle, so can do whatever\n");
 
 		planb_dbdma_stop(&pb->planb_base->ch2);
 		planb_dbdma_stop(&pb->planb_base->ch1);
-		st_le32 (&pb->planb_base->ch2.cmdptr,
-						virt_to_bus(pb->ch2_cmd));
-		st_le32 (&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->ch1_cmd));
-		out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		st_le32(&pb->planb_base->ch2.cmdptr, pb->clip_cbo.bus);
+		st_le32(&pb->planb_base->ch1.cmdptr, pb->vid_cbo.bus);
+		writew(DBDMA_NOP, &pb->vid_cbo.start->command);
 		planb_dbdma_restart(&pb->planb_base->ch2);
 		planb_dbdma_restart(&pb->planb_base->ch1);
 		pb->last_fr = -1;
@@ -477,29 +609,29 @@
 
 static void overlay_stop(struct planb *pb)
 {
-	DEBUG("PlanB: overlay_stop()\n");
+	DBG("PlanB: overlay_stop()\n");
 
 	if(pb->last_fr == -1) {
 
-		DEBUG("PlanB: no grabbing, it seems...\n");
+		DBG("PlanB: no grabbing, it seems...\n");
 
 		planb_dbdma_stop(&pb->planb_base->ch2);
 		planb_dbdma_stop(&pb->planb_base->ch1);
 		pb->last_fr = -999;
 	} else if(pb->last_fr == -2) {
 		unsigned int cmd_dep;
-		tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
+		tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].cap_cmd, DBDMA_STOP, 0);
 		eieio();
-		cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
+		cmd_dep = (unsigned int)readl(&pb->overlay_last1->cmd_dep);
 		if(overlay_is_active(pb)) {
 
-			DEBUG("PlanB: overlay is currently active\n");
+			DBG("PlanB: overlay is currently active\n");
 
 			planb_dbdma_stop(&pb->planb_base->ch2);
 			planb_dbdma_stop(&pb->planb_base->ch1);
-			if(cmd_dep != pb->ch1_cmd_phys) {
-				out_le32(&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->overlay_last1));
+			if(cmd_dep != pb->vid_cbo.bus) {
+				writel(virt_to_bus(pb->overlay_last1),
+					&pb->planb_base->ch1.cmdptr);
 				planb_dbdma_restart(&pb->planb_base->ch1);
 			}
 		}
@@ -514,15 +646,15 @@
 	int fr = -1;
 	struct dbdma_cmd last;
 
-	DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
+	DBG("PlanB: suspend_overlay: %d\n", pb->suspend);
 
 	if(pb->suspend++)
 		return;
-	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+	if(ACTIVE & readl(&pb->planb_base->ch1.status)) {
 		if(pb->last_fr == -2) {
 			fr = pb->prev_last_fr;
-			memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
-			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+			memcpy(&last, (void*)pb->gbuf[fr].last_cmd, sizeof(last));
+			tab_cmd_dbdma(pb->gbuf[fr].last_cmd, DBDMA_STOP, 0);
 		}
 		if(overlay_is_active(pb)) {
 			planb_dbdma_stop(&pb->planb_base->ch2);
@@ -542,38 +674,38 @@
 static void resume_overlay(struct planb *pb)
 {
 
-	DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
+	DBG("PlanB: resume_overlay: %d\n", pb->suspend);
 
 	if(pb->suspend > 1)
 		return;
 	if(pb->suspended.frame != -1) {
-		memcpy((void*)pb->last_cmd[pb->suspended.frame],
-				&pb->suspended.cmd, sizeof(pb->suspended.cmd));
+		memcpy((void*)pb->gbuf[pb->suspended.frame].last_cmd,
+			&pb->suspended.cmd, sizeof(pb->suspended.cmd));
 	}
-	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+	if(ACTIVE & readl(&pb->planb_base->ch1.status)) {
 		goto finish;
 	}
 	if(pb->suspended.overlay) {
 
-		DEBUG("PlanB: overlay being resumed\n");
+		DBG("PlanB: overlay being resumed\n");
 
-		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
-		st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
+		st_le16 (&pb->vid_cbo.start->command, DBDMA_NOP);
+		st_le16 (&pb->clip_cbo.start->command, DBDMA_NOP);
 		/* Set command buffer addresses */
-		st_le32(&pb->planb_base->ch1.cmdptr,
-					virt_to_bus(pb->overlay_last1));
-		out_le32(&pb->planb_base->ch2.cmdptr,
-					virt_to_bus(pb->overlay_last2));
+		writel(virt_to_bus(pb->overlay_last1),
+			&pb->planb_base->ch1.cmdptr);
+		writel(virt_to_bus(pb->overlay_last2),
+			&pb->planb_base->ch2.cmdptr);
 		/* Start the DMA controller */
-		out_le32 (&pb->planb_base->ch2.control,
-				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
-		out_le32 (&pb->planb_base->ch1.control,
-				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+		writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE),
+			&pb->planb_base->ch2.control);
+		writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE),
+			&pb->planb_base->ch1.control);
 	} else if(pb->suspended.frame != -1) {
-		out_le32(&pb->planb_base->ch1.cmdptr,
-				virt_to_bus(pb->last_cmd[pb->suspended.frame]));
-		out_le32 (&pb->planb_base->ch1.control,
-				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+		writel(virt_to_bus(pb->gbuf[pb->suspended.frame].last_cmd),
+			&pb->planb_base->ch1.cmdptr);
+		writel(PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE),
+			&pb->planb_base->ch1.control);
 	}
 
 finish:
@@ -589,7 +721,7 @@
 	int	ww = pb->win.width, hw = pb->win.height;
 	int	x, y, xtmp1, xtmp2;
 
-	DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
+	DBG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
 
 	if(xc < 0) {
 		wc += xc;
@@ -626,47 +758,48 @@
 
 static void fill_cmd_buff(struct planb *pb)
 {
-	int restore = 0;
-	volatile struct dbdma_cmd last;
+	int		restore = 0;
+	dbdma_cmd_t	last;
 
-	DEBUG("PlanB: fill_cmd_buff()\n");
+	DBG("PlanB: fill_cmd_buff()\n");
 
-	if(pb->overlay_last1 != pb->ch1_cmd) {
+	if(pb->overlay_last1 != pb->vid_cbo.start) {
 		restore = 1;
 		last = *(pb->overlay_last1);
 	}
-	memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
+	memset ((void *) pb->vid_cbo.start, 0, 2 * pb->tab_size
 					* sizeof(struct dbdma_cmd));
 	cmd_buff (pb);
 	if(restore)
 		*(pb->overlay_last1) = last;
 	if(pb->suspended.overlay) {
-		unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
-		if(jump_addr != pb->ch1_cmd_phys) {
+		unsigned long jump_addr = readl(&pb->overlay_last1->cmd_dep);
+		if(jump_addr != pb->vid_cbo.bus) {
 			int i;
 
-			DEBUG("PlanB: adjusting ch1's jump address\n");
+			DBG("PlanB: adjusting ch1's jump address\n");
 
 			for(i = 0; i < MAX_GBUFFERS; i++) {
-				if(pb->need_pre_capture[i]) {
-				    if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
+				if(pb->gbuf[i].need_pre_capture) {
+				    if(jump_addr == virt_to_bus(pb->gbuf[i].pre_cmd))
 					goto found;
 				} else {
-				    if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
+				    if(jump_addr ==
+					    virt_to_bus(pb->gbuf[i].cap_cmd))
 					goto found;
 				}
 			}
 
-			DEBUG("PlanB: not found...\n");
+			DBG("       not found!\n");
 
 			goto out;
 found:
-			if(pb->need_pre_capture[i])
-				out_le32(&pb->pre_cmd[i]->phy_addr,
-						virt_to_bus(pb->overlay_last1));
+			if(pb->gbuf[i].need_pre_capture)
+				writel(virt_to_bus(pb->overlay_last1),
+					&pb->gbuf[i].pre_cmd->phy_addr);
 			else
-				out_le32(&pb->cap_cmd[i]->phy_addr,
-						virt_to_bus(pb->overlay_last1));
+				writel(virt_to_bus(pb->overlay_last1),
+					&pb->gbuf[i].cap_cmd->phy_addr);
 		}
 	}
 out:
@@ -679,8 +812,8 @@
 {
 	int		i, bpp, count, nlines, stepsize, interlace;
 	unsigned long	base, jump, addr_com, addr_dep;
-	volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
-	volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
+	dbdma_cmd_ptr	c1 = pb->vid_cbo.start;
+	dbdma_cmd_ptr	c2 = pb->clip_cbo.start;
 
 	interlace = pb->win.interlace;
 	bpp = pb->win.bpp;
@@ -696,33 +829,28 @@
 	addr_dep = virt_to_bus(&c1->cmd_dep);
 	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
 	jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
-	if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
-					bpp, 1, pb)) == NULL) {
-		printk(KERN_WARNING "PlanB: encountered serious problems\n");
-		tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
-		tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
-		return;
-	}
+	c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
+						pb->win.color_fmt, 1, pb);
 	tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
 	tab_cmd_store(c1++, addr_dep, jump);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel),
 							PLANB_SET(FIELD_SYNC));
 		/* (1) wait for field sync to be set */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 							PLANB_SET(ODD_FIELD));
 		/* wait for field sync to be cleared */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 		/* if not odd field, wait until field sync is set again */
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
 		/* assert ch_sync to ch2 */
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control),
 							PLANB_SET(CH_SYNC));
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 							PLANB_SET(DMA_ABORT));
 
-	base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
-					+ pb->win.pad) + pb->win.x * bpp);
+	base = (pb->fb.phys + pb->fb.offset + pb->win.y * (pb->win.bpl +
+					pb->win.pad) + pb->win.x * bpp);
 
 	if (interlace) {
 		stepsize = 2;
@@ -744,16 +872,16 @@
 	/* Resync to odd field */
 		/* (2) wait for field sync to be set */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 							PLANB_SET(ODD_FIELD));
 		/* wait for field sync to be cleared */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 		/* if not odd field, wait until field sync is set again */
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
 		/* assert ch_sync to ch2 */
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch2.control),
 							PLANB_SET(CH_SYNC));
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 							PLANB_SET(DMA_ABORT));
 	
 	/* odd field data: */
@@ -765,22 +893,22 @@
 	/* And jump back to the start */
 cmd_tab_data_end:
 	pb->overlay_last1 = c1;	/* keep a pointer to the last command */
-	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, pb->vid_cbo.bus);
 
 	/* Clipmask command buffer */
 
 	/* Preamble commands: */
 	tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel),
 							PLANB_SET(CH_SYNC));
 		/* wait until ch1 asserts ch_sync */
 	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
 		/* clear ch_sync asserted by ch1 */
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.control),
 							PLANB_CLR(CH_SYNC));
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.wait_sel),
 							PLANB_SET(FIELD_SYNC));
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel),
 							PLANB_SET(ODD_FIELD));
 
 	/* jump to end of even field if appropriate */
@@ -791,7 +919,7 @@
 	tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
 
 	/* even field mask: */
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel),
 							PLANB_SET(DMA_ABORT));
 	/* this points to pos. B */
 	jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
@@ -806,7 +934,7 @@
 		goto cmd_tab_mask_end;
 
 	/* odd field mask: */
-/* C */	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+/* C */	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch2.br_sel),
 							PLANB_SET(DMA_ABORT));
 	/* this points to pos. B */
 	jump = virt_to_bus(c2 + nlines / 2);
@@ -824,13 +952,13 @@
 		/* corresponds to fsync (1) of ch1 */
 /* B */	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
 		/* restart ch1, meant to clear any dead bit or something */
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control),
 							PLANB_CLR(RUN));
-	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_bus->ch1.control),
 							PLANB_SET(RUN));
 	pb->overlay_last2 = c2;	/* keep a pointer to the last command */
 		/* start over even field clipmasking */
-	tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
+	tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, pb->clip_cbo.bus);
 
 	eieio();
 	return;
@@ -840,40 +968,22 @@
 /* grabdisplay support functions */
 /*********************************/
 
-static int palette2fmt[] = {
-       0,
-       PLANB_GRAY,
-       0,
-       0,
-       0,
-       PLANB_COLOUR32,
-       PLANB_COLOUR15,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-};
-
-#define PLANB_PALETTE_MAX 15
-
 static inline int overlay_is_active(struct planb *pb)
 {
 	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
-	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
+	unsigned int caddr = (unsigned)readl(&pb->planb_base->ch1.cmdptr);
 
-	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
-			&& (caddr < (pb->ch1_cmd_phys + size))
-			&& (caddr >= (unsigned)pb->ch1_cmd_phys);
+	return (readl(&pb->overlay_last1->cmd_dep) == pb->vid_cbo.bus)
+			&& (caddr < (pb->vid_cbo.bus + size))
+			&& (caddr >= (unsigned)pb->vid_cbo.bus);
 }
 
 static int vgrab(struct planb *pb, struct video_mmap *mp)
 {
-	unsigned int fr = mp->frame;
-	unsigned int format;
+	unsigned int	fr = mp->frame;
+	unsigned int	fmt = mp->format;
+	unsigned int	bpp = palette2fmt[fmt].bpp;
+	gbuf_ptr	gbuf = &pb->gbuf[fr];
 
 	if(pb->rawbuf==NULL) {
 		int err;
@@ -881,211 +991,225 @@
 			return err;
 	}
 
-	IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
-						mp->width, mp->height, fr);
+	DBG("PlanB: grab %d: %dx%d fmt %d (%u)\n", pb->grabbing, mp->width,
+						mp->height, fmt, fr);
 
-	if(pb->grabbing >= MAX_GBUFFERS)
+	if(pb->grabbing >= MAX_GBUFFERS) {
+		DBG("       no buffer\n");
 		return -ENOBUFS;
-	if(fr > (MAX_GBUFFERS - 1) || fr < 0)
+	}
+	if(fr > (MAX_GBUFFERS - 1) || fr < 0) {
+		DBG("       invalid buffer\n");
 		return -EINVAL;
-	if(mp->height <= 0 || mp->width <= 0)
+	}
+	if(mp->height <= 0 || mp->width <= 0) {
+		DBG("       negative height or width\n");
 		return -EINVAL;
-	if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
+	}
+	if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) {
+		DBG("       format out of range\n");
 		return -EINVAL;
-	if((format = palette2fmt[mp->format]) == 0)
+	}
+	if(bpp == 0) {
+		DBG("       unsupported format %d\n", mp->format);
 		return -EINVAL;
-	if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
+	}
+	if (mp->height * mp->width * bpp > PLANB_MAX_FBUF) {
+		DBG("       grab bigger than buffer\n");
 		return -EINVAL;
+	}
 
 	planb_lock(pb);
-	if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
-			format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
+	if(mp->width != gbuf->width || mp->height != gbuf->height ||
+			fmt != gbuf->fmt || (gbuf->norm_switch)) {
 		int i;
 #ifndef PLANB_GSCANLINE
-		unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
-								* pb->gfmt[fr];
-		unsigned int nsize = mp->width * mp->height * format;
+		unsigned int osize = gbuf->width * gbuf->height *
+					palette2fmt[gbuf->fmt].bpp;
+		unsigned int nsize = mp->width * mp->height * bpp;
 #endif
 
-		IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
-					mp->width, mp->height, mp->format);
+		DBG("PlanB: changed gwidth = %d, gheight = %d, format = %u, "
+			"osize = %d, nsize = %d\n", mp->width, mp->height, fmt,
+								osize, nsize);
 
+/* Do we _really_ need to clear the grab buffers?? */
+#if 0
 #ifndef PLANB_GSCANLINE
-		if(pb->gnorm_switch[fr])
+		if(gbuf->norm_switch)
 			nsize = 0;
 		if (nsize < osize) {
-			for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
+			for(i = gbuf->idx; osize > 0; i++) {
 				memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
 				osize -= PAGE_SIZE;
 			}
 		}
-		for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
-							+ pb->lnum[fr]; i++)
+		for(i = gbuf->l_fr_addr_idx; i <
+				gbuf->l_fr_addr_idx + gbuf->lnum; i++)
 			memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
 #else
 /* XXX TODO */
 /*
-		if(pb->gnorm_switch[fr])
+		if(gbuf->norm_switch)
 			memset((void *)pb->gbuffer[fr], 0,
-					pb->gbytes_per_line * pb->gheight[fr]);
+					pb->gbytes_per_line * gbuf->height);
 		else {
 			if(mp->
-			for(i = 0; i < pb->gheight[fr]; i++) {
+			for(i = 0; i < gbuf->height; i++) {
 				memset((void *)(pb->gbuffer[fr]
 					+ pb->gbytes_per_line * i
 			}
 		}
 */
 #endif
-		pb->gwidth[fr] = mp->width;
-		pb->gheight[fr] = mp->height;
-		pb->gfmt[fr] = format;
-		pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
-		planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
-		pb->need_pre_capture[fr] = 1;
-		pb->gnorm_switch[fr] = 0;
+#endif /* if 0 */
+		gbuf->width = mp->width;
+		gbuf->height = mp->height;
+		gbuf->fmt = fmt;
+		gbuf->last_cmd = setup_grab_cmd(fr, pb);
+		planb_pre_capture(fr, pb);
+		gbuf->need_pre_capture = 1;
+		gbuf->norm_switch = 0;
 	} else
-		pb->need_pre_capture[fr] = 0;
-	pb->frame_stat[fr] = GBUFFER_GRABBING;
-	if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+		gbuf->need_pre_capture = 0;
+
+	*gbuf->status = GBUFFER_GRABBING;
+	if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) {
 
-		IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
+		IDBG("PlanB: ch1 inactive, initiating grabbing\n");
 
 		planb_dbdma_stop(&pb->planb_base->ch1);
-		if(pb->need_pre_capture[fr]) {
+		if(gbuf->need_pre_capture) {
 
-			IDEBUG("PlanB: padding pre-capture sequence\n");
+			DBG("PlanB: padding pre-capture sequence\n");
 
-			out_le32 (&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->pre_cmd[fr]));
+			writel(virt_to_bus(gbuf->pre_cmd),
+				&pb->planb_base->ch1.cmdptr);
 		} else {
-			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
-			tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+			tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0);
+			tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0);
 		/* let's be on the safe side. here is not timing critical. */
-			tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
-			out_le32 (&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->cap_cmd[fr]));
+			tab_cmd_dbdma((gbuf->cap_cmd + 1), DBDMA_NOP, 0);
+			writel(virt_to_bus(gbuf->cap_cmd),
+				&pb->planb_base->ch1.cmdptr);
 		}
 		planb_dbdma_restart(&pb->planb_base->ch1);
 		pb->last_fr = fr;
 	} else {
 		int i;
 
-		IDEBUG("PlanB: ch1 active, grabbing being queued\n");
+		DBG("PlanB: ch1 active, grabbing being queued\n");
 
 		if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
 						overlay_is_active(pb))) {
 
-			IDEBUG("PlanB: overlay is active, grabbing defered\n");
+			DBG("PlanB: overlay is active, grabbing defered\n");
 
-			tab_cmd_dbdma(pb->last_cmd[fr],
-					DBDMA_NOP | BR_ALWAYS,
-					virt_to_bus(pb->ch1_cmd));
-			if(pb->need_pre_capture[fr]) {
+			tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS,
+					pb->vid_cbo.bus);
+			if(gbuf->need_pre_capture) {
 
-				IDEBUG("PlanB: padding pre-capture sequence\n");
+				DBG("PlanB: padding pre-capture sequence\n");
 
-				tab_cmd_store(pb->pre_cmd[fr],
+				tab_cmd_store(gbuf->pre_cmd,
 				    virt_to_bus(&pb->overlay_last1->cmd_dep),
-						virt_to_bus(pb->ch1_cmd));
+				    pb->vid_cbo.bus);
 				eieio();
-				out_le32 (&pb->overlay_last1->cmd_dep,
-						virt_to_bus(pb->pre_cmd[fr]));
+				writel(virt_to_bus(gbuf->pre_cmd),
+					&pb->overlay_last1->cmd_dep);
 			} else {
-				tab_cmd_store(pb->cap_cmd[fr],
+				tab_cmd_store(gbuf->cap_cmd,
 				    virt_to_bus(&pb->overlay_last1->cmd_dep),
-						virt_to_bus(pb->ch1_cmd));
-				tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+				    pb->vid_cbo.bus);
+				tab_cmd_dbdma((gbuf->cap_cmd + 1),
 								DBDMA_NOP, 0);
 				eieio();
-				out_le32 (&pb->overlay_last1->cmd_dep,
-						virt_to_bus(pb->cap_cmd[fr]));
+				writel(virt_to_bus(gbuf->cap_cmd),
+					&pb->overlay_last1->cmd_dep);
 			}
 			for(i = 0; overlay_is_active(pb) && i < 999; i++)
-				IDEBUG("PlanB: waiting for overlay done\n");
-			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
+				DBG("PlanB: waiting for overlay done\n");
+			tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0);
 			pb->prev_last_fr = fr;
 			pb->last_fr = -2;
 		} else if(pb->last_fr == -2) {
 
-			IDEBUG("PlanB: mixed mode detected, grabbing"
+			DBG("PlanB: mixed mode detected, grabbing"
 				" will be done before activating overlay\n");
 
-			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
-			if(pb->need_pre_capture[fr]) {
+			tab_cmd_dbdma(pb->vid_cbo.start, DBDMA_NOP, 0);
+			if(gbuf->need_pre_capture) {
 
-				IDEBUG("PlanB: padding pre-capture sequence\n");
+				DBG("PlanB: padding pre-capture sequence\n");
 
-				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+				tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd,
 						DBDMA_NOP | BR_ALWAYS,
-						virt_to_bus(pb->pre_cmd[fr]));
+						virt_to_bus(gbuf->pre_cmd));
 				eieio();
 			} else {
-				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
-				if(pb->gwidth[pb->prev_last_fr] !=
-								pb->gwidth[fr]
-					|| pb->gheight[pb->prev_last_fr] !=
-								pb->gheight[fr]
-					|| pb->gfmt[pb->prev_last_fr] !=
-								pb->gfmt[fr])
-					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+				tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0);
+				if(pb->gbuf[pb->prev_last_fr].width !=
+								gbuf->width
+					|| pb->gbuf[pb->prev_last_fr].height !=
+								gbuf->height
+					|| pb->gbuf[pb->prev_last_fr].fmt !=
+								gbuf->fmt)
+					tab_cmd_dbdma((gbuf->cap_cmd + 1),
 								DBDMA_NOP, 0);
 				else
-					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					tab_cmd_dbdma((gbuf->cap_cmd + 1),
 					    DBDMA_NOP | BR_ALWAYS,
-					    virt_to_bus(pb->cap_cmd[fr] + 16));
-				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+					    virt_to_bus(gbuf->cap_cmd + 16));
+				tab_cmd_dbdma(pb->gbuf[pb->prev_last_fr].last_cmd,
 						DBDMA_NOP | BR_ALWAYS,
-						virt_to_bus(pb->cap_cmd[fr]));
+						virt_to_bus(gbuf->cap_cmd));
 				eieio();
 			}
-			tab_cmd_dbdma(pb->last_cmd[fr],
-					DBDMA_NOP | BR_ALWAYS,
-					virt_to_bus(pb->ch1_cmd));
+			tab_cmd_dbdma(gbuf->last_cmd, DBDMA_NOP | BR_ALWAYS,
+				pb->vid_cbo.bus);
 			eieio();
 			pb->prev_last_fr = fr;
 			pb->last_fr = -2;
 		} else {
+			gbuf_ptr	lastgbuf = &pb->gbuf[pb->last_fr];
 
-			IDEBUG("PlanB: active grabbing session detected\n");
+			DBG("PlanB: active grabbing session detected\n");
 
-			if(pb->need_pre_capture[fr]) {
+			if(gbuf->need_pre_capture) {
 
-				IDEBUG("PlanB: padding pre-capture sequence\n");
+				DBG("PlanB: padding pre-capture sequence\n");
 
-				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+				tab_cmd_dbdma(lastgbuf->last_cmd,
 						DBDMA_NOP | BR_ALWAYS,
-						virt_to_bus(pb->pre_cmd[fr]));
+						virt_to_bus(gbuf->pre_cmd));
 				eieio();
 			} else {
-				tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
-				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
-				if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
-					|| pb->gheight[pb->last_fr] !=
-								pb->gheight[fr]
-					|| pb->gfmt[pb->last_fr] !=
-								pb->gfmt[fr])
-					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+				tab_cmd_dbdma(gbuf->last_cmd, DBDMA_STOP, 0);
+				tab_cmd_dbdma(gbuf->cap_cmd, DBDMA_NOP, 0);
+				if(lastgbuf->width != gbuf->width
+				    || lastgbuf->height != gbuf->height
+				    || lastgbuf->fmt != gbuf->fmt)
+					tab_cmd_dbdma((gbuf->cap_cmd + 1),
 								DBDMA_NOP, 0);
 				else
-					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					tab_cmd_dbdma((gbuf->cap_cmd + 1),
 					    DBDMA_NOP | BR_ALWAYS,
-					    virt_to_bus(pb->cap_cmd[fr] + 16));
-				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+					    virt_to_bus(gbuf->cap_cmd + 16));
+				tab_cmd_dbdma(lastgbuf->last_cmd,
 						DBDMA_NOP | BR_ALWAYS,
-						virt_to_bus(pb->cap_cmd[fr]));
+						virt_to_bus(gbuf->cap_cmd));
 				eieio();
 			}
 			pb->last_fr = fr;
 		}
-		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+		if(!(ACTIVE & readl(&pb->planb_base->ch1.status))) {
 
-			IDEBUG("PlanB: became inactive in the mean time..."
+			DBG("PlanB: became inactive in the mean time... "
 				"reactivating\n");
 
 			planb_dbdma_stop(&pb->planb_base->ch1);
-			out_le32 (&pb->planb_base->ch1.cmdptr,
-						virt_to_bus(pb->cap_cmd[fr]));
+			writel(virt_to_bus(gbuf->cap_cmd),
+				&pb->planb_base->ch1.cmdptr);
 			planb_dbdma_restart(&pb->planb_base->ch1);
 		}
 	}
@@ -1095,49 +1219,58 @@
 	return 0;
 }
 
-static void planb_pre_capture(int fr, int bpp, struct planb *pb)
+static void planb_pre_capture(int fr, struct planb *pb)
 {
-	volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
-	int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
+	gbuf_ptr	gbuf = &pb->gbuf[fr];
+	dbdma_cmd_ptr	c1 = gbuf->pre_cmd;
+	int		height = gbuf->height;
+	int		interlace = (height > pb->maxlines/2)? 1: 0;
 
 	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
-	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
-						bpp, 0, pb)) == NULL) {
-		printk(KERN_WARNING "PlanB: encountered some problems\n");
-		tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
-		return;
-	}
+	c1 = cmd_geo_setup(c1, gbuf->width, height, interlace, gbuf->fmt,
+									0, pb);
 	/* Sync to even field */
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
-		PLANB_SET(FIELD_SYNC));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel),
+							PLANB_SET(FIELD_SYNC));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(ODD_FIELD));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
 	tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(DMA_ABORT));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
 	/* For non-interlaced, we use even fields only */
-	if (pb->gheight[fr] <= pb->maxlines/2)
+	if (interlace == 0)
 		goto cmd_tab_data_end;
 	/* Sync to odd field */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(ODD_FIELD));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(DMA_ABORT));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
 cmd_tab_data_end:
-	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(gbuf->cap_cmd));
 
 	eieio();
 }
 
-static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
+/* This needs some explanation.
+ * What we do here is write the DBDMA commands to fill the grab buffer.
+ * Since the grab buffer is made up of physically non-contiguous chunks,
+ * we need to make sure to not make the DMA engine write across a chunk
+ * boundary: the DMA engine needs a physically contiguous memory chunk for
+ * a single scan line.
+ * So all those scan lines that cross a chunk boundary are written do spare
+ * scratch buffers, and we keep track of this fact.
+ * Later, in the interrupt routine, we copy those scan lines (in two pieces)
+ * back to where they belong in the right sequence in the grab buffer.
+ */
+static dbdma_cmd_ptr setup_grab_cmd(int fr, struct planb *pb)
 {
-	int		i, bpp, count, nlines, stepsize, interlace;
+	int		i, count, nlines, stepsize, interlace;
 #ifdef PLANB_GSCANLINE
 	int		scanline;
 #else
@@ -1146,19 +1279,20 @@
 #endif
 	unsigned long	jump;
 	int		pagei;
-	volatile struct dbdma_cmd *c1;
-	volatile struct dbdma_cmd *jump_addr;
-
-	c1 = pb->cap_cmd[fr];
-	interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
-	bpp = pb->gfmt[fr];	/* gfmt = bpp */
-	count = bpp * pb->gwidth[fr];
-	nlines = pb->gheight[fr];
+	dbdma_cmd_ptr	c1;
+	dbdma_cmd_ptr	jump_addr;
+	gbuf_ptr	gbuf = &pb->gbuf[fr];
+	int		fmt = gbuf->fmt;
+
+	c1 = gbuf->cap_cmd;
+	nlines = gbuf->height;
+	interlace = (nlines > pb->maxlines/2) ? 1 : 0;
+	count = palette2fmt[fmt].bpp * gbuf->width;
 #ifdef PLANB_GSCANLINE
 	scanline = pb->gbytes_per_line;
 #else
-	pb->lsize[fr] = count;
-	pb->lnum[fr] = 0;
+	gbuf->lsize = count;
+	gbuf->lnum = 0;
 #endif
 
 	/* Do video in: */
@@ -1166,22 +1300,17 @@
 	/* Preamble commands: */
 	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
-	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
-						bpp, 0, pb)) == NULL) {
-		printk(KERN_WARNING "PlanB: encountered serious problems\n");
-		tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
-		return (pb->cap_cmd[fr] + 2);
-	}
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
-		PLANB_SET(FIELD_SYNC));
+	c1 = cmd_geo_setup(c1, gbuf->width, nlines, interlace, fmt, 0, pb);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.wait_sel),
+							PLANB_SET(FIELD_SYNC));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(ODD_FIELD));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
 	tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
-		PLANB_SET(DMA_ABORT));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
 
 	if (interlace) {
 		stepsize = 2;
@@ -1194,12 +1323,12 @@
 
 	/* even field data: */
 
-	pagei = pb->gbuf_idx[fr];
+	pagei = gbuf->idx;
 #ifdef PLANB_GSCANLINE
 	for (i = 0; i < nlines; i += stepsize) {
-		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-					virt_to_bus(pb->rawbuf[pagei
-					+ i * scanline / PAGE_SIZE]), jump);
+		tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+		    virt_to_bus(pb->rawbuf[pagei + i * scanline / PAGE_SIZE]),
+									jump);
 	}
 #else
 	i = 0;
@@ -1219,18 +1348,25 @@
 		    leftover1 = 0;
 		else {
 		    if(lov0 >= count) {
+			/* can happen only when interlacing; then other field
+			 * uses up leftover space (lov0 - count). */
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
 				+ count * nlpp * stepsize + leftover1, jump);
 		    } else {
-			pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
+			/* start of free space at end of page: */
+			pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei]
 					+ count * nlpp * stepsize + leftover1;
-			pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
-			pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0;
+			/* index where continuation is: */
+			pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1;
+			/* How much is left to do in next page: */
+			pb->l_to_next_size[fr][gbuf->lnum] = count - lov0;
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
-						+ pb->lnum[fr]]), jump);
-			if(++pb->lnum[fr] > MAX_LNUM)
-				pb->lnum[fr]--;
+				virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx
+						+ gbuf->lnum]), jump);
+			if(++gbuf->lnum > MAX_LNUM) {
+				/* FIXME: error condition! */
+				gbuf->lnum--;
+		    	}
 		    }
 		    leftover1 = count * stepsize - lov0;
 		    i += stepsize;
@@ -1248,11 +1384,11 @@
 
 	/* Sync to odd field */
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 		PLANB_SET(ODD_FIELD));
 	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
 	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->ch1.br_sel),
 		PLANB_SET(DMA_ABORT));
 	
 	/* odd field data: */
@@ -1260,14 +1396,14 @@
 	jump = virt_to_bus(jump_addr);
 #ifdef PLANB_GSCANLINE
 	for (i = 1; i < nlines; i += stepsize) {
-		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+		tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
 					virt_to_bus(pb->rawbuf[pagei
 					+ i * scanline / PAGE_SIZE]), jump);
 	}
 #else
 	i = 1;
 	leftover1 = 0;
-	pagei = pb->gbuf_idx[fr];
+	pagei = gbuf->idx;
 	if(nlines <= 1)
 	    goto skip;
 	do {
@@ -1290,16 +1426,18 @@
 		    leftover1 = 0;
 		else {
 		    if(lov0 > count) {
-			pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
+			pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei]
 				+ count * (nlpp * stepsize + 1) + leftover1;
-			pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
-			pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize
+			pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1;
+			pb->l_to_next_size[fr][gbuf->lnum] = count * stepsize
 									- lov0;
 			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
-				virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
-							+ pb->lnum[fr]]), jump);
-			if(++pb->lnum[fr] > MAX_LNUM)
-				pb->lnum[fr]--;
+				virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx
+							+ gbuf->lnum]), jump);
+			if(++gbuf->lnum > MAX_LNUM) {
+				/* FIXME: error condition! */
+				gbuf->lnum--;
+			}
 			i += stepsize;
 		    }
 		    leftover1 = count * stepsize - lov0;
@@ -1313,7 +1451,7 @@
 #endif /* PLANB_GSCANLINE */
 
 cmd_tab_data_end:
-	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->intr_stat),
 			(fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
 	/* stop it */
 	tab_cmd_dbdma(c1, DBDMA_STOP, 0);
@@ -1327,50 +1465,54 @@
 	unsigned int stat, astat;
 	struct planb *pb = (struct planb *)dev_id;
 
-	IDEBUG("PlanB: planb_irq()\n");
+	IDBG("PlanB: planb_irq()\n");
 
 	/* get/clear interrupt status bits */
 	eieio();
-	stat = in_le32(&pb->planb_base->intr_stat);
+	stat = readl(&pb->planb_base->intr_stat);
 	astat = stat & pb->intr_mask;
-	out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ
-					& ~astat & stat & ~PLANB_GEN_IRQ);
-	IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat);
+	writel(PLANB_FRM_IRQ & ~astat & stat & ~PLANB_GEN_IRQ,
+		&pb->planb_base->intr_stat);
+	IDBG("PlanB: stat = %X, astat = %X\n", stat, astat);
 
 	if(astat & PLANB_FRM_IRQ) {
-		unsigned int fr = stat >> 9;
+		unsigned int	fr = stat >> 9;
+		gbuf_ptr	gbuf = &pb->gbuf[fr];
 #ifndef PLANB_GSCANLINE
-		int i;
+		int		i;
 #endif
-		IDEBUG("PlanB: PLANB_FRM_IRQ\n");
+		IDBG("PlanB: PLANB_FRM_IRQ\n");
 
 		pb->gcount++;
 
-		IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
+		IDBG("PlanB: grab %d: fr = %d, gcount = %d\n",
 				pb->grabbing, fr, pb->gcount);
 #ifndef PLANB_GSCANLINE
-		IDEBUG("PlanB: %d * %d bytes are being copied over\n",
-				pb->lnum[fr], pb->lsize[fr]);
-		for(i = 0; i < pb->lnum[fr]; i++) {
-			int first = pb->lsize[fr] - pb->l_to_next_size[fr][i];
+		/* Now that the buffer is full, copy those lines that fell
+		 * on a page boundary from the spare buffers back to where
+		 * they belong. */
+		IDBG("PlanB: %d * %d bytes are being copied over\n",
+				gbuf->lnum, gbuf->lsize);
+		for(i = 0; i < gbuf->lnum; i++) {
+			int first = gbuf->lsize - pb->l_to_next_size[fr][i];
 
 			memcpy(pb->l_to_addr[fr][i],
-				pb->rawbuf[pb->l_fr_addr_idx[fr] + i],
+				pb->rawbuf[gbuf->l_fr_addr_idx + i],
 				first);
 			memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]],
-				pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first,
+				pb->rawbuf[gbuf->l_fr_addr_idx + i] + first,
 						pb->l_to_next_size[fr][i]);
 		}
 #endif
-		pb->frame_stat[fr] = GBUFFER_DONE;
+		*gbuf->status = GBUFFER_DONE;
 		pb->grabbing--;
 		wake_up_interruptible(&pb->capq);
 		return;
 	}
 	/* incorrect interrupts? */
 	pb->intr_mask = PLANB_CLR_IRQ;
-	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
-	printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
+	writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat);
+	printk(KERN_ERR "PlanB: IRQ lockup, cleared interrupts"
 							" unconditionally\n");
 }
 
@@ -1380,16 +1522,22 @@
 
 static int planb_open(struct video_device *dev, int mode)
 {
-	struct planb *pb = (struct planb *)dev;
+	struct planb	*pb = (struct planb *)dev->priv;
+	int		err;
 
-	if (pb->user == 0) {
-		int err;
+	/* first open on driver? */
+	if(pb->vid_user + pb->vbi_user == 0) {
 		if((err = planb_prepare_open(pb)) != 0)
 			return err;
 	}
-	pb->user++;
+	/* first open on video dev? */
+	if(pb->vid_user == 0) {
+		if((err = planb_prepare_video(pb)) != 0)
+			return err;
+	}
+	pb->vid_user++;
 
-	DEBUG("PlanB: device opened\n");
+	DBG("PlanB: device opened\n");
 
 	MOD_INC_USE_COUNT;
 	return 0;   
@@ -1397,44 +1545,46 @@
 
 static void planb_close(struct video_device *dev)
 {
-	struct planb *pb = (struct planb *)dev;
+	struct planb *pb = (struct planb *)dev->priv;
 
-	if(pb->user < 1) /* ??? */
-		return;
 	planb_lock(pb);
-	if (pb->user == 1) {
-		if (pb->overlay) {
+	/* last close? then stop everything... */
+	if(--pb->vid_user == 0) {
+		if(pb->overlay) {
 			planb_dbdma_stop(&pb->planb_base->ch2);
 			planb_dbdma_stop(&pb->planb_base->ch1);
 			pb->overlay = 0;
 		}
-		planb_prepare_close(pb);
+		planb_close_video(pb);
 	}
-	pb->user--;
+	/* last open on PlanB hardware? */
+	if(pb->vid_user + pb->vbi_user == 0)
+		planb_prepare_close(pb);
 	planb_unlock(pb);
 
-	DEBUG("PlanB: device closed\n");
+	DBG("PlanB: device closed\n");
 
-	MOD_DEC_USE_COUNT;  
+	MOD_DEC_USE_COUNT;
+	return;
 }
 
 static long planb_read(struct video_device *v, char *buf, unsigned long count,
 				int nonblock)
 {
-	DEBUG("planb: read request\n");
+	DBG("planb: read request\n");
 	return -EINVAL;
 }
 
 static long planb_write(struct video_device *v, const char *buf,
 				unsigned long count, int nonblock)
 {
-	DEBUG("planb: write request\n");
+	DBG("planb: write request\n");
 	return -EINVAL;
 }
 
 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
-	struct planb *pb=(struct planb *)dev;
+	struct planb *pb=(struct planb *)dev->priv;
   	
 	switch (cmd)
 	{	
@@ -1442,7 +1592,7 @@
 		{
 			struct video_capability b;
 
-			DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
+			DBG("PlanB: IOCTL VIDIOCGCAP\n");
 
 			strcpy (b.name, pb->video_dev.name);
 			b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
@@ -1461,50 +1611,48 @@
 		case VIDIOCSFBUF:
 		{
                         struct video_buffer v;
-			unsigned short bpp;
 			unsigned int fmt;
 
-			DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
+			DBG("PlanB: IOCTL VIDIOCSFBUF\n");
 
-                        if (!capable(CAP_SYS_ADMIN)
-			|| !capable(CAP_SYS_RAWIO))
+                        if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
                                 return -EPERM;
-                        if (copy_from_user(&v, arg,sizeof(v)))
+                        if (copy_from_user(&v, arg, sizeof(v)))
                                 return -EFAULT;
 			planb_lock(pb);
 			switch(v.depth) {
-			case 8:
-				bpp = 1;
-				fmt = PLANB_GRAY;
+			    /* xawtv only asks for 8 bit in static grey, but
+			     * there is no way to know what it really means.. */
+			    case 8:
+				fmt = VIDEO_PALETTE_GREY;
 				break;
-			case 15:
-			case 16:
-				bpp = 2;
-				fmt = PLANB_COLOUR15;
+			    case 15:
+				fmt = VIDEO_PALETTE_RGB555;
 				break;
-			case 24:
-			case 32:
-				bpp = 4;
-				fmt = PLANB_COLOUR32;
+			    case 32:
+				fmt = VIDEO_PALETTE_RGB32;
 				break;
-			default:
+			    /* We don't deliver these two... */
+			    case 16:
+			    case 24:
+			    default:
 				planb_unlock(pb);
                                 return -EINVAL;
 			}
-			if (bpp * v.width > v.bytesperline) {
+			if (palette2fmt[fmt].bpp * v.width > v.bytesperline) {
 				planb_unlock(pb);
 				return -EINVAL;
 			}
-			pb->win.bpp = bpp;
+			pb->win.bpp = palette2fmt[fmt].bpp;
 			pb->win.color_fmt = fmt;
-			pb->frame_buffer_phys = (unsigned long) v.base;
+			pb->fb.phys = (unsigned long) v.base;
 			pb->win.sheight = v.height;
 			pb->win.swidth = v.width;
 			pb->picture.depth = pb->win.depth = v.depth;
 			pb->win.bpl = pb->win.bpp * pb->win.swidth;
 			pb->win.pad = v.bytesperline - pb->win.bpl;
 
-                        DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
+                        DBG("PlanB: Display at %p is %d by %d, bytedepth %d,"
 				" bpl %d (+ %d)\n", v.base, v.width,v.height,
 				pb->win.bpp, pb->win.bpl, pb->win.pad);
 
@@ -1521,9 +1669,9 @@
 		{
                         struct video_buffer v;
 
-			DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
+			DBG("PlanB: IOCTL VIDIOCGFBUF\n");
 
-			v.base = (void *)pb->frame_buffer_phys;
+			v.base = (void *)pb->fb.phys;
 			v.height = pb->win.sheight;
 			v.width = pb->win.swidth;
 			v.depth = pb->win.depth;
@@ -1539,7 +1687,7 @@
                         if(copy_from_user(&i, arg, sizeof(i)))
                                 return -EFAULT;
 			if(i==0) {
-				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
+				DBG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
 
 				if (!(pb->overlay))
 					return 0;
@@ -1548,9 +1696,9 @@
 				overlay_stop(pb);
 				planb_unlock(pb);
 			} else {
-				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
+				DBG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
 
-				if (pb->frame_buffer_phys == 0 ||
+				if (pb->fb.phys == 0 ||
 					  pb->win.width == 0 ||
 					  pb->win.height == 0)
 					return -EINVAL;
@@ -1569,7 +1717,7 @@
 		{
 			struct video_channel v;
 
-			DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
+			DBG("PlanB: IOCTL VIDIOCGCHAN\n");
 
 			if(copy_from_user(&v, arg,sizeof(v)))
 				return -EFAULT;
@@ -1598,7 +1746,7 @@
 		{
 			struct video_channel v;
 
-			DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
+			DBG("PlanB: IOCTL VIDIOCSCHAN\n");
 
 			if(copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
@@ -1616,6 +1764,7 @@
 					maxlines = PLANB_NTSC_MAXLINES;
 					break;
 				default:
+					DBG("       invalid norm %d.\n", v.norm);
 					return -EINVAL;
 					break;
 				}
@@ -1628,7 +1777,7 @@
 				/* Stop overlay if running */
 				suspend_overlay(pb);
 				for(i = 0; i < MAX_GBUFFERS; i++)
-					pb->gnorm_switch[i] = 1;
+					pb->gbuf[i].norm_switch = 1;
 				/* I know it's an overkill, but.... */
 				fill_cmd_buff(pb);
 				/* ok, now init it accordingly */
@@ -1651,6 +1800,7 @@
 					  ~7) | 4), pb);
 				break;
 			default:
+				DBG("       invalid channel %d.\n", v.channel);
 				return -EINVAL;
 				break;
 			}
@@ -1661,22 +1811,9 @@
 		{
 			struct video_picture vp = pb->picture;
 
-			DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
-
-			switch(pb->win.color_fmt) {
-			case PLANB_GRAY:
-				vp.palette = VIDEO_PALETTE_GREY;
-			case PLANB_COLOUR15:
-				vp.palette = VIDEO_PALETTE_RGB555;
-				break;
-			case PLANB_COLOUR32:
-				vp.palette = VIDEO_PALETTE_RGB32;
-				break;
-			default:
-				vp.palette = 0;
-				break;
-			}
+			DBG("PlanB: IOCTL VIDIOCGPICT\n");
 
+			vp.palette = pb->win.color_fmt;
 			if(copy_to_user(arg,&vp,sizeof(vp)))
 				return -EFAULT;
 			return 0;
@@ -1685,12 +1822,13 @@
 		{
 			struct video_picture vp;
 
-			DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
+			DBG("PlanB: IOCTL VIDIOCSPICT\n");
 
 			if(copy_from_user(&vp,arg,sizeof(vp)))
 				return -EFAULT;
 			pb->picture = vp;
 			/* Should we do sanity checks here? */
+			planb_lock(pb);
 			saa_set (SAA7196_BRIG, (unsigned char)
 			    ((pb->picture.brightness) >> 8), pb);
 			saa_set (SAA7196_HUEC, (unsigned char)
@@ -1699,6 +1837,7 @@
 			    ((pb->picture.colour) >> 9), pb);
 			saa_set (SAA7196_CONT, (unsigned char)
 			    ((pb->picture.contrast) >> 9), pb);
+			planb_unlock(pb);
 
 			return 0;
 		}
@@ -1708,7 +1847,7 @@
 			struct video_clip	clip;
 			int 			i;
 			
-			DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
+			DBG("PlanB: IOCTL VIDIOCSWIN\n");
 
 			if(copy_from_user(&vw,arg,sizeof(vw)))
 				return -EFAULT;
@@ -1728,6 +1867,9 @@
 				pb->win.height = vw.height;
 				fill_cmd_buff(pb);
 			}
+                        DBG("PlanB: Window at (%d,%d) size %dx%d\n", vw.x, vw.y, vw.width,
+				vw.height);
+
 			/* Reset clip mask */
 			memset ((void *) pb->mask, 0xff, (pb->maxlines
 					* ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
@@ -1747,7 +1889,7 @@
 		{
 			struct video_window vw;
 
-			DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
+			DBG("PlanB: IOCTL VIDIOCGWIN\n");
 
 			vw.x=pb->win.x;
 			vw.y=pb->win.y;
@@ -1762,30 +1904,32 @@
 			return 0;
 		}
 	        case VIDIOCSYNC: {
-			int i;
+			int		i;
+			gbuf_ptr	gbuf;
 
-			IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
+			DBG("PlanB: IOCTL VIDIOCSYNC\n");
 
 			if(copy_from_user((void *)&i,arg,sizeof(int)))
 				return -EFAULT;
 
-			IDEBUG("PlanB: sync to frame %d\n", i);
+			DBG("PlanB: sync to frame %d\n", i);
 
                         if(i > (MAX_GBUFFERS - 1) || i < 0)
                                 return -EINVAL;
+			gbuf = &pb->gbuf[i];
 chk_grab:
-                        switch (pb->frame_stat[i]) {
+                        switch (*gbuf->status) {
                         case GBUFFER_UNUSED:
                                 return -EINVAL;
 			case GBUFFER_GRABBING:
-				IDEBUG("PlanB: waiting for grab"
+				DBG("PlanB: waiting for grab"
 							" done (%d)\n", i);
  			        interruptible_sleep_on(&pb->capq);
 				if(signal_pending(current))
 					return -EINTR;
 				goto chk_grab;
                         case GBUFFER_DONE:
-                                pb->frame_stat[i] = GBUFFER_UNUSED;
+                                *gbuf->status = GBUFFER_UNUSED;
                                 break;
                         }
                         return 0;
@@ -1794,17 +1938,19 @@
 	        case VIDIOCMCAPTURE:
 		{
                         struct video_mmap vm;
-			volatile unsigned int status;
+			int		  fr;
 
-			IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
+			DBG("PlanB: IOCTL VIDIOCMCAPTURE\n");
 
 			if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
 				return -EFAULT;
-                        status = pb->frame_stat[vm.frame];
-                        if (status != GBUFFER_UNUSED)
-                                return -EBUSY;
+			fr = vm.frame;
+                        if(fr > (MAX_GBUFFERS - 1) || fr < 0)
+                                return -EINVAL;
+			if (*pb->gbuf[fr].status != GBUFFER_UNUSED)
+				return -EBUSY;
 
-		        return vgrab(pb, &vm);
+			return vgrab(pb, &vm);
 		}
 		
 		case VIDIOCGMBUF:
@@ -1812,7 +1958,7 @@
 			int i;
 			struct video_mbuf vm;
 
-			DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
+			DBG("PlanB: IOCTL VIDIOCGMBUF\n");
 
 			memset(&vm, 0 , sizeof(vm));
 			vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
@@ -1824,11 +1970,27 @@
 			return 0;
 		}
 		
+		case VIDIOCGUNIT:
+		{
+			struct video_unit vu;
+
+			DBG("PlanB: IOCTL VIDIOCGUNIT\n");
+
+			vu.video=pb->video_dev.minor;
+			vu.vbi=pb->vbi_dev.minor;
+			vu.radio=VIDEO_NO_UNIT;
+			vu.audio=VIDEO_NO_UNIT;
+			vu.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
+				return -EFAULT;
+			return 0;
+		}
+
 		case PLANBIOCGSAAREGS:
 		{
 			struct planb_saa_regs preg;
 
-			DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
+			DBG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
 
 			if(copy_from_user(&preg, arg, sizeof(preg)))
 				return -EFAULT;
@@ -1845,7 +2007,7 @@
 		{
 			struct planb_saa_regs preg;
 
-			DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
+			DBG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
 
 			if(copy_from_user(&preg, arg, sizeof(preg)))
 				return -EFAULT;
@@ -1859,10 +2021,14 @@
 		{
 			struct planb_stat_regs pstat;
 
-			DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
+			DBG("PlanB: IOCTL PLANBIOCGSTAT\n");
 
-			pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
-			pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
+			pstat.ch1_stat = readl(&pb->planb_base->ch1.status);
+			pstat.ch2_stat = readl(&pb->planb_base->ch2.status);
+			pstat.ch1_cmdbase = (unsigned long)pb->vid_cbo.start;
+			pstat.ch2_cmdbase = (unsigned long)pb->clip_cbo.start;
+			pstat.ch1_cmdptr = readl(&pb->planb_base->ch1.cmdptr);
+			pstat.ch2_cmdptr = readl(&pb->planb_base->ch2.cmdptr);
 			pstat.saa_stat0 = saa_status(0, pb);
 			pstat.saa_stat1 = saa_status(1, pb);
 
@@ -1871,11 +2037,11 @@
 				return -EFAULT;
 			return 0;
 		}
-		
+
 		case PLANBIOCSMODE: {
 			int v;
 
-			DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
+			DBG("PlanB: IOCTL PLANBIOCSMODE\n");
 
 			if(copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
@@ -1902,7 +2068,7 @@
 		case PLANBIOCGMODE: {
 			int v=pb->win.mode;
 
-			DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
+			DBG("PlanB: IOCTL PLANBIOCGMODE\n");
 
 			if(copy_to_user(arg,&v,sizeof(v)))
 				return -EFAULT;
@@ -1912,25 +2078,28 @@
 		case PLANBG_GRAB_BPL: {
 			int v=pb->gbytes_per_line;
 
-			DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
+			DBG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
 
 			if(copy_to_user(arg,&v,sizeof(v)))
 				return -EFAULT;
 			return 0;
 		}
 #endif /* PLANB_GSCANLINE */
+
+/* These serve only for debugging... */
+#ifdef DEBUG
 		case PLANB_INTR_DEBUG: {
 			int i;
 
-			DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
+			DBG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
 
 			if(copy_from_user(&i, arg, sizeof(i)))
 				return -EFAULT;
 
 			/* avoid hang ups all together */
 			for (i = 0; i < MAX_GBUFFERS; i++) {
-				if(pb->frame_stat[i] == GBUFFER_GRABBING) {
-					pb->frame_stat[i] = GBUFFER_DONE;
+				if(*pb->gbuf[i].status == GBUFFER_GRABBING) {
+					*pb->gbuf[i].status = GBUFFER_DONE;
 				}
 			}
 			if(pb->grabbing)
@@ -1942,7 +2111,7 @@
 			int i;
 			struct planb_any_regs any;
 
-			DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
+			DBG("PlanB: IOCTL PLANB_INV_REGS\n");
 
 			if(copy_from_user(&any, arg, sizeof(any)))
 				return -EFAULT;
@@ -1952,42 +2121,70 @@
 				return -EINVAL;
 			for (i = 0; i < any.bytes; i++) {
 				any.data[i] =
-					in_8((unsigned char *)pb->planb_base
+					readb((unsigned char *)pb->planb_base
 							+ any.offset + i);
 			}
 			if(copy_to_user(arg,&any,sizeof(any)))
 				return -EFAULT;
 			return 0;
 		}
+		case PLANBIOCGDBDMABUF:
+		{
+			struct planb_buf_regs buf;
+			dbdma_cmd_ptr dc;
+			int i;
+
+			DBG("PlanB: IOCTL PLANBIOCGDBDMABUF\n");
+
+			if(copy_from_user(&buf, arg, sizeof(buf)))
+				return -EFAULT;
+			buf.end &= ~0xf;
+			if( (buf.start < 0) || (buf.end < 0x10) ||
+			    (buf.end < buf.start+0x10) ||
+			    (buf.end > 2*pb->tab_size) )
+				return -EINVAL;
+
+			printk ("PlanB DBDMA command buffer:\n");
+			for (i=(buf.start>>4); i<=(buf.end>>4); i++) {
+				printk(" 0x%04x:", i<<4);
+				dc = pb->vid_cbo.start + i;
+				printk (" %04x %04x %08x %08x %04x %04x\n",
+				  dc->req_count, dc->command, dc->phy_addr,
+				  dc->cmd_dep, dc->res_count, dc->xfer_status);
+			}
+			return 0;
+		}
+#endif /* DEBUG */
+
 		default:
 		{
-			DEBUG("PlanB: Unimplemented IOCTL\n");
+			DBG("PlanB: Unimplemented IOCTL: %d (0x%x)\n", cmd, cmd);
 			return -ENOIOCTLCMD;
 		}
 	/* Some IOCTLs are currently unsupported on PlanB */
 		case VIDIOCGTUNER: {
-		DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
+		DBG("PlanB: IOCTL VIDIOCGTUNER\n");
 			goto unimplemented; }
 		case VIDIOCSTUNER: {
-		DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
+		DBG("PlanB: IOCTL VIDIOCSTUNER\n");
 			goto unimplemented; }
 		case VIDIOCSFREQ: {
-		DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
+		DBG("PlanB: IOCTL VIDIOCSFREQ\n");
 			goto unimplemented; }
 		case VIDIOCGFREQ: {
-		DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
+		DBG("PlanB: IOCTL VIDIOCGFREQ\n");
 			goto unimplemented; }
 		case VIDIOCKEY: {
-		DEBUG("PlanB: IOCTL VIDIOCKEY\n");
+		DBG("PlanB: IOCTL VIDIOCKEY\n");
 			goto unimplemented; }
 		case VIDIOCSAUDIO: {
-		DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
+		DBG("PlanB: IOCTL VIDIOCSAUDIO\n");
 			goto unimplemented; }
 		case VIDIOCGAUDIO: {
-		DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
+		DBG("PlanB: IOCTL VIDIOCGAUDIO\n");
 			goto unimplemented; }
 unimplemented:
-		DEBUG("       Unimplemented\n");
+		DBG("       Unimplemented\n");
 			return -ENOIOCTLCMD;
 	}
 	return 0;
@@ -1995,9 +2192,9 @@
 
 static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	int i;
-	struct planb *pb = (struct planb *)dev;
-        unsigned long start = (unsigned long)adr;
+	struct planb	*pb = (struct planb *)dev->priv;
+        unsigned long	start = (unsigned long)adr;
+	int		i;
 
 	if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
 	        return -EINVAL;
@@ -2006,7 +2203,7 @@
 		if((err=grabbuf_alloc(pb)))
 			return err;
 	}
-	for (i = 0; i < pb->rawbuf_size; i++) {
+	for (i = 0; i < pb->rawbuf_nchunks; i++) {
 		if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]),
 						PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
@@ -2018,77 +2215,223 @@
 	return 0;
 }
 
+/**********************************
+ * VBI device operation functions *
+ **********************************/
+
+static long planb_vbi_read(struct video_device *dev, char *buf,
+	unsigned long count, int nonblock)
+{
+	struct planb	*pb = (struct planb *)dev->priv;
+	int		q,todo;
+	DECLARE_WAITQUEUE(wait, current);
+
+/* Dummy for now */
+	printk ("PlanB: VBI read %li bytes.\n", count);
+	return (0);
+
+	todo=count;
+	while (todo && todo>(q=VBIBUF_SIZE-pb->vbip)) 
+	{
+		if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip, q))
+			return -EFAULT;
+		todo-=q;
+		buf+=q;
+
+		add_wait_queue(&pb->vbiq, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+		if (todo && q==VBIBUF_SIZE-pb->vbip) {
+			if(nonblock) {
+				remove_wait_queue(&pb->vbiq, &wait);
+				current->state = TASK_RUNNING;
+				if(count==todo)
+					return -EWOULDBLOCK;
+				return count-todo;
+			}
+			schedule();
+			if(signal_pending(current)) {
+				remove_wait_queue(&pb->vbiq, &wait);
+				current->state = TASK_RUNNING;
+				if(todo==count)
+					return -EINTR;
+				else
+					return count-todo;
+			}
+		}
+		remove_wait_queue(&pb->vbiq, &wait);
+		current->state = TASK_RUNNING;
+	}
+	if (todo) {
+		if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip,
+		    todo))
+			return -EFAULT;
+		pb->vbip+=todo;
+	}
+	return count;
+}
+
+static unsigned int planb_vbi_poll(struct video_device *dev,
+	struct file *file, poll_table *wait)
+{
+	struct planb	*pb = (struct planb *)dev->priv;
+	unsigned int	mask = 0;
+
+	printk ("PlanB: VBI poll.\n");
+	poll_wait(file, &pb->vbiq, wait);
+
+	if (pb->vbip < VBIBUF_SIZE)
+		mask |= (POLLIN | POLLRDNORM);
+
+	return mask;
+}
+
+static int planb_vbi_open(struct video_device *dev, int flags)
+{
+	struct planb	*pb = (struct planb *)dev->priv;
+	int		err;
+
+	/* first open on the driver? */
+	if(pb->vid_user + pb->vbi_user == 0) {
+		if((err = planb_prepare_open(pb)) != 0)
+			return err;
+	}
+	/* first open on the vbi device? */
+	if(pb->vbi_user == 1) {
+		if((err = planb_prepare_vbi(pb)) != 0)
+			return err;
+	}
+	++pb->vbi_user;
+
+	DBG("PlanB: VBI open\n");
+
+	MOD_INC_USE_COUNT;
+	return 0;   
+}
+
+static void planb_vbi_close(struct video_device *dev)
+{
+	struct planb	*pb = (struct planb *)dev->priv;
+
+	/* last close on vbi device? */
+	if(--pb->vbi_user == 0) {
+		planb_close_vbi(pb);
+	}
+	/* last close on any planb device? */
+	if(pb->vid_user + pb->vbi_user == 0) {
+		planb_prepare_close(pb);
+	}
+
+	DBG("PlanB: VBI close\n");
+
+	MOD_DEC_USE_COUNT;  
+	return;
+}
+
+static int planb_vbi_ioctl(struct video_device *dev, unsigned int cmd,
+	void *arg)
+{
+	switch (cmd) {  
+		/* This is only for alevt */
+		case BTTV_VBISIZE:
+			DBG("PlanB: IOCTL BTTV_VBISIZE.\n");
+			return VBIBUF_SIZE;
+		default:
+			DBG("PlanB: Unimplemented VBI IOCTL no. %i.\n", cmd);
+			return -EINVAL;
+	}
+}
+
 static struct video_device planb_template=
 {
 	owner:		THIS_MODULE,
 	name:		PLANB_DEVICE_NAME,
-	type:		VID_TYPE_OVERLAY,
+	type:		VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
 	hardware:	VID_HARDWARE_PLANB,
 	open:		planb_open,
 	close:		planb_close,
 	read:		planb_read,
-	write:		planb_write,
+	write:		planb_write,	/* not implemented */
 	ioctl:		planb_ioctl,
 	mmap:		planb_mmap,	/* mmap? */
 };
 
-static int init_planb(struct planb *pb)
+static struct video_device planb_vbi_template=
+{
+	owner:		THIS_MODULE,
+	name:		PLANB_VBI_NAME,
+	type:		VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+	hardware:	VID_HARDWARE_PLANB,
+	open:		planb_vbi_open,
+	close:		planb_vbi_close,
+	read:		planb_vbi_read,
+	write:		planb_write,	/* not implemented */
+	poll:		planb_vbi_poll,
+	ioctl:		planb_vbi_ioctl,
+};
+
+static int __devinit init_planb(struct planb *pb)
 {
 	unsigned char saa_rev;
 	int i, result;
 	unsigned long flags;
 
-	memset ((void *) &pb->win, 0, sizeof (struct planb_window));
+	printk(KERN_INFO "PlanB: PowerMacintosh video input driver rev. %s\n", PLANB_REV);
+
+	pb->video_dev.minor = -1;
+	pb->vid_user = 0;
+
 	/* Simple sanity check */
 	if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
 		printk(KERN_ERR "PlanB: Option(s) invalid\n");
 		return -2;
 	}
+	memset ((void *) &pb->win, 0, sizeof (struct planb_window));
 	pb->win.norm = def_norm;
 	pb->win.mode = PLANB_TV_MODE;	/* TV mode */
-	pb->win.interlace=1;
-	pb->win.x=0;
-	pb->win.y=0;
-	pb->win.width=768; /* 640 */
-	pb->win.height=576; /* 480 */
-	pb->maxlines=576;
-#if 0
-	btv->win.cropwidth=768; /* 640 */
-	btv->win.cropheight=576; /* 480 */
-	btv->win.cropx=0;
-	btv->win.cropy=0;
-#endif
-	pb->win.pad=0;
-	pb->win.bpp=4;
-	pb->win.depth=32;
-	pb->win.color_fmt=PLANB_COLOUR32;
-	pb->win.bpl=1024*pb->win.bpp;
-	pb->win.swidth=1024;
-	pb->win.sheight=768;
+	pb->win.interlace = 1;
+	pb->win.x = 0;
+	pb->win.y = 0;
+	pb->win.width = 768; /* 640 */
+	pb->win.height = 576; /* 480 */
+	pb->win.pad = 0;
+	pb->win.bpp = 4;
+	pb->win.depth = 32;
+	pb->win.color_fmt = VIDEO_PALETTE_RGB32;
+	pb->win.bpl = 1024 * pb->win.bpp;
+	pb->win.swidth = 1024;
+	pb->win.sheight = 768;
+	pb->maxlines = 576;
 #ifdef PLANB_GSCANLINE
 	if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
 				|| (pb->gbytes_per_line <= 0))
 		return -3;
 	else {
 		/* page align pb->gbytes_per_line for DMA purpose */
-		for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
-			i>>=1;
+		for(i = PAGE_SIZE; pb->gbytes_per_line < (i >> 1);)
+			i >>= 1;
 		pb->gbytes_per_line = i;
 	}
 #endif
 	pb->tab_size = PLANB_MAXLINES + 40;
 	pb->suspend = 0;
 	init_MUTEX(&pb->lock);
-	pb->ch1_cmd = 0;
-	pb->ch2_cmd = 0;
+	pb->vid_cbo.start = 0;
+	pb->clip_cbo.start = 0;
 	pb->mask = 0;
-	pb->priv_space = 0;
-	pb->offset = 0;
-	pb->user = 0;
+	pb->vid_raw = 0;
 	pb->overlay = 0;
 	init_waitqueue_head(&pb->suspendq);
 	pb->cmd_buff_inited = 0;
-	pb->frame_buffer_phys = 0;
+	pb->fb.phys = 0;
+	pb->fb.offset = 0;
+
+	/* VBI stuff: */
+	pb->vbi_dev.minor = -1;
+	pb->vbi_user = 0;
+	pb->vbirunning = 0;
+	pb->vbip = 0;
+	pb->vbibuf = 0;
+	init_waitqueue_head(&pb->vbiq);
 
 	/* Reset DMA controllers */
 	planb_dbdma_stop(&pb->planb_base->ch2);
@@ -2117,9 +2460,6 @@
 	disable_irq(pb->irq);
 	restore_flags(flags);
         
-	/* Now add the template and register the device unit. */
-	memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
-
 	pb->picture.brightness=0x90<<8;
 	pb->picture.contrast = 0x70 << 8;
 	pb->picture.colour = 0x70<<8;
@@ -2127,170 +2467,131 @@
 	pb->picture.whiteness = 0;
 	pb->picture.depth = pb->win.depth;
 
-	pb->frame_stat=NULL;
 	init_waitqueue_head(&pb->capq);
 	for(i=0; i<MAX_GBUFFERS; i++) {
-		pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
-		pb->gwidth[i]=0;
-		pb->gheight[i]=0;
-		pb->gfmt[i]=0;
-		pb->cap_cmd[i]=NULL;
+		gbuf_ptr	gbuf = &pb->gbuf[i];
+
+		gbuf->idx = PLANB_MAX_FBUF * i / PAGE_SIZE;
+		gbuf->width=0;
+		gbuf->height=0;
+		gbuf->fmt=0;
+		gbuf->cap_cmd=NULL;
 #ifndef PLANB_GSCANLINE
-		pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
+		gbuf->l_fr_addr_idx = MAX_GBUFFERS * (PLANB_MAX_FBUF
 						/ PAGE_SIZE + 1) + MAX_LNUM * i;
-		pb->lsize[i] = 0;
-		pb->lnum[i] = 0;
+		gbuf->lsize = 0;
+		gbuf->lnum = 0;
 #endif
 	}
 	pb->rawbuf=NULL;
 	pb->grabbing=0;
 
 	/* enable interrupts */
-	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+	writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat);
 	pb->intr_mask = PLANB_FRM_IRQ;
 	enable_irq(pb->irq);
 
+	/* Now add the templates and register the device units. */
+	memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
+	pb->video_dev.priv = pb;
+	memcpy(&pb->vbi_dev,&planb_vbi_template,sizeof(planb_vbi_template));
+	
 	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
 		return -1;
+	if(video_register_device(&pb->vbi_dev, VFL_TYPE_VBI, vbi_nr)<0) {
+		video_unregister_device(&pb->video_dev);
+		return -1;
+	}
 
 	return 0;
 }
 
 /*
- *	Scan for a PlanB controller, request the irq and map the io memory 
+ *	Scan for a PlanB controller and map the io memory 
  */
-
 static int find_planb(void)
 {
 	struct planb		*pb;
-	struct device_node	*planb_devices;
-	unsigned char		dev_fn, confreg, bus;
-	unsigned int		old_base, new_base;
-	unsigned int		irq;
-	struct pci_dev 		*pdev;
+	struct pci_dev 		*pdev = NULL;
+	unsigned long		base;
+	int			planb_num = 0;
 
 	if (_machine != _MACH_Pmac)
 		return 0;
 
-	planb_devices = find_devices("planb");
-	if (planb_devices == 0) {
-		planb_num=0;
+	pdev = pci_find_device(APPLE_VENDOR_ID, PLANB_DEV_ID, pdev);
+	if (pdev == NULL) {
 		printk(KERN_WARNING "PlanB: no device found!\n");
 		return planb_num;
 	}
 
-	if (planb_devices->next != NULL)
-		printk(KERN_ERR "Warning: only using first PlanB device!\n");
-	pb = &planbs[0];
+	pb = &planbs;
 	planb_num = 1;
+	base = pdev->resource[0].start;
 
-        if (planb_devices->n_addrs != 1) {
-                printk (KERN_WARNING "PlanB: expecting 1 address for planb "
-                	"(got %d)", planb_devices->n_addrs);
-		return 0;
-	}
-
-	if (planb_devices->n_intrs == 0) {
-		printk(KERN_WARNING "PlanB: no intrs for device %s\n",
-		       planb_devices->full_name);
-		return 0;
-	} else {
-		irq = planb_devices->intrs[0].line;
-	}
-
-	/* Initialize PlanB's PCI registers */
-
-	/* There is a bug with the way OF assigns addresses
-	   to the devices behind the chaos bridge.
-	   control needs only 0x1000 of space, but decodes only
-	   the upper 16 bits. It therefore occupies a full 64K.
-	   OF assigns the planb controller memory within this space;
-	   so we need to change that here in order to access planb. */
-
-	/* We remap to 0xf1000000 in hope that nobody uses it ! */
-
-	bus = (planb_devices->addrs[0].space >> 16) & 0xff;
-	dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
-	confreg = planb_devices->addrs[0].space & 0xff;
-	old_base = planb_devices->addrs[0].address;
-	new_base = 0xf1000000;
-
-	DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
-		"membase 0x%x (base reg. 0x%x)\n",
-		bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
-
-	pdev = pci_find_slot (bus, dev_fn);
-	if (!pdev) {
-		printk(KERN_ERR "cannot find slot\n");
-		/* XXX handle error */
-	}
+	DBG("PlanB: Found device %s, membase 0x%lx, irq %d\n",
+		pdev->slot_name, base, pdev->irq);
 
 	/* Enable response in memory space, bus mastering,
 	   use memory write and invalidate */
-	pci_write_config_word (pdev, PCI_COMMAND,
-		PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
-		PCI_COMMAND_INVALIDATE);
-	/* Set PCI Cache line size & latency timer */
-	pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, 0x8);
+	pci_enable_device (pdev);
+	pci_set_master (pdev);
+	pci_set_mwi(pdev);
+	/* value copied from MacOS... */
 	pci_write_config_byte (pdev, PCI_LATENCY_TIMER, 0x40);
 
-	/* Set the new base address */
-	pci_write_config_dword (pdev, confreg, new_base);
-
 	planb_regs = (volatile struct planb_registers *)
-						ioremap (new_base, 0x400);
+						ioremap (base, 0x400);
 	pb->planb_base = planb_regs;
-	pb->planb_base_phys = (struct planb_registers *)new_base;
-	pb->irq	= irq;
+	pb->planb_base_bus = (struct planb_registers *)base;
+	pb->irq	= pdev->irq;
 	
 	return planb_num;
 }
 
 static void release_planb(void)
 {
-	int i;
 	struct planb *pb;
 
-	for (i=0;i<planb_num; i++) 
-	{
-		pb=&planbs[i];
+	pb=&planbs;
 
-		/* stop and flash DMAs unconditionally */
-		planb_dbdma_stop(&pb->planb_base->ch2);
-		planb_dbdma_stop(&pb->planb_base->ch1);
+	/* stop and flush DMAs unconditionally */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
 
-		/* clear and free interrupts */
-		pb->intr_mask = PLANB_CLR_IRQ;
-		out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
-		free_irq(pb->irq, pb);
+	/* clear and free interrupts */
+	pb->intr_mask = PLANB_CLR_IRQ;
+	writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat);
+	free_irq(pb->irq, pb);
 
-		/* make sure all allocated memory are freed */
-		planb_prepare_close(pb);
+	/* make sure all allocated memory are freed */
+	planb_prepare_close(pb);
 
-		printk(KERN_INFO "PlanB: unregistering with v4l\n");
-		video_unregister_device(&pb->video_dev);
+	printk(KERN_INFO "PlanB: unregistering with v4l\n");
+	video_unregister_device(&pb->video_dev);
+	video_unregister_device(&pb->vbi_dev);
 
-		/* note that iounmap() does nothing on the PPC right now */
-		iounmap ((void *)pb->planb_base);
-	}
+	/* note that iounmap() does nothing on the PPC right now */
+	iounmap ((void *)pb->planb_base);
 }
 
 static int __init init_planbs(void)
 {
-	int i;
-  
-	if (find_planb()<=0)
+	int planb_num;
+
+	planb_num=find_planb();
+
+	if (planb_num < 0)
 		return -EIO;
+	if (planb_num == 0)
+		return -ENXIO;
 
-	for (i=0; i<planb_num; i++) {
-		if (init_planb(&planbs[i])<0) {
-			printk(KERN_ERR "PlanB: error registering device %d"
-							" with v4l\n", i);
-			release_planb();
-			return -EIO;
-		} 
-		printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
-	}  
+	if (init_planb(&planbs) < 0) {
+		printk(KERN_ERR "PlanB: error registering planb device"
+						" with v4l\n");
+		release_planb();
+		return -EIO;
+	} 
 	return 0;
 }
 
diff -urN linux-2.4.19-pre8/drivers/media/video/planb.h linux-2.4.19-pre9/drivers/media/video/planb.h
--- linux-2.4.19-pre8/drivers/media/video/planb.h	Wed Jun 27 17:10:55 2001
+++ linux-2.4.19-pre9/drivers/media/video/planb.h	Tue May 28 16:02:29 2002
@@ -1,14 +1,16 @@
 /* 
-    planb - PlanB frame grabber driver
+    planb - v4l-compatible frame grabber driver for the PlanB hardware
 
     PlanB is used in the 7x00/8x00 series of PowerMacintosh
     Computers as video input DMA controller.
 
-    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+    Copyright (C) 1998 - 2002  Michel Lanners <mailto:mlan@cpu.lu>
 
-    Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
+    Based largely on the old bttv driver by Ralph Metzler
 
-    Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
+    Additional debugging and coding by Takashi Oe <mailto:toe@unlserve.unl.edu>
+
+    For more information, see <http://www.cpu.lu/~mlan/planb.html>
 
 
     This program is free software; you can redistribute it and/or modify
@@ -26,18 +28,17 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: planb.h,v 1.13 1999/05/03 19:28:56 mlan Exp $ */
+/* $Id: planb.h,v 2.9 2002/04/03 15:57:57 mlan Exp mlan $ */
 
 #ifndef _PLANB_H_
 #define _PLANB_H_
 
-#ifdef __KERNEL__
-#include <asm/dbdma.h>
-#include "saa7196.h"
-#endif /* __KERNEL__ */
-
 #define PLANB_DEVICE_NAME	"Apple PlanB Video-In"
-#define PLANB_REV		"1.0"
+#define PLANB_VBI_NAME		"Apple PlanB VBI"
+#define PLANB_REV		"2.11"
+
+#define APPLE_VENDOR_ID		0x106b
+#define PLANB_DEV_ID		0x0004
 
 #ifdef __KERNEL__
 //#define PLANB_GSCANLINE	/* use this if apps have the notion of */
@@ -47,15 +48,24 @@
 #define PLANB_MAXLINES 576
 #define PLANB_NTSC_MAXLINES 480
 
+/* Max VBI data buffer size */
+#define VBI_LINESIZE 1024	/* on SAA7196, a line can be max. 1024 pixels */
+#define VBI_START 7		/* VBI starts at line 7 */
+#define VBI_MAXLINES 16		/* 16 lines per field */
+/* We have 2 of these, but return them one at a time */
+#define VBIBUF_SIZE (VBI_LINESIZE * VBI_MAXLINES)
+
+#define LINE_OFFSET 1		/* between line 1 and SAA's first valid line */
+
 /* Uncomment your preferred norm ;-) */
 #define PLANB_DEF_NORM VIDEO_MODE_PAL
 //#define PLANB_DEF_NORM VIDEO_MODE_NTSC
 //#define PLANB_DEF_NORM VIDEO_MODE_SECAM
 
 /* fields settings */
-#define PLANB_GRAY	0x1	/*  8-bit mono? */
-#define PLANB_COLOUR15	0x2	/* 16-bit mode */
-#define PLANB_COLOUR32	0x4	/* 32-bit mode */
+#define PLANB_SIZE8	0x1	/*  8-bit mono? */
+#define PLANB_SIZE16	0x2	/* 16-bit mode */
+#define PLANB_SIZE32	0x4	/* 32-bit mode */
 #define PLANB_CLIPMASK	0x8	/* hardware clipmasking */
 
 /* misc. flags for PlanB DMA operation */
@@ -67,6 +77,41 @@
 #define DMA_ABORT	0x2	/* error or just out of sync if set */
 #define ODD_FIELD	0x4	/* odd field is detected if set */
 
+/* format info and correspondance */
+struct fmts {
+	int	bpp;		/* bytes per pixel */
+	int	pb_fmt;		/* planb format (DMA engine sub 0x40/0x44 ) */
+	int	saa_fmt;	/* saa format:				bit
+				   SAA7196 sub 0x20: bits FS0		0
+				   			  FS1		1
+					   sub 0x30: bit  MCT		4
+							  LLV		5 */
+};
+
+/* This is supposed to match the VIDEO_PALETTE_* defines in
+ * struct video_picture in videodev.h */
+static struct fmts palette2fmt[] = {
+	{ 0, 0,			   0 },
+	{ 1, PLANB_SIZE8,	0x33 },	/* VIDEO_PALETTE_GREY */
+	{ 0, 0,			   0 },
+	{ 0, 0,			   0 },
+	{ 0, 0,			   0 },
+	{ 4, PLANB_SIZE32,	   2 },	/* VIDEO_PALETTE_RGB32 */
+	{ 2, PLANB_SIZE16,	   0 },	/* VIDEO_PALETTE_RGB555 */
+	{ 2, PLANB_SIZE16,	0x21 },	/* VIDEO_PALETTE_YUV422 */
+	{ 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 },
+};
+
+#define PLANB_PALETTE_MAX (sizeof palette2fmt / sizeof (struct fmts))
+
 /* for capture operations */
 #define MAX_GBUFFERS	2
 /* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */
@@ -87,6 +132,10 @@
 struct planb_stat_regs {
 	unsigned int ch1_stat;
 	unsigned int ch2_stat;
+	unsigned long ch1_cmdbase;
+	unsigned long ch2_cmdbase;
+	unsigned int ch1_cmdptr;
+	unsigned int ch2_cmdptr;
 	unsigned char saa_stat0;
 	unsigned char saa_stat1;
 };
@@ -97,23 +146,43 @@
 	unsigned char data[128];
 };
 
+struct planb_buf_regs {
+	unsigned int start;
+	unsigned int end;
+};
+
 /* planb private ioctls */
-#define PLANBIOCGSAAREGS	_IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs)	/* Read a saa7196 reg value */
-#define PLANBIOCSSAAREGS	_IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs)	/* Set a saa7196 reg value */
-#define PLANBIOCGSTAT		_IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs)	/* Read planb status */
+/* Read a saa7196 reg value */
+#define PLANBIOCGSAAREGS	_IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs)
+/* Set a saa7196 reg value */
+#define PLANBIOCSSAAREGS	_IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs)
+/* Read planb status */
+#define PLANBIOCGSTAT		_IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs)
+/* Get TV/VTR mode */
 #define PLANB_TV_MODE		1
 #define PLANB_VTR_MODE		2
-#define PLANBIOCGMODE		_IOR('v', BASE_VIDIOCPRIVATE + 3, int)	/* Get TV/VTR mode */
-#define PLANBIOCSMODE		_IOW('v', BASE_VIDIOCPRIVATE + 4, int)	/* Set TV/VTR mode */
+#define PLANBIOCGMODE		_IOR('v', BASE_VIDIOCPRIVATE + 3, int)
+/* Set TV/VTR mode */
+#define PLANBIOCSMODE		_IOW('v', BASE_VIDIOCPRIVATE + 4, int)
 
 #ifdef PLANB_GSCANLINE
-#define PLANBG_GRAB_BPL		_IOR('v', BASE_VIDIOCPRIVATE + 5, int)	/* # of bytes per scanline in grab buffer */
+/* # of bytes per scanline in grab buffer */
+#define PLANBG_GRAB_BPL		_IOR('v', BASE_VIDIOCPRIVATE + 5, int)
 #endif
 
+/* This doesn't really belong here, but until someone cleans up (or defines
+   in the first place ;-) the VBI API, it helps alevt... */
+#define BTTV_VBISIZE		_IOR('v', BASE_VIDIOCPRIVATE + 8, int)
+
+/* Various debugging IOCTLs */
+#ifdef DEBUG
 /* call wake_up_interruptible() with appropriate actions */
 #define PLANB_INTR_DEBUG	_IOW('v', BASE_VIDIOCPRIVATE + 20, int)
 /* investigate which reg does what */
 #define PLANB_INV_REGS		_IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs)
+/* Dump DBDMA command buffer from (int) to (int) */
+#define PLANBIOCGDBDMABUF	_IOW('v', BASE_VIDIOCPRIVATE + 22, struct planb_buf_regs)
+#endif /* DEBUG */
 
 #ifdef __KERNEL__
 
@@ -121,27 +190,44 @@
 #define PLANB_SET(x)	((x) << 16 | (x))
 #define PLANB_CLR(x)	((x) << 16)
 
-/* This represents the physical register layout */
-struct planb_registers {
-	volatile struct dbdma_regs	ch1;		/* 0x00: video in */
-	volatile unsigned int		even;		/* 0x40: even field setting */
-	volatile unsigned int		odd;		/* 0x44; odd field setting */
-	unsigned int			pad1[14];	/* empty? */
-	volatile struct dbdma_regs	ch2;		/* 0x80: clipmask out */
-	unsigned int			pad2[16];	/* 0xc0: empty? */
-	volatile unsigned int		reg3;		/* 0x100: ???? */
-	volatile unsigned int		intr_stat;	/* 0x104: irq status */
+typedef volatile struct dbdma_cmd dbdma_cmd_t;
+typedef volatile struct dbdma_cmd *dbdma_cmd_ptr;
+typedef volatile struct dbdma_regs dbdma_regs_t;
+typedef volatile struct dbdma_regs *dbdma_regs_ptr;
+
+typedef struct gbuffer gbuf_t;
+typedef struct gbuffer *gbuf_ptr;
+
+/* grab buffer status */
+#define GBUFFER_UNUSED		0x00U
+#define GBUFFER_GRABBING	0x01U
+#define GBUFFER_DONE		0x02U
+
+/* planb interrupt status values (0x104: irq status) */
 #define PLANB_CLR_IRQ		0x00		/* clear Plan B interrupt */
 #define PLANB_GEN_IRQ		0x01		/* assert Plan B interrupt */
 #define PLANB_FRM_IRQ		0x0100		/* end of frame */
-	unsigned int			pad3[1];	/* empty? */
-	volatile unsigned int		reg5;		/* 0x10c: ??? */
-	unsigned int			pad4[60];	/* empty? */
-	volatile unsigned char		saa_addr;	/* 0x200: SAA subadr */
-	char				pad5[3];
-	volatile unsigned char		saa_regval;	/* SAA7196 write reg. val */
-	char				pad6[3];
-	volatile unsigned char		saa_status;	/* SAA7196 status byte */
+
+#define PLANB_DUMMY 40	/* # of command buf's allocated for pre-capture seq. */
+
+/* This represents the physical register layout */
+struct planb_registers {
+	dbdma_regs_t		ch1;		/* 0x00: video in */
+	volatile u32		even;		/* 0x40: even field setting */
+	volatile u32		odd;		/* 0x44; odd field setting */
+	u32			pad1[14];	/* empty? */
+	dbdma_regs_t		ch2;		/* 0x80: clipmask out */
+	u32			pad2[16];	/* 0xc0: empty? */
+	volatile u32		reg3;		/* 0x100: ???? */
+	volatile u32		intr_stat;	/* 0x104: irq status */
+	u32			pad3[1];	/* empty? */
+	volatile u32		reg5;		/* 0x10c: ??? */
+	u32			pad4[60];	/* empty? */
+	volatile u8		saa_addr;	/* 0x200: SAA subadr */
+	u8			pad5[3];
+	volatile u8		saa_regval;	/* SAA7196 write reg. val */
+	u8			pad6[3];
+	volatile u8		saa_status;	/* SAA7196 status byte */
 	/* There is more unused stuff here */
 };
 
@@ -163,67 +249,105 @@
 	struct dbdma_cmd cmd;
 };
 
+/* Framebuffer info */
+struct planb_fb {
+	unsigned long	phys;		/* Framebuffer phys. base address */
+	int		offset;		/* offset of pixel 1 */
+};
+
+/* DBDMA command buffer descriptor */
+struct dbdma_cmd_buf {
+	dbdma_cmd_ptr	start;
+	dbdma_cmd_ptr	jumpaddr;	/* where are we called from? */
+	unsigned int	size;
+	unsigned long	bus;		/* start address as seen from the bus */
+};
+
+/* grab buffer descriptor */
+struct gbuffer {
+	dbdma_cmd_ptr		cap_cmd;
+	dbdma_cmd_ptr		last_cmd;
+	dbdma_cmd_ptr		pre_cmd;
+	int			idx;
+	int			need_pre_capture;
+	int			width;
+	int			height;
+	unsigned int		fmt;
+	int			norm_switch;
+#ifndef PLANB_GSCANLINE
+	int			l_fr_addr_idx;
+	int			lsize;
+	int			lnum;
+#endif
+        volatile unsigned int	*status;	/* ptr to status value */
+};
+
 struct planb {
-	struct	video_device video_dev;
-	struct	video_picture picture;		/* Current picture params */
-	struct	video_audio audio_dev;		/* Current audio params */
+/* the video device: */
+	struct video_device	video_dev;
+	struct video_picture	picture;	/* Current picture params */
+	int			vid_user;	/* Users on video device */
+	void			*vid_raw;	/* Org. alloc. mem for kfree */
+	struct dbdma_cmd_buf	vid_cbo;	/* odd video dbdma cmd buf */
+	struct dbdma_cmd_buf	vid_cbe;	/* even */
+	void			*clip_raw;
+	struct dbdma_cmd_buf	clip_cbo;	/* odd clip dbdma cmd buf */
+	struct dbdma_cmd_buf	clip_cbe;	/* even */
+	dbdma_cmd_ptr		overlay_last1;
+	dbdma_cmd_ptr		overlay_last2;
   
-	volatile struct planb_registers *planb_base;	/* virt base of planb */
-	struct planb_registers *planb_base_phys;	/* phys base of planb */
-	void	*priv_space;			/* Org. alloc. mem for kfree */
-	int	user;
-	unsigned int tab_size;
-	int     maxlines;
-	struct semaphore lock;
-	unsigned int	irq;			/* interrupt number */
-	volatile unsigned int intr_mask;
-
-	int	overlay;			/* overlay running? */
-	struct	planb_window win;
-	unsigned long frame_buffer_phys;	/* We need phys for DMA */
-	int	offset;				/* offset of pixel 1 */
-	volatile struct dbdma_cmd *ch1_cmd;	/* Video In DMA cmd buffer */
-	volatile struct dbdma_cmd *ch2_cmd;	/* Clip Out DMA cmd buffer */
-	volatile struct dbdma_cmd *overlay_last1;
-	volatile struct dbdma_cmd *overlay_last2;
-	unsigned long ch1_cmd_phys;
-	volatile unsigned char *mask;		/* Clipmask buffer */
-	int suspend;
-	wait_queue_head_t suspendq;
-	struct planb_suspend suspended;
-	int	cmd_buff_inited;		/* cmd buffer inited? */
-
-	int grabbing;
-	unsigned int gcount;
-	wait_queue_head_t capq;
-	int last_fr;
-	int prev_last_fr;
-	unsigned char **rawbuf;
-	int rawbuf_size;
-	int gbuf_idx[MAX_GBUFFERS];
-	volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS];
-	volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS];
-	volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS];
-	int need_pre_capture[MAX_GBUFFERS];
-#define PLANB_DUMMY 40	/* # of command buf's allocated for pre-capture seq. */
-	int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS];
-	unsigned int gfmt[MAX_GBUFFERS];
-	int gnorm_switch[MAX_GBUFFERS];
-        volatile unsigned int *frame_stat;
-#define GBUFFER_UNUSED       0x00U
-#define GBUFFER_GRABBING     0x01U
-#define GBUFFER_DONE         0x02U
+/* the hardware: */
+	volatile struct planb_registers
+				*planb_base;	/* virt base of planb */
+	struct planb_registers	*planb_base_bus; /* phys base of planb */
+	unsigned int		tab_size;
+	int     		maxlines;
+	unsigned int		irq;		/* interrupt number */
+	volatile unsigned int	intr_mask;
+	struct planb_fb		fb;		/* Framebuffer info */
+
+/* generic stuff: */
+	void			*jump_raw;	/* jump buffer raw space */
+	dbdma_cmd_ptr		jumpbuf;	/* same, DBDMA_ALIGN'ed */
+	struct semaphore	lock;
+	int			overlay;	/* overlay running? */
+	struct planb_window	win;
+	volatile unsigned char	*mask;		/* Clipmask buffer */
+	int			suspend;
+	wait_queue_head_t	suspendq;
+	struct planb_suspend	suspended;
+	int			cmd_buff_inited; /* cmd buffer inited? */
+
+/* grabbing stuff: */ 
+	int			grabbing;
+	unsigned int		gcount;
+	wait_queue_head_t	capq;
+	int			last_fr;
+	int			prev_last_fr;
+	unsigned char		**rawbuf;
+	int			rawbuf_nchunks;
+	struct gbuffer		gbuf[MAX_GBUFFERS];
+
 #ifdef PLANB_GSCANLINE
-	int gbytes_per_line;
+	int			gbytes_per_line;
 #else
-#define MAX_LNUM 431	/* change this if PLANB_MAXLINES or */
+#define MAX_LNUM 576	/* change this if PLANB_MAXLINES or */
 			/* PLANB_MAXPIXELS changes */
-	int l_fr_addr_idx[MAX_GBUFFERS];
-	unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM];
-	int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM];
-	int l_to_next_size[MAX_GBUFFERS][MAX_LNUM];
-	int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS];
-#endif
+	unsigned char		*l_to_addr[MAX_GBUFFERS][MAX_LNUM];
+	int			l_to_next_idx[MAX_GBUFFERS][MAX_LNUM];
+	int			l_to_next_size[MAX_GBUFFERS][MAX_LNUM];
+#endif /* PLANB_GSCANLINE */
+
+/* VBI stuff: */
+	struct video_device	vbi_dev;	/* VBI data device */
+	int			vbi_user;	/* Users on vbi device */
+	void			*vbi_raw;
+	struct dbdma_cmd_buf	vbi_cbo;	/* odd VBI dbdma cmd buf */
+	struct dbdma_cmd_buf	vbi_cbe;	/* even */
+	int			vbirunning;
+	int			vbip;		/* pointer into VBI buffer */
+	unsigned char		*vbibuf;	/* buffer for VBI data */
+	wait_queue_head_t	vbiq;
 };
 
 #endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre8/drivers/media/video/saa7196.h linux-2.4.19-pre9/drivers/media/video/saa7196.h
--- linux-2.4.19-pre8/drivers/media/video/saa7196.h	Fri May  7 11:05:30 1999
+++ linux-2.4.19-pre9/drivers/media/video/saa7196.h	Tue May 28 16:02:29 2002
@@ -3,19 +3,17 @@
     scaler, and clock generator circuit (DESCpro), as used in
     the PlanB video input of the Powermac 7x00/8x00 series.
   
-    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+    Copyright (C) 1998 - 2002 Michel Lanners <mailto:mlan@cpu.lu>
 
     The register defines are shamelessly copied from the meteor
-    driver out of NetBSD (with permission),
+    driver out of FreeBSD (with permission),
     and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe
     (Thanks !)
   
-    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
-
     The default values used for PlanB are my mistakes.
 */
 
-/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */
+/* $Id: saa7196.h,v 2.3 2002/04/03 15:57:57 mlan Exp mlan $ */
 
 #ifndef _SAA7196_H_
 #define _SAA7196_H_
diff -urN linux-2.4.19-pre8/drivers/message/i2o/Makefile linux-2.4.19-pre9/drivers/message/i2o/Makefile
--- linux-2.4.19-pre8/drivers/message/i2o/Makefile	Fri Dec 29 14:07:21 2000
+++ linux-2.4.19-pre9/drivers/message/i2o/Makefile	Tue May 28 16:02:29 2002
@@ -9,8 +9,13 @@
 
 export-objs	:= i2o_pci.o i2o_core.o i2o_config.o i2o_block.o i2o_lan.o i2o_scsi.o i2o_proc.o
 
+#
+# Do not touch the order here 
+# We must link i2o_core, then i2o_pci, then protocols
+#
+obj-$(CONFIG_I2O)	+= i2o_core.o
 obj-$(CONFIG_I2O_PCI)	+= i2o_pci.o
-obj-$(CONFIG_I2O)	+= i2o_core.o i2o_config.o
+obj-$(CONFIG_I2O)	+= i2o_config.o
 obj-$(CONFIG_I2O_BLOCK)	+= i2o_block.o
 obj-$(CONFIG_I2O_LAN)	+= i2o_lan.o
 obj-$(CONFIG_I2O_SCSI)	+= i2o_scsi.o
diff -urN linux-2.4.19-pre8/drivers/message/i2o/README linux-2.4.19-pre9/drivers/message/i2o/README
--- linux-2.4.19-pre8/drivers/message/i2o/README	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/message/i2o/README	Tue May 28 16:02:29 2002
@@ -1,52 +1,99 @@
-
-	Linux I2O Support	(c) Copyright 1999 Red Hat Software
-					and others.
+	Linux I2O Support	(c) Copyright 1999-2002 Red Hat and others.
 
 	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.
 
-AUTHORS (so far)
 
-Alan Cox, Building Number Three Ltd.
-	Core code, SCSI and Block OSMs
+Hardware Compatibility
+-----------------------
+
+This is an informal test summary. It is not definitive as a reference work
+or guaranteed of any accuracy.
 
-Steve Ralston, LSI Logic Corp.
-	Debugging SCSI and Block OSM
+Last updated for 2.4.19pre7-ac1
 
-Deepak Saxena, Intel Corp.
-	Various core/block extensions
-	/proc interface, bug fixes
-	Ioctl interfaces for control
-	Debugging LAN OSM
-
-Philip Rumpf
-	Fixed assorted dumb SMP locking bugs
-
-Juha Sievanen, University of Helsinki Finland
-	LAN OSM code
-	/proc interface to LAN class
-	Bug fixes
-	Core code extensions
-
-Auvo Häkkinen, University of Helsinki Finland
-	LAN OSM code
-	/Proc interface to LAN class
-	Bug fixes
-	Core code extensions
 
-Taneli Vähäkangas, University of Helsinki Finland
-	Fixes to i2o_config
+Tested Hardware			block	config	lan	proc	scsi
+-----------------------------------------------------------------------
+Current Release
+	AMI MegaRAID[0]		YES	YES	N/A	YES	N/A
+
+
+Previous Stable Release (2.4.18ac3)
+	AMI MegaRAID[0]		FAIL
+	DPT Smartraid		------------ Use dpt_i2o module ------------
+	Intel SCU RAID		FAIL[2]	???	N/A	???	FAIL[2]
+	Promise Supertrak100	YES[3]	YES[3]	N/A	YES[3]	N/A
+	Promise SX6000		YES[3]	YES[3]	N/A	YES[3]	N/A
+	Symbios FC920		YES	YES[4]	N/A	YES	YES
+
+
+[0] In I2O mode. For normal mode use the megaraid driver
+[1] Initialisation oddities and scsi failure. Use dpt_i2o module instead.
+[2] Card hangs under certain load patterns.
+[3] The driver works correctly. Certain values are misreported by this
+card but the results are only cosmetic. Firmware updates are required for some
+very early cards. Set the card into I2O not 'Linux' mode.
+[4] HTML configuration mode not available.
+
+Requirements
+------------
+
+I2O 1.5 compliant hardware
+PCI bus interrupt driven I2O devices
+Devices in classes Block, Lan or SCSI.
+32bit I2O messages supported
+
+Limitations
+-----------
+64bit message formats are not supported (64bit I2O is basically a whole 
+		different driver variant)
+I2O Tape class is not supported (no known devices using this..)
+Currently only 32bit x86 platforms are supported.
+
+
+Authors
+--------
+	Alan Cox, Building Number Three Ltd.
+		Core code, SCSI and Block OSMs
+
+	Steve Ralston, LSI Logic Corp.
+		Debugging SCSI and Block OSM
+
+	Deepak Saxena, Intel Corp.
+		Various core/block extensions
+		/proc interface, bug fixes
+		Ioctl interfaces for control
+		Debugging LAN OSM
+
+	Philip Rumpf
+		Fixed assorted dumb SMP locking bugs
+
+	Juha Sievanen, University of Helsinki Finland
+		LAN OSM code
+		/proc interface to LAN class
+		Bug fixes
+		Core code extensions
+
+	Auvo Häkkinen, University of Helsinki Finland
+		LAN OSM code
+		/Proc interface to LAN class
+		Bug fixes
+		Core code extensions
 
-Boji T Kannanthanam
-	Intel i2o controller work, extending proc/config stuff
+	Taneli Vähäkangas, University of Helsinki Finland
+		Fixes to i2o_config
 
-CREDITS
+	Boji T Kannanthanam
+		Intel i2o controller work, extending proc/config stuff
 
+Credits
+--------
 	This work was made possible by 
 
-Red Hat Software
+Red Hat
 	Funding for the Building #3 part of the project
 
 Symbios Logic (Now LSI)
@@ -68,33 +115,21 @@
 Promise
 	Providing a Supertrak 100 board and support info
 
-DPT
+DPT (now Adaptec)
 	Providing a DPT smartraid I2O card (use dpt_i2o for this
 	board however)
 
-STATUS:
-o	Should be stable for x86 32bit
-
-KNOWN ISSUES:
-o	Reports that intel boards die if you load i2o_block and i2o_scsi
-o	Some promise cards need firmware updates
-
-TO DO:
 
 General:
 o	Finish 64bit and big endian cleanup
 o	Switch to new PCI mapping layer throughout
 o	Hotswap of controllers
-o	Provide hidden address space if asked
-o	Long term message flow control
 o	PCI IOP's without interrupts are not supported yet
 o	Push FAIL handling into the core
-o	DDM control interfaces for module load etc
 
 Block:
 o	Multiple major numbers (problem goes away in 2.5)
 o	Power management
-o	Finish Media changers
 
 SCSI:
 
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_block.c linux-2.4.19-pre9/drivers/message/i2o/i2o_block.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_block.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_block.c	Tue May 28 16:02:29 2002
@@ -21,6 +21,11 @@
  *	Alan Cox:	
  *		FC920 has an rmw bug. Dont or in the end marker.
  *		Removed queue walk, fixed for 64bitness.
+ *		Rewrote much of the code over time
+ *		Added indirect block lists
+ *		Handle 64K limits on many controllers
+ *		Don't use indirects on the Promise (breaks)
+ *		Heavily chop down the queue depths
  *	Deepak Saxena:
  *		Independent queues per IOP
  *		Support for dynamic device creation/deletion
@@ -75,7 +80,7 @@
 
 #define MAX_I2OB	16
 
-#define MAX_I2OB_DEPTH	128
+#define MAX_I2OB_DEPTH	8
 #define MAX_I2OB_RETRIES 4
 
 //#define DRIVERDEBUG
@@ -140,9 +145,12 @@
 	struct request *head, *tail;
 	request_queue_t *req_queue;
 	int max_segments;
+	int max_direct;		/* Not yet used properly */
 	int done_flag;
-	int constipated;
 	int depth;
+	int rcache;
+	int wcache;
+	int power;
 };
 
 /*
@@ -150,6 +158,7 @@
  *	We should cache align these to avoid ping-ponging lines on SMP
  *	boxes under heavy I/O load...
  */
+
 struct i2ob_request
 {
 	struct i2ob_request *next;
@@ -173,8 +182,6 @@
 	request_queue_t req_queue;
 };
 static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS];
 
 /*
  *	Each I2O disk is one of these.
@@ -192,10 +199,7 @@
 static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);
 static DECLARE_COMPLETION(i2ob_thread_dead);
 static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
-static u32 evt_msg[MSG_FRAME_SIZE>>2];
-
-static struct timer_list i2ob_timer;
-static int i2ob_timer_started = 0;
+static u32 evt_msg[MSG_FRAME_SIZE];
 
 static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *,
 	 struct i2o_message *);
@@ -205,7 +209,6 @@
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
 static void i2ob_request(request_queue_t *);
-static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *);
 static int i2ob_init_iop(unsigned int);
 static request_queue_t* i2ob_get_queue(kdev_t);
 static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
@@ -230,8 +233,12 @@
 	I2O_CLASS_RANDOM_BLOCK_STORAGE
 };
 
-/*
- *	Get a message
+/**
+ *	i2ob_get	-	Get an I2O message
+ *	@dev:  I2O block device
+ *
+ *	Get a message from the FIFO used for this block device. The message is returned
+ *	or the I2O 'no message' value of 0xFFFFFFFF if nothing is available.
  */
 
 static u32 i2ob_get(struct i2ob_device *dev)
@@ -240,10 +247,24 @@
    	return I2O_POST_READ32(c);
 }
  
-/*
- *	Turn a Linux block request into an I2O block read/write.
+/**
+ *	i2ob_send		-	Turn a request into a message and send it
+ *	@m: Message offset
+ *	@dev: I2O device
+ *	@ireq: Request structure
+ *	@base: Partition offset
+ *	@unit: Device identity
+ *
+ *	Generate an I2O BSAREAD request. This interface function is called for devices that
+ *	appear to explode when they are fed indirect chain pointers (notably right now this
+ *	appears to afflict Promise hardwre, so be careful what you feed the hardware
+ *
+ *	No cleanup is done by this interface. It is done on the interrupt side when the
+ *	reply arrives
+ *
+ *	To Fix: Generate PCI maps of the buffers
  */
-
+ 
 static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit)
 {
 	struct i2o_controller *c = dev->controller;
@@ -290,9 +311,9 @@
 				size += bh->b_size;
 				last += bh->b_size;
 				if(bh->b_reqnext)
-					__raw_writel(0x14000000|(size), mptr-8);
+					__raw_writel(0x10000000|(size), mptr-8);
 				else
-					__raw_writel(0xD4000000|(size), mptr-8);
+					__raw_writel(0xD0000000|(size), mptr-8);
 			}
 			else
 			{
@@ -309,16 +330,22 @@
 			count -= bh->b_size;
 			bh = bh->b_reqnext;
 		}
-		/*
-		 *	Heuristic for now since the block layer doesnt give
-		 *	us enough info. If its a big write assume sequential
-		 *	readahead on controller. If its small then don't read
-		 *	ahead but do use the controller cache.
-		 */
-		if(size >= 8192)
-			__raw_writel((8<<24)|(1<<16)|8, msg+16);
-		else
-			__raw_writel((8<<24)|(1<<16)|4, msg+16);
+		switch(dev->rcache)
+		{
+			case CACHE_NULL:
+				__raw_writel(0, msg+16);break;
+			case CACHE_PREFETCH:
+				__raw_writel(0x201F0008, msg+16);break;
+			case CACHE_SMARTFETCH:
+				if(req->nr_sectors > 16)
+					__raw_writel(0x201F0008, msg+16);
+				else
+					__raw_writel(0x001F0000, msg+16);
+				break;
+		}				
+				
+//		printk("Reading %d entries %d bytes.\n",
+//			mptr-msg-8, req->nr_sectors<<9);
 	}
 	else if(req->cmd == WRITE)
 	{
@@ -350,28 +377,29 @@
 			bh = bh->b_reqnext;
 		}
 
-		if(c->battery)
-		{
-			
-			if(size>16384)
-				__raw_writel(4, msg+16);
-			else
-				/* 
-				 * Allow replies to come back once data is cached in the controller
-				 * This allows us to handle writes quickly thus giving more of the
-				 * queue to reads.
-				 */
-				__raw_writel(16, msg+16);
-		}
-		else
+		switch(dev->wcache)
 		{
-			/* Large write, don't cache */
-			if(size>8192)
-				__raw_writel(4, msg+16);
-			else
-			/* write through */
-				__raw_writel(8, msg+16);
+			case CACHE_NULL:
+				__raw_writel(0, msg+16);break;
+			case CACHE_WRITETHROUGH:
+				__raw_writel(0x001F0008, msg+16);break;
+			case CACHE_WRITEBACK:
+				__raw_writel(0x001F0010, msg+16);break;
+			case CACHE_SMARTBACK:
+				if(req->nr_sectors > 16)
+					__raw_writel(0x001F0004, msg+16);
+				else
+					__raw_writel(0x001F0010, msg+16);
+				break;
+			case CACHE_SMARTTHROUGH:
+				if(req->nr_sectors > 16)
+					__raw_writel(0x001F0004, msg+16);
+				else
+					__raw_writel(0x001F0010, msg+16);
 		}
+				
+//		printk("Writing %d entries %d bytes.\n",
+//			mptr-msg-8, req->nr_sectors<<9);
 	}
 	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
 	
@@ -405,6 +433,8 @@
  
 static inline void i2ob_end_request(struct request *req)
 {
+	/* FIXME  - pci unmap the request */
+
 	/*
 	 * Loop until all of the buffers that are linked
 	 * to this request have been marked updated and
@@ -423,6 +453,7 @@
 /*
  * Request merging functions
  */
+
 static inline int i2ob_new_segment(request_queue_t *q, struct request *req,
 				  int __max_segments)
 {
@@ -491,11 +522,11 @@
 	 *	thing for other cases too.
 	 */
 	 	
-	__raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
-	__raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
-	__raw_writel(i2ob_context|(unit<<8), msg+8);
-	__raw_writel(0, msg+12);
-	__raw_writel(60<<16, msg+16);
+	i2o_raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
+	i2o_raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
+	i2o_raw_writel(i2ob_context|(unit<<8), msg+8);
+	i2o_raw_writel(0, msg+12);
+	i2o_raw_writel(60<<16, msg+16);
 	DEBUG("FLUSH");
 	i2o_post_message(c,m);
 	return 0;
@@ -531,7 +562,7 @@
 		 * We increment the error count and abort it
 		 *
 		 * In theory this will never happen.  The I2O block class
-		 * speficiation states that block devices never return
+		 * specification states that block devices never return
 		 * FAILs but instead use the REQ status field...but
 		 * better be on the safe side since no one really follows
 		 * the spec to the book :)
@@ -561,17 +592,6 @@
 		return;
 	}
 
-	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
-	{
-		spin_lock_irqsave(&io_request_lock, flags);
-		dev->constipated=0;
-		DEBUG("unconstipated\n");
-		if(i2ob_backlog_request(c, dev)==0)
-			i2ob_request(dev->req_queue);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-
 	if(!dev->i2odev)
 	{
 		/*
@@ -629,64 +649,12 @@
 		 *	The second is that you have a SuperTrak 100 and the
 		 *	firmware got constipated. Unlike standard i2o card
 		 *	setups the supertrak returns an error rather than
-		 *	blocking for the timeout in these cases.
+		 *	blocking for the timeout in these cases. 
+		 *
+		 *	Don't stick a supertrak100 into cache aggressive modes
 		 */
 		 
 		
-		spin_lock_irqsave(&io_request_lock, flags);
-		if(err==4)
-		{
-			/*
-			 *	Time to uncork stuff
-			 */
-			
-			if(!dev->constipated)
-			{
-				dev->constipated = 1;
-				DEBUG(("constipated\n"));
-				/* Now pull the chain */
-				if(i2ob_flush(c, dev, unit)<0)
-				{
-					DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n"));
-					dev->constipated=0;
-				}
-				DEBUG(("flushing\n"));
-			}
-			
-			/*
-			 *	Recycle the request
-			 */
-			 
-//			i2ob_unhook_request(ireq, c->unit);
-			
-			/*
-			 *	Place it on the recycle queue
-			 */
-			 
-			ireq->next = NULL;
-			if(i2ob_backlog_tail[c->unit]!=NULL)
-				i2ob_backlog_tail[c->unit]->next = ireq;
-			else
-				i2ob_backlog[c->unit] = ireq;			
-			i2ob_backlog_tail[c->unit] = ireq;
-			
-			atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
-			/*
-			 *	If the constipator flush failed we want to
-			 *	poke the queue again. 
-			 */
-			 
-			i2ob_request(dev->req_queue);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			
-			/*
-			 *	and out
-			 */
-			 
-			return;	
-		}
-		spin_unlock_irqrestore(&io_request_lock, flags);
 		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
 			bsa_errors[m[4]&0XFFFF]);
 		if(m[4]&0x00FF0000)
@@ -706,14 +674,12 @@
 	i2ob_unhook_request(ireq, c->unit);
 	i2ob_end_request(ireq->req);
 	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
+	
 	/*
 	 *	We may be able to do more I/O
 	 */
-
-	if(i2ob_backlog_request(c, dev)==0)
-		i2ob_request(dev->req_queue);
-
+	 
+	i2ob_request(dev->req_queue);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
@@ -734,6 +700,7 @@
 		u32 evt_indicator;
 		u8 ASC;
 		u8 ASCQ;
+		u16 pad;
 		u8 data[16];
 		} *evt_local;
 
@@ -764,8 +731,8 @@
 		evt_local = (struct i2o_reply *)evt_msg;
 		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
 
-		unit = evt_local->header[3];
-		evt = evt_local->evt_indicator;
+		unit = le32_to_cpu(evt_local->header[3]);
+		evt = le32_to_cpu(evt_local->evt_indicator);
 
 		switch(evt)
 		{
@@ -864,6 +831,15 @@
 			 * An event we didn't ask for.  Call the card manufacturer
 			 * and tell them to fix their firmware :)
 			 */
+			 
+			case 0x20:
+				/*
+				 * If a promise card reports 0x20 event then the brown stuff
+				 * hit the fan big time. The card seems to recover but loses
+				 * the pending writes. Deeply ungood except for testing fsck
+				 */
+				if(i2ob_dev[unit].i2odev->controller->bus.pci.promise)
+					panic("I2O controller firmware failed. Reboot and force a filesystem check.\n");
 			default:
 				printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n"
 					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
@@ -877,68 +853,6 @@
 }
 
 /*
- * The timer handler will attempt to restart requests 
- * that are queued to the driver.  This handler
- * currently only gets called if the controller
- * had no more room in its inbound fifo.  
- */
-
-static void i2ob_timer_handler(unsigned long q)
-{
-	unsigned long flags;
-
-	/*
-	 * We cannot touch the request queue or the timer
-         * flag without holding the io_request_lock.
-	 */
-	spin_lock_irqsave(&io_request_lock,flags);
-
-	/* 
-	 * Clear the timer started flag so that 
-	 * the timer can be queued again.
-	 */
-	i2ob_timer_started = 0;
-
-	/* 
-	 * Restart any requests.
-	 */
-	i2ob_request((request_queue_t*)q);
-
-	/* 
-	 * Free the lock.
-	 */
-	spin_unlock_irqrestore(&io_request_lock,flags);
-}
-
-static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
-{
-	u32 m;
-	struct i2ob_request *ireq;
-	
-	while((ireq=i2ob_backlog[c->unit])!=NULL)
-	{
-		int unit;
-
-		if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4)
-			break;
-
-		m = i2ob_get(dev);
-		if(m == 0xFFFFFFFF)
-			break;
-
-		i2ob_backlog[c->unit] = ireq->next;
-		if(i2ob_backlog[c->unit] == NULL)
-			i2ob_backlog_tail[c->unit] = NULL;
-			
-		unit = MINOR(ireq->req->rq_dev);
-		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit);
-	}
-	if(i2ob_backlog[c->unit])
-		return 1;
-	return 0;
-}
-
-/*
  *	The I2O block driver is listed as one of those that pulls the
  *	front entry off the queue before processing it. This is important
  *	to remember here. If we drop the io lock then CURRENT will change
@@ -954,7 +868,6 @@
 	struct i2ob_device *dev;
 	u32 m;
 	
-	
 	while (!list_empty(&q->queue_head)) {
 		/*
 		 *	On an IRQ completion if there is an inactive
@@ -977,49 +890,15 @@
 		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
 			break;
 		
-		/*
-		 *	Is the channel constipated ?
-		 */
-
-		if(i2ob_backlog[dev->unit]!=NULL)
-			break;
-			
 		/* Get a message */
 		m = i2ob_get(dev);
 
 		if(m==0xFFFFFFFF)
 		{
-			/* 
-			 * See if the timer has already been queued.
-			 */
-			if (!i2ob_timer_started)
-			{
-				DEBUG((KERN_ERR "i2ob: starting timer\n"));
-
-				/*
-				 * Set the timer_started flag to insure
-				 * that the timer is only queued once.
-				 * Queing it more than once will corrupt
-				 * the timer queue.
-				 */
-				i2ob_timer_started = 1;
-
-				/* 
-				 * Set up the timer to expire in
-				 * 500ms.
-				 */
-				i2ob_timer.expires = jiffies + (HZ >> 1);
-				i2ob_timer.data = (unsigned int)q;
-
-				/*
-				 * Start it.
-				 */
-				 
-				add_timer(&i2ob_timer);
-				return;
-			}
+			if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) == 0)
+				printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n");
+			break;
 		}
-
 		/*
 		 * Everything ok, so pull from kernel queue onto our queue
 		 */
@@ -1151,11 +1030,6 @@
 
 	dev = &i2ob_dev[minor];
 	switch (cmd) {
-		case BLKGETSIZE:
-			return put_user(i2ob[minor].nr_sects, (long *) arg);
-		case BLKGETSIZE64:
-			return put_user((u64)i2ob[minor].nr_sects << 9, (u64 *)arg);
-
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry g;
@@ -1165,23 +1039,31 @@
 			g.start = i2ob[minor].start_sect;
 			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
 		}
+		
+		case BLKI2OGRSTRAT:
+			return put_user(dev->rcache, (int *)arg);
+		case BLKI2OGWSTRAT:
+			return put_user(dev->wcache, (int *)arg);
+		case BLKI2OSRSTRAT:
+			if(arg<0||arg>CACHE_SMARTFETCH)
+				return -EINVAL;
+			dev->rcache = arg;
+			break;
+		case BLKI2OSWSTRAT:
+			if(arg!=0 && (arg<CACHE_WRITETHROUGH || arg>CACHE_SMARTBACK))
+				return -EINVAL;
+			dev->wcache = arg;
+			break;
 	
 		case BLKRRPART:
 			if(!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			return do_i2ob_revalidate(inode->i_rdev,1);
 			
-		case BLKFLSBUF:
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-			
 		default:
-			return -EINVAL;
+			return blk_ioctl(inode->i_rdev, cmd, arg);
 	}
+	return 0;
 }
 
 /*
@@ -1219,7 +1101,7 @@
 		 */
 		u32 msg[5];
 		int *query_done = &dev->done_flag;
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[0] = (FIVE_WORD_MSG_SIZE|SGL_OFFSET_0);
 		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
 		msg[2] = i2ob_context|0x40000000;
 		msg[3] = (u32)query_done;
@@ -1238,7 +1120,17 @@
 		DEBUG("Unlocking...");
 		i2o_post_wait(dev->controller, msg, 20, 2);
 		DEBUG("Unlocked.\n");
-	
+
+		msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid;
+		if(dev->flags & (1<<3|1<<4))	/* Removable */
+			msg[4] = 0x21 << 24;
+		else
+			msg[4] = 0x24 << 24;
+
+		if(i2o_post_wait(dev->controller, msg, 20, 60)==0)
+			dev->power = 0x24;
+
 		/*
  		 * Now unclaim the device.
 		 */
@@ -1282,7 +1174,19 @@
 			return -EBUSY;
 		}
 		DEBUG("Claimed ");
-		
+		/*
+	 	 *	Power up if needed
+	 	 */
+
+		if(dev->power > 0x1f)
+		{
+			msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid;
+			msg[4] = 0x02 << 24;
+			if(i2o_post_wait(dev->controller, msg, 20, 60) == 0)
+				dev->power = 0x02;
+		}
+
 		/*
 		 *	Mount the media if needed. Note that we don't use
 		 *	the lock bit. Since we have to issue a lock if it
@@ -1329,8 +1233,8 @@
 {
 	u64 size;
 	u32 blocksize;
-	u32 limit;
 	u8 type;
+	u16 power;
 	u32 flags, status;
 	struct i2ob_device *dev=&i2ob_dev[unit];
 	int i;
@@ -1352,6 +1256,8 @@
 		i2ob_query_device(dev, 0x0000, 4, &size, 8);
 	}
 	
+	if(i2ob_query_device(dev, 0x0000, 2, &power, 2)!=0)
+		power = 0;
 	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
 	i2ob_sizes[unit] = (int)(size>>10);
@@ -1360,28 +1266,29 @@
 	i2ob_gendisk.part[unit].nr_sects = size>>9;
 	i2ob[unit].nr_sects = (int)(size>>9);
 
-	/* Set limit based on inbound frame size */
-	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
-	limit = limit<<9;
-
 	/*
 	 * Max number of Scatter-Gather Elements
 	 */	
 
+	i2ob_dev[unit].power = power;	/* Save power state in device proper */
+	i2ob_dev[unit].flags = flags;
+
 	for(i=unit;i<=unit+15;i++)
 	{
-		i2ob_max_sectors[i] = 256;
-		i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2;
-
-		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy == 2)
-			i2ob_dev[i].depth = 32;
+		i2ob_dev[i].power = power;	/* Save power state */
+		i2ob_dev[unit].flags = flags;	/* Keep the type info */
+		i2ob_max_sectors[i] = 96;	/* 256 might be nicer but many controllers 
+						   explode on 65536 or higher */
+		i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 7) / 2;
+		
+		i2ob_dev[i].rcache = CACHE_SMARTFETCH;
+		i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
+		
+		if(d->controller->battery == 0)
+			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
 
-		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy == 1)
-		{
-			i2ob_max_sectors[i] = 32;
-			i2ob_dev[i].max_segments = 8;
-			i2ob_dev[i].depth = 4;
-		}
+		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.promise)
+			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
 
 		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req)
 		{
@@ -1390,11 +1297,10 @@
 		}
 	}
 
-
 	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
 
 	printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n",
-		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, limit);
+		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, i2ob_max_sectors[unit]<<9);
 
 	i2ob_query_device(dev, 0x0000, 0, &type, 1);
 
@@ -1410,14 +1316,19 @@
 	}
 	if(status&(1<<10))
 		printk("(RAID)");
-	if(((flags & (1<<3)) && !(status & (1<<3))) ||
-	   ((flags & (1<<4)) && !(status & (1<<4))))
+
+	if((flags^status)&(1<<4|1<<3))	/* Missing media or device */
 	{
 		printk(KERN_INFO " Not loaded.\n");
-		return 1;
+		/* Device missing ? */
+		if((flags^status)&(1<<4))
+			return 1;
+	}
+	else
+	{
+		printk(": %dMB, %d byte sectors",
+			(int)(size>>20), blocksize);
 	}
-	printk(": %dMB, %d byte sectors",
-		(int)(size>>20), blocksize);
 	if(status&(1<<0))
 	{
 		u32 cachesize;
@@ -1427,7 +1338,6 @@
 			printk(", %dMb cache", cachesize>>10);
 		else
 			printk(", %dKb cache", cachesize);
-		
 	}
 	printk(".\n");
 	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
@@ -1471,7 +1381,7 @@
 {
 	int i;
 
-	i2ob_queues[unit] = (struct i2ob_iop_queue*) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
+	i2ob_queues[unit] = (struct i2ob_iop_queue *) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
 	if(!i2ob_queues[unit])
 	{
 		printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n");
@@ -1671,8 +1581,7 @@
 
 	if(i2o_claim_device(d, &i2o_block_handler))
 	{
-		printk(KERN_INFO 
-			"i2o_block: Unable to claim device. Installation aborted\n");
+		printk(KERN_INFO "i2o_block: Unable to claim device. Installation aborted\n");
 		return;
 	}
 
@@ -1859,11 +1768,7 @@
  *  (Just smiley confuses emacs :-)
  */
 
-#ifdef MODULE
-#define i2o_block_init init_module
-#endif
-
-int i2o_block_init(void)
+static int i2o_block_init(void)
 {
 	int i;
 
@@ -1918,14 +1823,6 @@
 	}
 
 	/*
-	 *	Timers
-	 */
-	 
-	init_timer(&i2ob_timer);
-	i2ob_timer.function = i2ob_timer_handler;
-	i2ob_timer.data = 0;
-	
-	/*
 	 *	Register the OSM handler as we will need this to probe for
 	 *	drives, geometry and other goodies.
 	 */
@@ -1968,15 +1865,8 @@
 	return 0;
 }
 
-#ifdef MODULE
 
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O Block Device OSM");
-MODULE_LICENSE("GPL");
-
-
-void cleanup_module(void)
+static void i2o_block_exit(void)
 {
 	int i;
 	
@@ -2036,4 +1926,11 @@
 
 	del_gendisk(&i2ob_gendisk);
 }
-#endif
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Block Device OSM");
+MODULE_LICENSE("GPL");
+
+module_init(i2o_block_init);
+module_exit(i2o_block_exit);
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_config.c linux-2.4.19-pre9/drivers/message/i2o/i2o_config.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_config.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_config.c	Tue May 28 16:02:29 2002
@@ -447,7 +447,7 @@
 	int token;
 	u32 len;
 	u32 reslen;
-	u32 msg[MSG_FRAME_SIZE/4];
+	u32 msg[MSG_FRAME_SIZE];
 
 	if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html)))
 	{
@@ -908,11 +908,7 @@
 	&config_fops
 };	
 
-#ifdef MODULE
-int init_module(void)
-#else
-int __init i2o_config_init(void)
-#endif
+static int __init i2o_config_init(void)
 {
 	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
 	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software\n");
@@ -946,9 +942,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-
-void cleanup_module(void)
+static void i2o_config_exit(void)
 {
 	misc_deregister(&i2o_miscdev);
 	
@@ -963,4 +957,5 @@
 MODULE_DESCRIPTION("I2O Configuration");
 MODULE_LICENSE("GPL");
 
-#endif
+module_init(i2o_config_init);
+module_exit(i2o_config_exit);
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_core.c linux-2.4.19-pre9/drivers/message/i2o/i2o_core.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_core.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_core.c	Tue May 28 16:02:29 2002
@@ -70,7 +70,7 @@
 static int core_context;
 
 /* Initialization && shutdown functions */
-static void i2o_sys_init(void);
+void i2o_sys_init(void);
 static void i2o_sys_shutdown(void);
 static int i2o_reset_controller(struct i2o_controller *);
 static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);
@@ -120,28 +120,6 @@
  */
 static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;
 
-#ifdef MODULE
-/* 
- * Function table to send to bus specific layers
- * See <include/linux/i2o.h> for explanation of this
- */
-static struct i2o_core_func_table i2o_core_functions =
-{
-	i2o_install_controller,
-	i2o_activate_controller,
-	i2o_find_controller,
-	i2o_unlock_controller,
-	i2o_run_queue,
-	i2o_delete_controller
-};
-
-#ifdef CONFIG_I2O_PCI_MODULE
-extern int i2o_pci_core_attach(struct i2o_core_func_table *);
-extern void i2o_pci_core_detach(void);
-#endif /* CONFIG_I2O_PCI_MODULE */
-
-#endif /* MODULE */
-
 /*
  * Structures and definitions for synchronous message posting.
  * See i2o_post_wait() for description.
@@ -2013,10 +1991,10 @@
  	 */
 	msg[6] = 0x54000000 | sys_tbl_len;
 	msg[7] = virt_to_bus(sys_tbl);
-	msg[8] = 0x54000000 | 8;
-	msg[9] = virt_to_bus(privbuf);
-	msg[10] = 0xD4000000 | 8;
-	msg[11] = virt_to_bus(privbuf+2);
+	msg[8] = 0x54000000 | privbuf[1];
+	msg[9] = privbuf[0];
+	msg[10] = 0xD4000000 | privbuf[3];
+	msg[11] = privbuf[2];
 
 	ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL);
 	
@@ -2044,7 +2022,7 @@
 /*
  * Initialize I2O subsystem.
  */
-static void __init i2o_sys_init(void)
+void __init i2o_sys_init(void)
 {
 	struct i2o_controller *iop, *niop = NULL;
 
@@ -2220,9 +2198,8 @@
 	msg[2]= core_context;
 	msg[3]= 0x0106;				/* Transaction context */
 	msg[4]= 4096;				/* Host page frame size */
-	/* Frame size is in words. Pick 128, its what everyone elses uses and
-		other sizes break some adapters. */
-	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size and Initcode */
+	/* Frame size is in words. 256 bytes a frame for now */
+	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size in words and Initcode */
 	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */
 	msg[7]= virt_to_bus(status);
 
@@ -2295,7 +2272,7 @@
 	for(i=0; i< NMBR_MSG_FRAMES; i++) {
 		I2O_REPLY_WRITE32(c,m);
 		mb();
-		m += MSG_FRAME_SIZE;
+		m += (MSG_FRAME_SIZE << 2);
 	}
 
 	return 0;
@@ -2479,9 +2456,8 @@
 		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
 		sys_tbl->iops[count].iop_capabilities = 
 				iop->status_block->iop_capabilities;
-		sys_tbl->iops[count].inbound_low = 
-				(u32)virt_to_bus(iop->post_port);
-		sys_tbl->iops[count].inbound_high = 0;	// TODO: 64-bit support
+		sys_tbl->iops[count].inbound_low = iop->post_port;
+		sys_tbl->iops[count].inbound_high = 0;	// FIXME: 64-bit support
 
 		count++;
 	}
@@ -3433,6 +3409,10 @@
 EXPORT_SYMBOL(i2o_install_handler);
 EXPORT_SYMBOL(i2o_remove_handler);
 
+EXPORT_SYMBOL(i2o_install_controller);
+EXPORT_SYMBOL(i2o_delete_controller);
+EXPORT_SYMBOL(i2o_run_queue);
+
 EXPORT_SYMBOL(i2o_claim_device);
 EXPORT_SYMBOL(i2o_release_device);
 EXPORT_SYMBOL(i2o_device_notify_on);
@@ -3457,37 +3437,27 @@
 
 EXPORT_SYMBOL(i2o_get_class_name);
 
-#ifdef MODULE
+EXPORT_SYMBOL_GPL(i2o_sys_init);
 
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
 MODULE_LICENSE("GPL");
 
-
-
-int init_module(void)
+static int i2o_core_init(void)
 {
 	printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
 	if (i2o_install_handler(&i2o_core_handler) < 0)
 	{
-		printk(KERN_ERR 
-			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+		printk(KERN_ERR "i2o_core: Unable to install core handler.\nI2O stack not loaded!");
 		return 0;
 	}
 
 	core_context = i2o_core_handler.context;
 
 	/*
-	 * Attach core to I2O PCI transport (and others as they are developed)
-	 */
-#ifdef CONFIG_I2O_PCI_MODULE
-	if(i2o_pci_core_attach(&i2o_core_functions) < 0)
-		printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
-#endif
-
-	/*
 	 * Initialize event handling thread
 	 */	
+
 	init_MUTEX_LOCKED(&evt_sem);
 	evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND);
 	if(evt_pid < 0)
@@ -3507,7 +3477,7 @@
 	return 0;
 }
 
-void cleanup_module(void)
+static void i2o_core_exit(void)
 {
 	int stat;
 
@@ -3528,73 +3498,10 @@
 		}
 		printk("done.\n");
 	}
-
-#ifdef CONFIG_I2O_PCI_MODULE
-	i2o_pci_core_detach();
-#endif
-
 	i2o_remove_handler(&i2o_core_handler);
-
 	unregister_reboot_notifier(&i2o_reboot_notifier);
 }
 
-#else
-
-extern int i2o_block_init(void);
-extern int i2o_config_init(void);
-extern int i2o_lan_init(void);
-extern int i2o_pci_init(void);
-extern int i2o_proc_init(void);
-extern int i2o_scsi_init(void);
-
-int __init i2o_init(void)
-{
-	printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n");
-	
-	if (i2o_install_handler(&i2o_core_handler) < 0)
-	{
-		printk(KERN_ERR 
-			"i2o_core: Unable to install core handler.\nI2O stack not loaded!");
-		return 0;
-	}
-
-	core_context = i2o_core_handler.context;
-
-	/*
-	 * Initialize event handling thread
-	 * We may not find any controllers, but still want this as 
-	 * down the road we may have hot pluggable controllers that
-	 * need to be dealt with.
-	 */	
-	init_MUTEX_LOCKED(&evt_sem);
-	if((evt_pid = kernel_thread(i2o_core_evt, &evt_reply, CLONE_SIGHAND)) < 0)
-	{
-		printk(KERN_ERR "I2O: Could not create event handler kernel thread\n");
-		i2o_remove_handler(&i2o_core_handler);
-		return 0;
-	}
-
+module_init(i2o_core_init);
+module_exit(i2o_core_exit);
 
-#ifdef CONFIG_I2O_PCI
-	i2o_pci_init();
-#endif
-
-	if(i2o_num_controllers)
-		i2o_sys_init();
-
-	register_reboot_notifier(&i2o_reboot_notifier);
-
-	i2o_config_init();
-#ifdef CONFIG_I2O_BLOCK
-	i2o_block_init();
-#endif
-#ifdef CONFIG_I2O_LAN
-	i2o_lan_init();
-#endif
-#ifdef CONFIG_I2O_PROC
-	i2o_proc_init();
-#endif
-	return 0;
-}
-
-#endif
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_lan.c linux-2.4.19-pre9/drivers/message/i2o/i2o_lan.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_lan.c	Mon Oct 22 08:39:56 2001
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_lan.c	Tue May 28 16:02:29 2002
@@ -1430,11 +1430,7 @@
 	return dev;
 }
 
-#ifdef MODULE
-#define i2o_lan_init	init_module
-#endif
-
-int __init i2o_lan_init(void)
+static int __init i2o_lan_init(void)
 {
 	struct net_device *dev;
 	int i;
@@ -1515,9 +1511,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-
-void cleanup_module(void)
+static void i2o_lan_exit(void)
 {
 	int i;
 
@@ -1576,4 +1570,5 @@
 MODULE_PARM(tx_batch_mode, "0-2" "i");
 MODULE_PARM_DESC(tx_batch_mode, "0=Send immediatelly, 1=Send in batches, 2=Switch automatically");
 
-#endif
+module_init(i2o_lan_init);
+module_exit(i2o_lan_exit);
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_pci.c linux-2.4.19-pre9/drivers/message/i2o/i2o_pci.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_pci.c	Thu Oct 25 13:53:47 2001
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_pci.c	Tue May 28 16:02:29 2002
@@ -15,6 +15,8 @@
  *
  *	TODO:
  *		Support polled I2O PCI controllers. 
+ *		2.4 hotplug support
+ *		Finish verifying 64bit/bigendian clean
  */
 
 #include <linux/config.h>
@@ -31,21 +33,17 @@
 #include <asm/mtrr.h>
 #endif // CONFIG_MTRR
 
-#ifdef MODULE
-/*
- * Core function table
- * See <include/linux/i2o.h> for an explanation
- */
-static struct i2o_core_func_table *core;
-
-/* Core attach function */
-extern int i2o_pci_core_attach(struct i2o_core_func_table *);
-extern void i2o_pci_core_detach(void);
-#endif /* MODULE */
+static int dpt = 0;
 
-/*
- *	Free bus specific resources
+
+/**
+ *	i2o_pci_dispose		-	Free bus specific resources
+ *	@c: I2O controller
+ *
+ *	Disable interrupts and then free interrupt, I/O and mtrr resources 
+ *	used by this controller. Called by the I2O core on unload.
  */
+ 
 static void i2o_pci_dispose(struct i2o_controller *c)
 {
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
@@ -61,9 +59,13 @@
 #endif
 }
 
-/*
- *	No real bus specific handling yet (note that later we will
- *	need to 'steal' PCI devices on i960 mainboards)
+/**
+ *	i2o_pci_bind		-	Bind controller and devices
+ *	@c: i2o controller
+ *	@dev: i2o device
+ *
+ *	Bind a device driver to a controller. In the case of PCI all we need to do
+ *	is module housekeeping.
  */
  
 static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev)
@@ -72,51 +74,83 @@
 	return 0;
 }
 
+/**
+ *	i2o_pci_unbind		-	Bind controller and devices
+ *	@c: i2o controller
+ *	@dev: i2o device
+ *
+ *	Unbind a device driver from a controller. In the case of PCI all we need to do
+ *	is module housekeeping.
+ */
+ 
+
 static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev)
 {
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-/*
- * Bus specific enable/disable functions
+/**
+ *	i2o_pci_enable		-	Enable controller
+ *	@c: controller
+ *
+ *	Called by the I2O core code in order to enable bus specific
+ *	resources for this controller. In our case that means unmasking the 
+ *	interrupt line.
  */
+
 static void i2o_pci_enable(struct i2o_controller *c)
 {
 	I2O_IRQ_WRITE32(c, 0);
 	c->enabled = 1;
 }
 
+/**
+ *	i2o_pci_disable		-	Enable controller
+ *	@c: controller
+ *
+ *	Called by the I2O core code in order to enable bus specific
+ *	resources for this controller. In our case that means masking the 
+ *	interrupt line.
+ */
+
 static void i2o_pci_disable(struct i2o_controller *c)
 {
 	I2O_IRQ_WRITE32(c, 0xFFFFFFFF);
 	c->enabled = 0;
 }
 
-/*
- *	Bus specific interrupt handler
+/**
+ *	i2o_pci_interrupt	-	Bus specific interrupt handler
+ *	@irq: interrupt line
+ *	@dev_id: cookie
+ *
+ *	Handle an interrupt from a PCI based I2O controller. This turns out
+ *	to be rather simple. We keep the controller pointer in the cookie.
  */
  
 static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
 {
 	struct i2o_controller *c = dev_id;
-#ifdef MODULE
-	core->run_queue(c);
-#else
 	i2o_run_queue(c);
-#endif /* MODULE */
 }	
 
-/*
- *	Install a PCI (or in theory AGP) i2o controller
+/**
+ *	i2o_pci_install		-	Install a PCI i2o controller
+ *	@dev: PCI device of the I2O controller
+ *
+ *	Install a PCI (or in theory AGP) i2o controller. Devices are
+ *	initialized, configured and registered with the i2o core subsystem. Be
+ *	very careful with ordering. There may be pending interrupts.
  *
- * TODO: Add support for polled controllers
+ *	To Do: Add support for polled controllers
  */
+
 int __init i2o_pci_install(struct pci_dev *dev)
 {
 	struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller),
 						GFP_KERNEL);
-	u8 *mem;
+	unsigned long mem;
 	u32 memptr = 0;
 	u32 size;
 	
@@ -150,8 +184,8 @@
 	/* Map the I2O controller */
 	
 	printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
-	mem = ioremap(memptr, size);
-	if(mem==NULL)
+	mem = (unsigned long)ioremap(memptr, size);
+	if(mem==0)
 	{
 		printk(KERN_ERR "i2o: Unable to map controller.\n");
 		kfree(c);
@@ -159,17 +193,16 @@
 	}
 
 	c->bus.pci.irq = -1;
-	c->bus.pci.queue_buggy = 0;
 	c->bus.pci.dpt = 0;
 	c->bus.pci.short_req = 0;
 	c->pdev = dev;
 
-	c->irq_mask = (volatile u32 *)(mem+0x34);
-	c->post_port = (volatile u32 *)(mem+0x40);
-	c->reply_port = (volatile u32 *)(mem+0x44);
+	c->irq_mask = mem+0x34;
+	c->post_port = mem+0x40;
+	c->reply_port = mem+0x44;
 
 	c->mem_phys = memptr;
-	c->mem_offset = (u32)mem;
+	c->mem_offset = mem;
 	c->destructor = i2o_pci_dispose;
 	
 	c->bind = i2o_pci_bind;
@@ -186,14 +219,12 @@
 	 
 	if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630)
 	{
-		c->bus.pci.short_req=1;
+		c->bus.pci.short_req = 1;
 		printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n");
 	}
 	if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE)
 	{
-		c->bus.pci.queue_buggy=1;
-		if (dev->subsystem_device == 0x0000) /* SX6000 ???? */
-			c->bus.pci.queue_buggy=2;
+		c->bus.pci.promise = 1;
 		printk(KERN_INFO "I2O: Promise workarounds activated.\n");
 	}
 
@@ -211,10 +242,11 @@
 #ifdef CONFIG_MTRR
 	c->bus.pci.mtrr_reg0 =
 		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
-/*
-* If it is an INTEL i960 I/O processor then set the first 64K to Uncacheable
-* since the region contains the Messaging unit which shouldn't be cached.
-*/
+	/*
+	 * If it is an INTEL i960 I/O processor then set the first 64K to
+	 * Uncacheable since the region contains the Messaging unit which
+	 * shouldn't be cached.
+	 */
 	c->bus.pci.mtrr_reg1 = -1;
 	if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT)
 	{
@@ -232,17 +264,13 @@
 
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
 
-#ifdef MODULE
-	i = core->install(c);
-#else
 	i = i2o_install_controller(c);
-#endif /* MODULE */
 	
 	if(i<0)
 	{
 		printk(KERN_ERR "i2o: Unable to install controller.\n");
 		kfree(c);
-		iounmap(mem);
+		iounmap((void *)mem);
 		return i;
 	}
 
@@ -256,12 +284,8 @@
 			printk(KERN_ERR "%s: unable to allocate interrupt %d.\n",
 				c->name, dev->irq);
 			c->bus.pci.irq = -1;
-#ifdef MODULE
-			core->delete(c);
-#else
 			i2o_delete_controller(c);
-#endif /* MODULE */	
-			iounmap(mem);
+			iounmap((void *)mem);
 			return -EBUSY;
 		}
 	}
@@ -272,6 +296,16 @@
 	return 0;	
 }
 
+/**
+ *	i2o_pci_scan	-	Scan the pci bus for controllers
+ *	
+ *	Scan the PCI devices on the system looking for any device which is a 
+ *	memory of the Intelligent, I2O class. We attempt to set up each such device
+ *	and register it with the core.
+ *
+ *	Returns the number of controllers registered
+ */
+ 
 int __init i2o_pci_scan(void)
 {
 	struct pci_dev *dev;
@@ -283,7 +317,7 @@
 	{
 		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
 			continue;
-		if(dev->vendor == PCI_VENDOR_ID_DPT)
+		if(dev->vendor == PCI_VENDOR_ID_DPT && !dpt)
 		{
 			if(dev->device == 0xA501 || dev->device == 0xA511)
 			{
@@ -310,84 +344,44 @@
 	return count?count:-ENODEV;
 }
 
-#ifdef I2O_HOTPLUG_SUPPORT
-/*
- * Activate a newly found PCI I2O controller
- * Not used now, but will be needed in future for
- * hot plug PCI support
+
+/**
+ *	i2o_pci_core_attach	-	PCI initialisation for I2O
+ *
+ *	Find any I2O controllers and if present initialise them and bring up
+ *	the I2O subsystem.
+ *
+ *	Returns 0 on success or an error code
  */
-static void i2o_pci_activate(i2o_controller * c)
+ 
+static int i2o_pci_core_attach(void)
 {
-	int i=0;
-	struct i2o_controller *c;
-	
-	if(c->type == I2O_TYPE_PCI)
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+	if(i2o_pci_scan()>0)
 	{
-		I2O_IRQ_WRITE32(c,0);
-#ifdef MODULE
-		if(core->activate(c))
-#else
-		if(i2o_activate_controller(c))
-#endif /* MODULE */
-		{
-			printk("%s: Failed to initialize.\n", c->name);
-#ifdef MODULE
-			core->unlock(c);
-			core->delete(c);
-#else
-			i2o_unlock_controller(c);
-			i2o_delete_controller(c);
-#endif
-			continue;
-		}
+		i2o_sys_init();
+		return 0;
 	}
-}
-#endif // I2O_HOTPLUG_SUPPORT
-
-#ifdef MODULE
-
-int i2o_pci_core_attach(struct i2o_core_func_table *table)
-{
-	MOD_INC_USE_COUNT;
-
-	core = table;
-
-	return i2o_pci_scan();
-}
-
-void i2o_pci_core_detach(void)
-{
-	core = NULL;
-
-	MOD_DEC_USE_COUNT;
+	return -ENODEV;
 }
 
-int init_module(void)
-{
-	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
-	
-	core = NULL;
-
- 	return 0;
+/**
+ *	i2o_pci_core_detach	-	PCI unload for I2O
+ *
+ *	Free up any resources not released when the controllers themselves were
+ *	shutdown and unbound from the bus and drivers
+ */
  
-}
-
-void cleanup_module(void)
+static void i2o_pci_core_detach(void)
 {
 }
 
-EXPORT_SYMBOL(i2o_pci_core_attach);
-EXPORT_SYMBOL(i2o_pci_core_detach);
-
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O PCI Interface");
 MODULE_LICENSE("GPL");
 
-
-#else
-void __init i2o_pci_init(void)
-{
-	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
-	i2o_pci_scan();
-}
-#endif
+MODULE_PARM(dpt, "i");
+MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o");
+module_init(i2o_pci_core_attach);
+module_exit(i2o_pci_core_detach);
+ 
\ No newline at end of file
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_proc.c linux-2.4.19-pre9/drivers/message/i2o/i2o_proc.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_proc.c	Thu Oct 25 13:53:47 2001
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_proc.c	Tue May 28 16:02:29 2002
@@ -20,18 +20,12 @@
  *   LAN entries by Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
  *		    Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
  *   University of Helsinki, Department of Computer Science
- */
-
-/*
- * set tabstop=3
- */
-
-/*
- * TODO List
  *
- * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
- *   is available to test with
- * - Clean up code to use official structure definitions 
+ *   Some cleanup (c) 2002 Red Hat <alan@redhat.com>
+ *   Working to make I2O 64bit safe and following the PCI API
+ *
+ *   TODO List
+ *	- Clean up code to use official structure definitions 
  */
 
 // FIXME!
@@ -3371,8 +3365,5 @@
 	i2o_remove_handler(&i2o_proc_handler);
 }
 
-#ifdef MODULE
 module_init(i2o_proc_init);
-#endif
 module_exit(i2o_proc_exit);
-
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_scsi.c linux-2.4.19-pre9/drivers/message/i2o/i2o_scsi.c
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_scsi.c	Mon Oct 22 08:39:56 2001
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_scsi.c	Tue May 28 16:02:29 2002
@@ -119,14 +119,12 @@
 	int i;
 	unsigned long flags;
 	
-	save_flags(flags);
-	cli();
-
+	spin_lock_irqsave(&io_request_lock, flags);
 	for(i=0;i<retry_ct;i++)
 		i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
 	retry_ct=0;
 	
-	restore_flags(flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 static void flush_pending(void)
@@ -134,8 +132,7 @@
 	int i;
 	unsigned long flags;
 	
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&io_request_lock, flags);
 
 	for(i=0;i<retry_ct;i++)
 	{
@@ -145,7 +142,7 @@
 	}
 	retry_ct=0;
 	
-	restore_flags(flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
@@ -212,9 +209,9 @@
 	 *	Low byte is device status, next is adapter status,
 	 *	(then one byte reserved), then request status.
 	 */
-	ds=(u8)m[4]; 
-	as=(u8)(m[4]>>8);
-	st=(u8)(m[4]>>24);
+	ds=(u8)le32_to_cpu(m[4]); 
+	as=(u8)le32_to_cpu(m[4]>>8);
+	st=(u8)le32_to_cpu(m[4]>>24);
 	
 	dprintk(("i2o got a scsi reply %08X: ", m[0]));
 	dprintk(("m[2]=%08X: ", m[2]));
@@ -231,7 +228,10 @@
 		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
 		return;
 	}
-	
+
+	/*
+ 	 *	FIXME: 64bit breakage
+	 */
 	current_command = (Scsi_Cmnd *)m[3];
 	
 	/*
@@ -252,11 +252,11 @@
 	
 	if(st == 0x06)
 	{
-		if(m[5] < current_command->underflow)
+		if(le32_to_cpu(m[5]) < current_command->underflow)
 		{
 			int i;
 			printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n",
-				m[5], current_command->underflow);
+				le32_to_cpu(m[5]), current_command->underflow);
 			printk("Cmd: ");
 			for(i=0;i<15;i++)
 				printk("%02X ", current_command->cmnd[i]);
@@ -319,7 +319,7 @@
 	return 0;
 }
 
-void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
 {
 	struct i2o_device *unit;
 	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
@@ -379,7 +379,7 @@
 	}		
 }
 
-int i2o_scsi_detect(Scsi_Host_Template * tpnt)
+static int i2o_scsi_detect(Scsi_Host_Template * tpnt)
 {
 	unsigned long flags;
 	struct Scsi_Host *shpnt = NULL;
@@ -473,7 +473,7 @@
 	return count;
 }
 
-int i2o_scsi_release(struct Scsi_Host *host)
+static int i2o_scsi_release(struct Scsi_Host *host)
 {
 	if(--i2o_scsi_hosts==0)
 	{
@@ -490,45 +490,14 @@
 }
 
 
-const char *i2o_scsi_info(struct Scsi_Host *SChost)
+static const char *i2o_scsi_info(struct Scsi_Host *SChost)
 {
 	struct i2o_scsi_host *hostdata;
-
 	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
-
 	return(&hostdata->controller->name[0]);
 }
 
-
-/*
- * From the wd93 driver:
- * Returns true if there will be a DATA_OUT phase with this command, 
- * false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- *
- */
-static int is_dir_out(Scsi_Cmnd *cmd)
-{
-	switch (cmd->cmnd[0]) 
-	{
-     		case WRITE_6:           case WRITE_10:          case WRITE_12:
-      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
-      		case WRITE_VERIFY:      case WRITE_VERIFY_12:      
-      		case COMPARE:           case COPY:              case COPY_VERIFY:
-      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
-      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
-      		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
-      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
-      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
-      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
-      		case 0xea:
-        		return 1;
-		default:
-        		return 0;
-	}
-}
-
-int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	int i;
 	int tid;
@@ -594,9 +563,10 @@
 	do
 	{
 		mb();
-		m = I2O_POST_READ32(c);
+		m = le32_to_cpu(I2O_POST_READ32(c));
 	}
 	while(m==0xFFFFFFFF);
+
 	msg = (u32 *)(c->mem_offset + m);
 	
 	/*
@@ -606,28 +576,29 @@
 	len = SCpnt->request_bufflen;
 	direction = 0x00000000;			// SGL IN  (osm<--iop)
 	
-	/*
-	 *	The scsi layer should be handling this stuff
-	 */
-	
-	scsidir = 0x00000000;			// DATA NO XFER
-	if(len)
+	if(SCpnt->sc_data_direction == SCSI_DATA_NONE)
+		scsidir = 0x00000000;			// DATA NO XFER
+	else if(SCpnt->sc_data_direction == SCSI_DATA_WRITE)
 	{
-		if(is_dir_out(SCpnt))
-		{
-			direction=0x04000000;	// SGL OUT  (osm-->iop)
-			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
-		}
-		else
-		{
-			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
-		}
+		direction=0x04000000;	// SGL OUT  (osm-->iop)
+		scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+	}
+	else if(SCpnt->sc_data_direction == SCSI_DATA_READ)
+	{
+		scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+	}
+	else
+	{
+		/* Unknown - kill the command */
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
 	}
 	
-	__raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
+	i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
+	i2o_raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
 	/* Sorry 64bit folks. FIXME */
-	__raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
+	i2o_raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
 
 	/* LSI_920_PCI_QUIRK
 	 *
@@ -670,7 +641,7 @@
 	}
 
 	/* Direction, disconnect ok, tag, CDBLen */
-	__raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
+	i2o_raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
 
 	mptr=msg+5;
 
@@ -690,6 +661,8 @@
 	 *	FIXME: we need to set the sglist limits according to the 
 	 *	message size of the I2O controller. We might only have room
 	 *	for 6 or so worst case
+	 *
+	 *	FIXME: pci dma mapping
 	 */
 	
 	if(SCpnt->use_sg)
@@ -705,8 +678,8 @@
 			/*
 			 *	Need to chain!
 			 */
-			__raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
-			__raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
+			i2o_raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
+			i2o_raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
 			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
 			if (SCpnt->use_sg > max_sg_len)
 			{
@@ -729,22 +702,22 @@
 		{		
 			for(i = 0 ; i < SCpnt->use_sg; i++)
 			{
-				__raw_writel(direction|0x10000000|sg->length, mptr++);
+				i2o_raw_writel(direction|0x10000000|sg->length, mptr++);
 				len+=sg->length;
-				__raw_writel(virt_to_bus(sg->address), mptr++);
+				i2o_raw_writel(virt_to_bus(sg->address), mptr++);
 				sg++;
 			}
 
 			/* Make this an end of list. Again evade the 920 bug and
 			   unwanted PCI read traffic */
 		
-			__raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
+			i2o_raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
 		}
 		
 		if(!chain)
 			reqlen = mptr - msg;
 		
-		__raw_writel(len, lenptr);
+		i2o_raw_writel(len, lenptr);
 		
 		if(len != SCpnt->underflow)
 			printk("Cmd len %08X Cmd underflow %08X\n",
@@ -754,15 +727,15 @@
 	{
 		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
 				SCpnt->request_bufflen));
-		__raw_writel(len = SCpnt->request_bufflen, lenptr);
+		i2o_raw_writel(len = SCpnt->request_bufflen, lenptr);
 		if(len == 0)
 		{
 			reqlen = 9;
 		}
 		else
 		{
-			__raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
-			__raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
+			i2o_raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
+			i2o_raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
 		}
 	}
 	
@@ -770,7 +743,7 @@
 	 *	Stick the headers on 
 	 */
 
-	__raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
+	i2o_raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
 	
 	/* Queue the message */
 	i2o_post_message(c,m);
@@ -794,7 +767,7 @@
 	SCpnt->SCp.Status++;
 }
 
-int i2o_scsi_command(Scsi_Cmnd * SCpnt)
+static int i2o_scsi_command(Scsi_Cmnd * SCpnt)
 {
 	i2o_scsi_queuecommand(SCpnt, internal_done);
 	SCpnt->SCp.Status = 0;
@@ -803,12 +776,12 @@
 	return SCpnt->result;
 }
 
-int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
+static int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
 {
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
-	u32 *msg;
+	unsigned long msg;
 	u32 m;
 	int tid;
 	
@@ -832,30 +805,30 @@
 	do
 	{
 		mb();
-		m = I2O_POST_READ32(c);
+		m = le32_to_cpu(I2O_POST_READ32(c));
 	}
 	while(m==0xFFFFFFFF);
-	msg = (u32 *)(c->mem_offset + m);
+	msg = c->mem_offset + m;
 	
-	__raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);
-	__raw_writel(0, &msg[3]);	/* Not needed for an abort */
-	__raw_writel((u32)SCpnt, &msg[4]);	
+	i2o_raw_writel(FIVE_WORD_MSG_SIZE, msg);
+	i2o_raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, msg+4);
+	i2o_raw_writel(scsi_context, msg+8);
+	i2o_raw_writel(0, msg+12);	/* Not needed for an abort */
+	i2o_raw_writel((u32)SCpnt, msg+16);	/* FIXME 32bitism */
 	wmb();
 	i2o_post_message(c,m);
 	wmb();
 	return SCSI_ABORT_PENDING;
 }
 
-int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
 	int tid;
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
 	u32 m;
-	u32 *msg;
+	unsigned long msg;
 
 	/*
 	 *	Find the TID for the bus
@@ -874,7 +847,7 @@
 	 *	possibly ?
 	 */
 	 
-	m = I2O_POST_READ32(c);
+	m = le32_to_cpu(I2O_POST_READ32(c));
 	
 	/*
 	 *	No free messages, try again next time - no big deal
@@ -883,13 +856,13 @@
 	if(m == 0xFFFFFFFF)
 		return SCSI_RESET_PUNT;
 	
-	msg = (u32 *)(c->mem_offset + m);
-	__raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context|0x80000000, &msg[2]);
+	msg = c->mem_offset + m;
+	i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
+	i2o_raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, msg+4);
+	i2o_raw_writel(scsi_context|0x80000000, msg+8);
 	/* We use the top bit to split controller and unit transactions */
 	/* Now store unit,tid so we can tie the completion back to a specific device */
-	__raw_writel(c->unit << 16 | tid, &msg[3]);
+	i2o_raw_writel(c->unit << 16 | tid, msg+12);
 	wmb();
 	i2o_post_message(c,m);
 	return SCSI_RESET_PENDING;
@@ -899,7 +872,7 @@
  *	This is anyones guess quite frankly.
  */
  
-int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
+static int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip)
 {
 	int size;
 
diff -urN linux-2.4.19-pre8/drivers/message/i2o/i2o_scsi.h linux-2.4.19-pre9/drivers/message/i2o/i2o_scsi.h
--- linux-2.4.19-pre8/drivers/message/i2o/i2o_scsi.h	Mon Dec 11 13:20:04 2000
+++ linux-2.4.19-pre9/drivers/message/i2o/i2o_scsi.h	Tue May 28 16:02:29 2002
@@ -14,15 +14,15 @@
 #define I2O_SCSI_CAN_QUEUE 4
 #define I2O_SCSI_CMD_PER_LUN 6
 
-extern int i2o_scsi_detect(Scsi_Host_Template *);
-extern const char *i2o_scsi_info(struct Scsi_Host *);
-extern int i2o_scsi_command(Scsi_Cmnd *);
-extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int i2o_scsi_abort(Scsi_Cmnd *);
-extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
-extern int i2o_scsi_bios_param(Disk *, kdev_t, int *);
+static int i2o_scsi_detect(Scsi_Host_Template *);
+static const char *i2o_scsi_info(struct Scsi_Host *);
+static int i2o_scsi_command(Scsi_Cmnd *);
+static int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int i2o_scsi_abort(Scsi_Cmnd *);
+static int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
+static int i2o_scsi_bios_param(Disk *, kdev_t, int *);
 extern void i2o_scsi_setup(char *str, int *ints);
-extern int i2o_scsi_release(struct Scsi_Host *host);
+static int i2o_scsi_release(struct Scsi_Host *host);
 
 #define I2OSCSI {                                          \
 		  next: NULL,				    \
diff -urN linux-2.4.19-pre8/drivers/net/acenic.c linux-2.4.19-pre9/drivers/net/acenic.c
--- linux-2.4.19-pre8/drivers/net/acenic.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/net/acenic.c	Tue May 28 16:02:29 2002
@@ -2692,7 +2692,7 @@
 	flagsize &= ~BD_FLG_COAL_NOW;
 #endif
 
-	if (!ACE_IS_TIGON_I(ap)) {
+	if (ACE_IS_TIGON_I(ap)) {
 		writel(addr >> 32, &desc->addr.addrhi);
 		writel(addr & 0xffffffff, &desc->addr.addrlo);
 		writel(flagsize, &desc->flagsize);
diff -urN linux-2.4.19-pre8/drivers/net/declance.c linux-2.4.19-pre9/drivers/net/declance.c
--- linux-2.4.19-pre8/drivers/net/declance.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/net/declance.c	Tue May 28 16:02:29 2002
@@ -791,6 +791,8 @@
 	ib->mode = 0;
 	ib->filter [0] = 0;
 	ib->filter [2] = 0;
+	ib->filter [4] = 0;
+	ib->filter [6] = 0;
 
 	lance_init_ring(dev);
 	load_csrs(lp);
@@ -943,9 +945,9 @@
 		if (!(*addrs & 1))
 			continue;
 
-		crc = ether_crc(6, addrs);
+		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
-		mcast_table[crc >> 3] |= 1 << (crc & 0xf);
+		mcast_table[2 * (crc >> 4)] |= 1 << (crc & 0xf);
 	}
 	return;
 }
diff -urN linux-2.4.19-pre8/drivers/net/epic100.c linux-2.4.19-pre9/drivers/net/epic100.c
--- linux-2.4.19-pre8/drivers/net/epic100.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/net/epic100.c	Tue May 28 16:02:29 2002
@@ -582,7 +582,7 @@
 #define EE_READ256_CMD	(6 << 8)
 #define EE_ERASE_CMD	(7 << 6)
 
-static int read_eeprom(long ioaddr, int location)
+static int __devinit read_eeprom(long ioaddr, int location)
 {
 	int i;
 	int retval = 0;
diff -urN linux-2.4.19-pre8/drivers/net/ppp_deflate.c linux-2.4.19-pre9/drivers/net/ppp_deflate.c
--- linux-2.4.19-pre8/drivers/net/ppp_deflate.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre9/drivers/net/ppp_deflate.c	Tue May 28 16:02:29 2002
@@ -657,4 +657,4 @@
 
 module_init(deflate_init);
 module_exit(deflate_cleanup);
-MODULE_LICENSE("BSD without advertisement clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -urN linux-2.4.19-pre8/drivers/net/skfp/h/fplustm.h linux-2.4.19-pre9/drivers/net/skfp/h/fplustm.h
--- linux-2.4.19-pre8/drivers/net/skfp/h/fplustm.h	Fri May 12 11:43:26 2000
+++ linux-2.4.19-pre9/drivers/net/skfp/h/fplustm.h	Tue May 28 16:02:29 2002
@@ -50,38 +50,82 @@
 	u_long err_tkerr ;		/* token error */
 } ;
 
+#define SK_XD_ALIGN     (size_t) 32
+
 /*
  *	Transmit Descriptor struct
  */
+struct s_dummy_txd {
+        u_int txd_tbctrl ;              /* transmit buffer control */
+        u_int txd_txdscr ;              /* transmit frame status word */
+        u_int txd_tbadr ;               /* physical tx buffer address */
+        u_int txd_ntdadr ;              /* physical pointer to the next TxD */
+#ifdef  ENA_64BIT_SUP
+        u_int txd_tbadr_hi ;            /* physical tx buffer addr(high dword)*/
+#endif 
+        caddr_t txd_virt ;              /* virtual pointer to the data frag */
+                                        /* virt pointer to the next TxD */
+        struct s_smt_fp_txd volatile far *txd_next ;
+        struct s_txd_os txd_os ;        /* OS - specific struct */ 
+	/* No padding here! */
+} ;
+
+#define SK_DUMMY_TXD	sizeof(struct s_dummy_txd)
+#define SK_TXD_PAD	(((SK_DUMMY_TXD+SK_XD_ALIGN-1) \
+				& ~(SK_XD_ALIGN-1))-SK_DUMMY_TXD)
 struct s_smt_fp_txd {
 	u_int txd_tbctrl ;		/* transmit buffer control */
 	u_int txd_txdscr ;		/* transmit frame status word */
 	u_int txd_tbadr ;		/* physical tx buffer address */
 	u_int txd_ntdadr ;		/* physical pointer to the next TxD */
 #ifdef	ENA_64BIT_SUP
-	u_int txd_tbadr_hi ;		/* physical tx buffer addr (high dword)*/
+	u_int txd_tbadr_hi ;		/* physical tx buffer addr(high dword)*/
 #endif
-	char far *txd_virt ;		/* virtual pointer to the data frag */
+	caddr_t txd_virt ;		/* virtual pointer to the data frag */
 					/* virt pointer to the next TxD */
 	struct s_smt_fp_txd volatile far *txd_next ;
 	struct s_txd_os txd_os ;	/* OS - specific struct */
+	char padding[SK_TXD_PAD];	/* padding */
 } ;
 
+
+
 /*
  *	Receive Descriptor struct
  */
+
+struct s_dummy_rxd {
+        u_int rxd_rbctrl ;              /* receive buffer control */
+        u_int rxd_rfsw ;                /* receive frame status word */
+        u_int rxd_rbadr ;               /* physical rx buffer address */
+        u_int rxd_nrdadr ;              /* physical pointer to the next RxD */
+#ifdef  ENA_64BIT_SUP
+        u_int rxd_rbadr_hi ;            /* physical tx buffer addr(high dword)*/
+#endif
+        caddr_t rxd_virt ;              /* virtual pointer to the data frag */
+                                        /* virt pointer to the next RxD */
+        struct s_smt_fp_rxd volatile far *rxd_next ;
+        struct s_rxd_os rxd_os ;        /* OS - specific struct */
+        /* No padding here! */
+} ;
+
+#define SK_DUMMY_RXD	sizeof(struct s_dummy_rxd)
+#define SK_RXD_PAD	(((SK_DUMMY_RXD+SK_XD_ALIGN-1) \
+				& ~(SK_XD_ALIGN-1))-SK_DUMMY_RXD)
+
 struct s_smt_fp_rxd {
 	u_int rxd_rbctrl ;		/* receive buffer control */
 	u_int rxd_rfsw ;		/* receive frame status word */
 	u_int rxd_rbadr ;		/* physical rx buffer address */
 	u_int rxd_nrdadr ;		/* physical pointer to the next RxD */
 #ifdef	ENA_64BIT_SUP
-	u_int rxd_rbadr_hi ;		/* physical tx buffer addr (high dword)*/
+	u_int rxd_rbadr_hi ;		/* physical tx buffer addr(high dword)*/
 #endif
-	char far *rxd_virt ;		/* virtual pointer to the data frag */
+	caddr_t rxd_virt ;		/* virtual pointer to the data frag */
 					/* virt pointer to the next RxD */
 	struct s_smt_fp_rxd volatile far *rxd_next ;
 	struct s_rxd_os rxd_os ;	/* OS - specific struct */
+	char padding[SK_RXD_PAD] ;
 } ;
 
 /*
diff -urN linux-2.4.19-pre8/drivers/net/skfp/skfddi.c linux-2.4.19-pre9/drivers/net/skfp/skfddi.c
--- linux-2.4.19-pre8/drivers/net/skfp/skfddi.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre9/drivers/net/skfp/skfddi.c	Tue May 28 16:02:29 2002
@@ -56,6 +56,7 @@
  *		12-Nov-99	CG	Source code release
  *		22-Nov-99	CG	Included in kernel source.
  *		07-May-00	DM	64 bit fixes, new dma interface
+ *		06-May-02	ML	Structure fixes
  *
  * Compilation options (-Dxxx):
  *              DRIVERDEBUG     print lots of messages to log file
@@ -68,7 +69,7 @@
 
 /* Version information string - should be updated prior to */
 /* each new release!!! */
-#define VERSION		"2.06"
+#define VERSION		"2.07"
 
 static const char *boot_msg = 
 	"SysKonnect FDDI PCI Adapter driver v" VERSION " for\n"
@@ -188,6 +189,7 @@
 };
 MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
 
 // Define module-wide (static) variables
 
diff -urN linux-2.4.19-pre8/drivers/net/sundance.c linux-2.4.19-pre9/drivers/net/sundance.c
--- linux-2.4.19-pre8/drivers/net/sundance.c	Tue May 28 16:02:19 2002
+++ linux-2.4.19-pre9/drivers/net/sundance.c	Tue May 28 16:02:29 2002
@@ -637,7 +637,7 @@
 
 
 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
-static int eeprom_read(long ioaddr, int location)
+static int __devinit eeprom_read(long ioaddr, int location)
 {
 	int boguscnt = 1000;		/* Typical 190 ticks. */
 	writew(0x0200 | (location & 0xff), ioaddr + EECtrl);
diff -urN linux-2.4.19-pre8/drivers/net/sunlance.c linux-2.4.19-pre9/drivers/net/sunlance.c
--- linux-2.4.19-pre8/drivers/net/sunlance.c	Tue May 28 16:02:21 2002
+++ linux-2.4.19-pre9/drivers/net/sunlance.c	Tue May 28 16:02:29 2002
@@ -258,7 +258,7 @@
 	void (*tx)(struct net_device *);
 
 	char	       	       *name;
-	__u32			init_block_dvma;
+	dma_addr_t		init_block_dvma;
 	struct net_device      *dev;		  /* Backpointer	*/
 	struct lance_private   *next_module;
 	struct sbus_dev	       *sdev;
@@ -320,7 +320,7 @@
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_init_block *ib = lp->init_block;
-	__u32 aib = lp->init_block_dvma;
+	dma_addr_t aib = lp->init_block_dvma;
 	__u32 leptr;
 	int i;
     
diff -urN linux-2.4.19-pre8/drivers/pci/quirks.c linux-2.4.19-pre9/drivers/pci/quirks.c
--- linux-2.4.19-pre8/drivers/pci/quirks.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.19-pre9/drivers/pci/quirks.c	Tue May 28 16:02:29 2002
@@ -486,7 +486,7 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency },
-	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	0x3112	/* Not out yet ? */,	quirk_vialatency },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id },
diff -urN linux-2.4.19-pre8/drivers/pcmcia/Makefile linux-2.4.19-pre9/drivers/pcmcia/Makefile
--- linux-2.4.19-pre8/drivers/pcmcia/Makefile	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/pcmcia/Makefile	Tue May 28 16:02:29 2002
@@ -60,7 +60,7 @@
 endif
 
 obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
-obj-$)CONFIG_PCMCIA_M8XX)	+= m8xx_pcmcia.o
+obj-$(CONFIG_PCMCIA_M8XX)	+= m8xx_pcmcia.o
 
 sa1100_cs-objs-y				:= sa1100_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
diff -urN linux-2.4.19-pre8/drivers/pnp/isapnp.c linux-2.4.19-pre9/drivers/pnp/isapnp.c
--- linux-2.4.19-pre8/drivers/pnp/isapnp.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/pnp/isapnp.c	Tue May 28 16:02:29 2002
@@ -2138,8 +2138,6 @@
 	kfree(card);
 }
 
-#endif /* MODULE */
-
 static void isapnp_free_all_resources(void)
 {
 #ifdef ISAPNP_REGION_OK
@@ -2147,7 +2145,6 @@
 #endif
 	release_region(_PNPWRP, 1);
 	release_region(isapnp_rdp, 1);
-#ifdef MODULE
 #ifdef CONFIG_PROC_FS
 	isapnp_proc_done();
 #endif
@@ -2156,9 +2153,10 @@
 		list_del(list);
 		isapnp_free_card(pci_bus_b(list));
 	}
-#endif
 }
 
+#endif /* MODULE */
+
 static int isapnp_announce_device(struct isapnp_driver *drv, 
 				  struct pci_dev *dev)
 {
diff -urN linux-2.4.19-pre8/drivers/s390/char/tubtty.c linux-2.4.19-pre9/drivers/s390/char/tubtty.c
--- linux-2.4.19-pre8/drivers/s390/char/tubtty.c	Thu Oct 11 09:43:29 2001
+++ linux-2.4.19-pre9/drivers/s390/char/tubtty.c	Tue May 28 16:02:29 2002
@@ -603,12 +603,20 @@
 static void
 tty3270_bh(void *data)
 {
-	long flags;
 	tub_t *tubp;
+	ioinfo_t *ioinfop;
+	long flags;
 	struct tty_struct *tty;
 
-	tubp = data;
-	TUBLOCK(tubp->irq, flags);
+	ioinfop = ioinfo[(tubp = data)->irq];
+	while (TUBTRYLOCK(tubp->irq, flags) == 0) {
+		if (ioinfop->ui.flags.unready == 1)
+			return;
+	}
+	if (ioinfop->ui.flags.unready == 1 ||
+	    ioinfop->ui.flags.ready == 0)
+		goto do_unlock;
+
 	tubp->flags &= ~TUB_BHPENDING;
 	tty = tubp->tty;
 
diff -urN linux-2.4.19-pre8/drivers/sbus/audio/cs4231.c linux-2.4.19-pre9/drivers/sbus/audio/cs4231.c
--- linux-2.4.19-pre8/drivers/sbus/audio/cs4231.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sbus/audio/cs4231.c	Tue May 28 16:02:29 2002
@@ -35,7 +35,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/sbus.h>
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
 #define EB4231_SUPPORT
 #include <asm/ebus.h>
 #include <asm/pbm.h>
diff -urN linux-2.4.19-pre8/drivers/sbus/char/pcikbd.c linux-2.4.19-pre9/drivers/sbus/char/pcikbd.c
--- linux-2.4.19-pre8/drivers/sbus/char/pcikbd.c	Tue Aug 28 07:09:44 2001
+++ linux-2.4.19-pre9/drivers/sbus/char/pcikbd.c	Tue May 28 16:02:29 2002
@@ -29,7 +29,7 @@
 #include <linux/init.h>
 
 #include <asm/ebus.h>
-#if defined(CONFIG_USB) && defined(CONFIG_SPARC64)
+#if (defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)) && defined(CONFIG_SPARC64)
 #include <asm/isa.h>
 #endif
 #include <asm/oplib.h>
@@ -640,7 +640,7 @@
 	restore_flags(flags);
 }
 
-#if defined(CONFIG_USB) && defined(CONFIG_SPARC64)
+#if (defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)) && defined(CONFIG_SPARC64)
 static void isa_kd_nosound(unsigned long __unused)
 {
 	/* disable counter 2 */
@@ -758,7 +758,7 @@
 				}
 			}
 		}
-#ifdef CONFIG_USB
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
 		/* We are being called for the sake of USB keyboard
 		 * state initialization.  So we should check for beeper
 		 * device in this case.
diff -urN linux-2.4.19-pre8/drivers/sbus/char/sunserial.c linux-2.4.19-pre9/drivers/sbus/char/sunserial.c
--- linux-2.4.19-pre8/drivers/sbus/char/sunserial.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre9/drivers/sbus/char/sunserial.c	Tue May 28 16:02:29 2002
@@ -139,7 +139,7 @@
 	nop_getkeycode
 };
 
-#ifdef CONFIG_USB
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
 extern void pci_compute_shiftstate(void);
 extern int pci_setkeycode(unsigned int, unsigned int);
 extern int pci_getkeycode(unsigned int);
@@ -158,7 +158,7 @@
 		err = init->init();
 		init = init->next;
 	}
-#ifdef CONFIG_USB
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
 	if (!serial_console &&
 	    kbd_ops.compute_shiftstate == nop_compute_shiftstate) {
 		printk("kbd_init: Assuming USB keyboard.\n");
diff -urN linux-2.4.19-pre8/drivers/scsi/Config.in linux-2.4.19-pre9/drivers/scsi/Config.in
--- linux-2.4.19-pre8/drivers/scsi/Config.in	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre9/drivers/scsi/Config.in	Tue May 28 16:02:29 2002
@@ -218,6 +218,7 @@
    dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
    if [ "$CONFIG_SCSI_MESH" != "n" ]; then
       int '  maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5
+      int '  initial bus reset delay (ms) (0 = no reset)' CONFIG_SCSI_MESH_RESET_DELAY_MS 4000
    fi
    dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
 fi
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7770.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7770.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7770.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7770.c	Tue May 28 16:02:29 2002
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#21 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $
  */
@@ -57,7 +57,7 @@
 #define ID_AHA_284xB	0x04907756 /* BIOS enabled */
 #define ID_AHA_284x	0x04907757 /* BIOS disabled*/
 
-static void aha2840_load_seeprom(struct ahc_softc *ahc);
+static int aha2840_load_seeprom(struct ahc_softc *ahc);
 static ahc_device_setup_t ahc_aic7770_VL_setup;
 static ahc_device_setup_t ahc_aic7770_EISA_setup;;
 static ahc_device_setup_t ahc_aic7770_setup;
@@ -104,12 +104,16 @@
 int
 aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 {
+	u_long	l;
+	u_long	s;
 	int	error;
+	int	have_seeprom;
 	u_int	hostconf;
 	u_int   irq;
 	u_int	intdef;
 
 	error = entry->setup(ahc);
+	have_seeprom = 0;
 	if (error != 0)
 		return (error);
 
@@ -182,21 +186,22 @@
 					ahc->flags |= AHC_TERM_ENB_B;
 			}
 		}
-		/*
-		 * We have no way to tell, so assume extended
-		 * translation is enabled.
-		 */
-		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
+		if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS))
+			ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
 		break;
 	}
 	case AHC_VL:
 	{
-		aha2840_load_seeprom(ahc);
+		have_seeprom = aha2840_load_seeprom(ahc);
 		break;
 	}
 	default:
 		break;
 	}
+	if (have_seeprom == 0) {
+		free(ahc->seep_config, M_DEVBUF);
+		ahc->seep_config = NULL;
+	}
 
 	/*
 	 * Ensure autoflush is enabled
@@ -215,15 +220,16 @@
 	if (error != 0)
 		return (error);
 
+	error = aic7770_map_int(ahc, irq);
+	if (error != 0)
+		return (error);
+
+	ahc_list_lock(&l);
 	/*
 	 * Link this softc in with all other ahc instances.
 	 */
 	ahc_softc_insert(ahc);
 
-	error = aic7770_map_int(ahc, irq);
-	if (error != 0)
-		return (error);
-
 	/*
 	 * Enable the board's BUS drivers
 	 */
@@ -232,7 +238,11 @@
 	/*
 	 * Allow interrupts.
 	 */
+	ahc_lock(ahc, &s);
 	ahc_intr_enable(ahc, TRUE);
+	ahc_unlock(ahc, &s);
+
+	ahc_list_unlock(&l);
 
 	return (0);
 }
@@ -240,13 +250,13 @@
 /*
  * Read the 284x SEEPROM.
  */
-static void
+static int
 aha2840_load_seeprom(struct ahc_softc *ahc)
 {
-	struct	  seeprom_descriptor sd;
-	struct	  seeprom_config sc;
-	uint8_t   scsi_conf;
-	int	  have_seeprom;
+	struct	seeprom_descriptor sd;
+	struct	seeprom_config *sc;
+	int	have_seeprom;
+	uint8_t scsi_conf;
 
 	sd.sd_ahc = ahc;
 	sd.sd_control_offset = SEECTL_2840;
@@ -259,6 +269,7 @@
 	sd.sd_CK = CK_2840;
 	sd.sd_DO = DO_2840;
 	sd.sd_DI = DI_2840;
+	sc = ahc->seep_config;
 
 	if (bootverbose)
 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
@@ -267,7 +278,7 @@
 
 	if (have_seeprom) {
 
-		if (ahc_verify_cksum(&sc) == 0) {
+		if (ahc_verify_cksum(sc) == 0) {
 			if(bootverbose)
 				printf ("checksum error\n");
 			have_seeprom = 0;
@@ -285,41 +296,44 @@
 		 * Put the data we've collected down into SRAM
 		 * where ahc_init will find it.
 		 */
-		int i;
-		int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
+		int	 i;
+		int	 max_targ;
 		uint16_t discenable;
 
+		max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
 		discenable = 0;
 		for (i = 0; i < max_targ; i++){
-	                uint8_t target_settings;
-			target_settings = (sc.device_flags[i] & CFXFER) << 4;
-			if (sc.device_flags[i] & CFSYNCH)
+			uint8_t target_settings;
+
+			target_settings = (sc->device_flags[i] & CFXFER) << 4;
+			if (sc->device_flags[i] & CFSYNCH)
 				target_settings |= SOFS;
-			if (sc.device_flags[i] & CFWIDEB)
+			if (sc->device_flags[i] & CFWIDEB)
 				target_settings |= WIDEXFER;
-			if (sc.device_flags[i] & CFDISC)
+			if (sc->device_flags[i] & CFDISC)
 				discenable |= (0x01 << i);
 			ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
 		}
 		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
 		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
 
-		ahc->our_id = sc.brtime_id & CFSCSIID;
+		ahc->our_id = sc->brtime_id & CFSCSIID;
 
 		scsi_conf = (ahc->our_id & 0x7);
-		if (sc.adapter_control & CFSPARITY)
+		if (sc->adapter_control & CFSPARITY)
 			scsi_conf |= ENSPCHK;
-		if (sc.adapter_control & CFRESETB)
+		if (sc->adapter_control & CFRESETB)
 			scsi_conf |= RESET_SCSI;
 
-		if (sc.bios_control & CF284XEXTEND)		
+		if (sc->bios_control & CF284XEXTEND)		
 			ahc->flags |= AHC_EXTENDED_TRANS_A;
 		/* Set SCSICONF info */
 		ahc_outb(ahc, SCSICONF, scsi_conf);
 
-		if (sc.adapter_control & CF284XSTERM)
+		if (sc->adapter_control & CF284XSTERM)
 			ahc->flags |= AHC_TERM_ENB_A;
 	}
+	return (have_seeprom);
 }
 
 static int
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7770_osm.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7770_osm.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7770_osm.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7770_osm.c	Tue May 28 16:02:29 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7770_osm.c#1 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#11 $
  */
 
 #include "aic7xxx_osm.h"
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.h	Tue May 28 16:02:29 2002
@@ -37,9 +37,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#45 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.16.2.13 2002/04/29 19:36:29 gibbs Exp $
  */
 
 #ifndef _AIC7XXX_H_
@@ -351,9 +351,11 @@
 					   */
 	AHC_BIOS_ENABLED      = 0x80000,
 	AHC_ALL_INTERRUPTS    = 0x100000,
-	AHC_PAGESCBS	      = 0x400000, /* Enable SCB paging */
-	AHC_EDGE_INTERRUPT    = 0x800000, /* Device uses edge triggered ints */
-	AHC_39BIT_ADDRESSING  = 0x1000000 /* Use 39 bit addressing scheme. */
+	AHC_PAGESCBS	      = 0x400000,  /* Enable SCB paging */
+	AHC_EDGE_INTERRUPT    = 0x800000,  /* Device uses edge triggered ints */
+	AHC_39BIT_ADDRESSING  = 0x1000000, /* Use 39 bit addressing scheme. */
+	AHC_LSCBS_ENABLED     = 0x2000000, /* 64Byte SCBs enabled */
+	AHC_SCB_CONFIG_USED   = 0x4000000  /* No SEEPROM but SCB2 had info. */
 } ahc_flag;
 
 /************************* Hardware  SCB Definition ***************************/
@@ -942,6 +944,7 @@
 	ahc_feature		  features;
 	ahc_bug			  bugs;
 	ahc_flag		  flags;
+	struct seeprom_config	 *seep_config;
 
 	/* Values to store in the SEQCTL register for pause and unpause */
 	uint8_t			  unpause;
@@ -1149,6 +1152,11 @@
 					   char channel, int lun, u_int tag,
 					   role_t role, uint32_t status,
 					   ahc_search_action action);
+int			ahc_search_untagged_queues(struct ahc_softc *ahc,
+						   ahc_io_ctx_t ctx,
+						   int target, char channel,
+						   int lun, uint32_t status,
+						   ahc_search_action action);
 int			ahc_search_disc_list(struct ahc_softc *ahc, int target,
 					     char channel, int lun, u_int tag,
 					     int stop_on_first, int remove,
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.reg
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.reg	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.reg	Tue May 28 16:02:29 2002
@@ -37,9 +37,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.20.2.10 2001/07/28 18:46:40 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.20.2.11 2002/04/29 19:36:30 gibbs Exp $
  */
-VERSION = "$Id$"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#30 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -474,7 +474,7 @@
 	bit	SOFT1		0x80
 	bit	SOFT0		0x40
 	bit	SOFTCMDEN	0x20	
-	bit	HAS_BRDCTL	0x10	/* External Board control */
+	bit	EXT_BRDCTL	0x10	/* External Board control */
 	bit	SEEPROM		0x08	/* External serial eeprom logic */
 	bit	EEPROM		0x04	/* Writable external BIOS ROM */
 	bit	ROM		0x02	/* Logic for accessing external ROM */
@@ -1472,18 +1472,30 @@
 	DATA_COUNT_ODD {
 		size		1
 	}
+}
+
+scratch_ram {
+	address		0x056
+	size		4
+	/*
+	 * These scratch ram locations are initialized by the 274X BIOS.
+	 * We reuse them after capturing the BIOS settings during
+	 * initialization.
+	 */
 
 	/*
 	 * The initiator specified tag for this target mode transaction.
 	 */
-	INITIATOR_TAG {
-		size		1
+	HA_274_BIOSGLOBAL {
+		size	1
+		bit	HA_274_EXTENDED_TRANS	0x01
+		alias	INITIATOR_TAG
 	}
 
 	SEQ_FLAGS2 {
-		size		1
-		bit	SCB_DMA			  0x01
-		bit	TARGET_MSG_PENDING	  0x02
+		size	1
+		bit	SCB_DMA			0x01
+		bit	TARGET_MSG_PENDING	0x02
 	}
 }
 
@@ -1491,9 +1503,13 @@
 	address		0x05a
 	size		6
 	/*
-	 * These are reserved registers in the card's scratch ram.  Some of
-	 * the values are specified in the AHA2742 technical reference manual
-	 * and are initialized by the BIOS at boot time.
+	 * These are reserved registers in the card's scratch ram on the 2742.
+	 * The EISA configuraiton chip is mapped here.  On Rev E. of the
+	 * aic7770, the sequencer can use this area for scratch, but the
+	 * host cannot directly access these registers.  On later chips, this
+	 * area can be read and written by both the host and the sequencer.
+	 * Even on later chips, many of these locations are initialized by
+	 * the BIOS.
 	 */
 	SCSICONF {
 		size		1
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.seq linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx.seq	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx.seq	Tue May 28 16:02:29 2002
@@ -37,10 +37,10 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.94.2.16 2002/04/29 19:36:30 gibbs Exp $
  */
 
-VERSION = "$Id$"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#43 $"
 PATCH_ARG_LIST = "struct ahc_softc *ahc"
 
 #include "aic7xxx.reg"
@@ -438,7 +438,6 @@
 select_out:
 	/* Turn off the selection hardware */
 	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
-	mvi	CLRSINT0, CLRSELDO;
 	mov	SCBPTR, WAITING_SCBH;
 	mov	WAITING_SCBH,SCB_NEXT;
 	mov	SAVED_SCSIID, SCB_SCSIID;
@@ -453,6 +452,7 @@
 		 * sending our identify messages.
 		 */
 		mvi	P_MESGIN|BSYO call change_phase;
+		mvi	CLRSINT0, CLRSELDO;
 
 		/*
 		 * Start out with a simple identify message.
@@ -499,6 +499,7 @@
 		}
 		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
 		mov	SCB_TAG	 call dma_scb;
+		call	set_transfer_settings;
 		jmp	target_synccmd;
 
 target_mesgout:
@@ -642,6 +643,7 @@
 	 */
 	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
 	or	SEQ_FLAGS, IDENTIFY_SEEN;
+	mvi	CLRSINT0, CLRSELDO;
 
 	/*
 	 * Main loop for information transfer phases.  Wait for the
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Tue May 28 16:02:29 2002
@@ -28,9 +28,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#15 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.9 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.8.2.5 2002/04/29 19:36:31 gibbs Exp $
  */
 
 /*
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Tue May 28 16:02:29 2002
@@ -38,9 +38,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#10 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.8 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.7.2.3 2002/04/29 19:36:31 gibbs Exp $
  */
 #ifndef _AIC7XXX_93CX6_H_
 #define _AIC7XXX_93CX6_H_
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_core.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_core.c	Tue May 28 16:02:29 2002
@@ -37,9 +37,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#2 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#69 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.41.2.22 2002/04/29 19:36:26 gibbs Exp $
  */
 
 #ifdef __linux__
@@ -1301,6 +1301,13 @@
 				if (lastphase == ahc_phase_table[i].phase)
 					break;
 			}
+			/*
+			 * Renegotiate with this device at the
+			 * next oportunity just in case this busfree
+			 * is due to a negotiation mismatch with the
+			 * device.
+			 */
+			ahc_force_renegotiation(ahc);
 			printf("Unexpected busfree %s\n"
 			       "SEQADDR == 0x%x\n",
 			       ahc_phase_table[i].phasemsg,
@@ -1423,8 +1430,11 @@
 	ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
 				|CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG|
 				CLRREQINIT);
+	ahc_flush_device_writes(ahc);
 	ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
+ 	ahc_flush_device_writes(ahc);
 	ahc_outb(ahc, CLRINT, CLRSCSIINT);
+	ahc_flush_device_writes(ahc);
 }
 
 /**************************** Debugging Routines ******************************/
@@ -2532,9 +2542,13 @@
 		} else 
 			ahc->msgin_index++;
 
-		/* Ack the byte */
-		ahc_outb(ahc, CLRSINT1, CLRREQINIT);
-		ahc_inb(ahc, SCSIDATL);
+		if (message_done == MSGLOOP_TERMINATED) {
+			end_session = TRUE;
+		} else {
+			/* Ack the byte */
+			ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+			ahc_inb(ahc, SCSIDATL);
+		}
 		break;
 	}
 	case MSG_TYPE_TARGET_MSGIN:
@@ -2745,6 +2759,17 @@
 	 * extended message type.
 	 */
 	switch (ahc->msgin_buf[0]) {
+	case MSG_DISCONNECT:
+	case MSG_SAVEDATAPOINTER:
+	case MSG_CMDCOMPLETE:
+	case MSG_RESTOREPOINTERS:
+	case MSG_IGN_WIDE_RESIDUE:
+		/*
+		 * End our message loop as these are messages
+		 * the sequencer handles on its own.
+		 */
+		done = MSGLOOP_TERMINATED;
+		break;
 	case MSG_MESSAGE_REJECT:
 		response = ahc_handle_msg_reject(ahc, devinfo);
 		/* FALLTHROUGH */
@@ -3534,6 +3559,15 @@
 	ahc = device_get_softc((device_t)platform_arg);
 #endif
 	memset(ahc, 0, sizeof(*ahc));
+	ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+				  M_DEVBUF, M_NOWAIT);
+	if (ahc->seep_config == NULL) {
+#ifndef	__FreeBSD__
+		free(ahc, M_DEVBUF);
+#endif
+		free(name, M_DEVBUF);
+		return (NULL);
+	}
 	LIST_INIT(&ahc->pending_scbs);
 	/* We don't know our unit number until the OSM sets it */
 	ahc->name = name;
@@ -3729,6 +3763,8 @@
 #endif
 	if (ahc->name != NULL)
 		free(ahc->name, M_DEVBUF);
+	if (ahc->seep_config != NULL)
+		free(ahc->seep_config, M_DEVBUF);
 #ifndef __FreeBSD__
 	free(ahc, M_DEVBUF);
 #endif
@@ -3788,11 +3824,15 @@
 	ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
 
 	/*
-	 * Ensure that the reset has finished
+	 * Ensure that the reset has finished.  We delay 1000us
+	 * prior to reading the register to make sure the chip
+	 * has sufficiently completed its reset to handle register
+	 * accesses.
 	 */
 	wait = 1000;
-	while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK))
+	do {
 		ahc_delay(1000);
+	} while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
 
 	if (wait == 0) {
 		printf("%s: WARNING - Failed chip reset!  "
@@ -3880,11 +3920,26 @@
 static void
 ahc_build_free_scb_list(struct ahc_softc *ahc)
 {
+	int scbsize;
 	int i;
 
+	scbsize = 32;
+	if ((ahc->flags & AHC_LSCBS_ENABLED) != 0)
+		scbsize = 64;
+
 	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		int j;
+
 		ahc_outb(ahc, SCBPTR, i);
 
+		/*
+		 * Touch all SCB bytes to avoid parity errors
+		 * should one of our debugging routines read
+		 * an otherwise uninitiatlized byte.
+		 */
+		for (j = 0; j < scbsize; j++)
+			ahc_outb(ahc, SCB_BASE+j, 0xFF);
+
 		/* Clear the control byte. */
 		ahc_outb(ahc, SCB_CONTROL, 0);
 
@@ -3894,8 +3949,10 @@
 		else 
 			ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
 
-		/* Make the tag number invalid */
+		/* Make the tag number, SCSIID, and lun invalid */
 		ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+		ahc_outb(ahc, SCB_SCSIID, 0xFF);
+		ahc_outb(ahc, SCB_LUN, 0xFF);
 	}
 
 	/* Make sure that the last SCB terminates the free list */
@@ -5108,8 +5165,6 @@
 	uint8_t prev;
 	uint8_t curscbptr;
 	int	found;
-	int	maxtarget;
-	int	i;
 	int	have_qregs;
 
 	qintail = ahc->qinfifonext;
@@ -5159,8 +5214,7 @@
 
 				ostat = ahc_get_transaction_status(scb);
 				if (ostat == CAM_REQ_INPROG)
-					ahc_set_transaction_status(scb,
-								   status);
+					ahc_set_transaction_status(scb, status);
 				cstat = ahc_get_transaction_status(scb);
 				if (cstat != CAM_REQ_CMP)
 					ahc_freeze_scb(scb);
@@ -5298,9 +5352,33 @@
 	}
 	ahc_outb(ahc, SCBPTR, curscbptr);
 
-	/*
-	 * And lastly, the untagged holding queues.
-	 */
+	found += ahc_search_untagged_queues(ahc, /*ahc_io_ctx_t*/NULL, target,
+					    channel, lun, status, action);
+
+	if (action == SEARCH_COMPLETE)
+		ahc_release_untagged_queues(ahc);
+	return (found);
+}
+
+int
+ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx,
+			   int target, char channel, int lun, uint32_t status,
+			   ahc_search_action action)
+{
+	struct	scb *scb;
+	int	maxtarget;
+	int	found;
+	int	i;
+
+	if (action == SEARCH_COMPLETE) {
+		/*
+		 * Don't attempt to run any queued untagged transactions
+		 * until we are done with the abort process.
+		 */
+		ahc_freeze_untagged_queues(ahc);
+	}
+
+	found = 0;
 	i = 0;
 	if ((ahc->flags & AHC_SCB_BTT) == 0) {
 
@@ -5339,37 +5417,37 @@
 			if ((scb->flags & SCB_ACTIVE) != 0)
 				continue;
 
-			if (ahc_match_scb(ahc, scb, target, channel,
-					  lun, SCB_LIST_NULL, role)) {
-				/*
-				 * We found an scb that needs to be acted on.
-				 */
-				found++;
-				switch (action) {
-				case SEARCH_COMPLETE:
-				{
-					cam_status ostat;
-					cam_status cstat;
-
-					ostat = ahc_get_transaction_status(scb);
-					if (ostat == CAM_REQ_INPROG)
-						ahc_set_transaction_status(scb,
-								   status);
-					cstat = ahc_get_transaction_status(scb);
-					if (cstat != CAM_REQ_CMP)
-						ahc_freeze_scb(scb);
-					if ((scb->flags & SCB_ACTIVE) == 0)
-						printf("Inactive SCB in untaggedQ\n");
-					ahc_done(ahc, scb);
-					break;
-				}
-				case SEARCH_REMOVE:
-					TAILQ_REMOVE(untagged_q, scb,
-						     links.tqe);
-					break;
-				case SEARCH_COUNT:
-					break;
-				}
+			if (ahc_match_scb(ahc, scb, target, channel, lun,
+					  SCB_LIST_NULL, ROLE_INITIATOR) == 0
+			 || (ctx != NULL && ctx != scb->io_ctx))
+				continue;
+
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb, status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in untaggedQ\n");
+				ahc_done(ahc, scb);
+				break;
+			}
+			case SEARCH_REMOVE:
+				TAILQ_REMOVE(untagged_q, scb, links.tqe);
+				break;
+			case SEARCH_COUNT:
+				break;
 			}
 		}
 	}
@@ -5724,6 +5802,16 @@
 	 */
 	ahc_run_qoutfifo(ahc);
 #if AHC_TARGET_MODE
+	/*
+	 * XXX - In Twin mode, the tqinfifo may have commands
+	 *	 for an unaffected channel in it.  However, if
+	 *	 we have run out of ATIO resources to drain that
+	 *	 queue, we may not get them all out here.  Further,
+	 *	 the blocked transactions for the reset channel
+	 *	 should just be killed off, irrespecitve of whether
+	 *	 we are blocked on ATIO resources.  Write a routine
+	 *	 to compact the tqinfifo appropriately.
+	 */
 	if ((ahc->flags & AHC_TARGETROLE) != 0) {
 		ahc_run_tqinfifo(ahc, /*paused*/TRUE);
 	}
@@ -5745,10 +5833,6 @@
 		 */
 		ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
 		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
-		ahc_outb(ahc, SIMODE1, simode1);
-		if (initiate_reset)
-			ahc_reset_current_bus(ahc);
-		ahc_clear_intstat(ahc);
 #if AHC_TARGET_MODE
 		/*
 		 * Bus resets clear ENSELI, so we cannot
@@ -5756,18 +5840,18 @@
 		 * if we are in target mode.
 		 */
 		if ((ahc->flags & AHC_TARGETROLE) != 0)
-			ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+			simode1 |= ENSCSIRST;
 #endif
+		ahc_outb(ahc, SIMODE1, simode1);
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
 		ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
 		ahc_outb(ahc, SBLKCTL, sblkctl);
 		restart_needed = FALSE;
 	} else {
 		/* Case 2: A command from this bus is active or we're idle */
 		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
-		ahc_outb(ahc, SIMODE1, simode1);
-		if (initiate_reset)
-			ahc_reset_current_bus(ahc);
-		ahc_clear_intstat(ahc);
 #if AHC_TARGET_MODE
 		/*
 		 * Bus resets clear ENSELI, so we cannot
@@ -5775,8 +5859,12 @@
 		 * if we are in target mode.
 		 */
 		if ((ahc->flags & AHC_TARGETROLE) != 0)
-			ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+			simode1 |= ENSCSIRST;
 #endif
+		ahc_outb(ahc, SIMODE1, simode1);
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
 		ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
 		restart_needed = TRUE;
 	}
@@ -6956,6 +7044,8 @@
 		/*
 		 * Wait for more ATIOs from the peripheral driver for this lun.
 		 */
+		if (bootverbose)
+			printf("%s: ATIOs exhausted\n", ahc_name(ahc));
 		return (1);
 	} else
 		ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_host.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_host.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_host.h	Tue May 28 16:02:29 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#3 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_host.h#9 $
  */
 
 #ifndef _AIC7XXX_HOST_H_
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_inline.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_inline.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_inline.h	Tue May 28 16:02:29 2002
@@ -37,9 +37,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#35 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.2.2.11 2002/04/29 19:36:31 gibbs Exp $
  */
 
 #ifndef _AIC7XXX_INLINE_H_
@@ -358,8 +358,8 @@
 	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
 	if ((scb->flags & SCB_CDB32_PTR) != 0) {
 		q_hscb->shared_data.cdb_ptr =
-		    ahc_hscb_busaddr(ahc, q_hscb->tag)
-		  + offsetof(struct hardware_scb, cdb32);	
+		    ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
+			      + offsetof(struct hardware_scb, cdb32));
 	}
 	q_hscb->tag = saved_tag;
 	q_hscb->next = scb->hscb->tag;
@@ -472,7 +472,8 @@
 	if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
 		retval |= AHC_RUN_QOUTFIFO;
 #ifdef AHC_TARGET_MODE
-	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+	if ((ahc->flags & AHC_TARGETROLE) != 0
+	 && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
 		ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
 				ahc->shared_data_dmamap,
 				ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Tue Nov 13 09:19:41 2001
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,407 +0,0 @@
-/*
- * Linux driver attachment glue for PCI based controllers.
- *
- * Copyright (c) 2000-2001 Adaptec Inc.
- * All rights reserved.
- *
- * 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.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#27 $
- */
-
-#include "aic7xxx_osm.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-struct pci_device_id
-{
-};
-#endif
-
-static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
-					const struct pci_device_id *ent);
-static int	ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
-						u_long *base);
-#ifdef MMAPIO
-static int	ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
-						 u_long *bus_addr,
-						 uint8_t **maddr);
-#endif /* MMAPIO */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
-
-/* We do our own ID filtering.  So, grab all SCSI storage class devices. */
-static struct pci_device_id ahc_linux_pci_id_table[] = {
-	{
-		0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-		PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
-	},
-	{
-		0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-		PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
-	},
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
-
-struct pci_driver aic7xxx_pci_driver = {
-	name:		"aic7xxx",
-	probe:		ahc_linux_pci_dev_probe,
-	remove:		ahc_linux_pci_dev_remove,
-	id_table:	ahc_linux_pci_id_table
-};
-
-static void
-ahc_linux_pci_dev_remove(struct pci_dev *pdev)
-{
-	struct ahc_softc *ahc;
-	struct ahc_softc *list_ahc;
-
-	/*
-	 * We should be able to just perform
-	 * the free directly, but check our
-	 * list for extra sanity.
-	 */
-	ahc = pci_get_drvdata(pdev);
-	TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
-		if (list_ahc == ahc) {
-			ahc_free(ahc);
-			break;
-		}
-	}
-}
-#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
-
-static int
-ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	char		 buf[80];
-	struct		 ahc_softc *ahc;
-	ahc_dev_softc_t	 pci;
-	struct		 ahc_pci_identity *entry;
-	char		*name;
-	int		 error;
-
-	/*
-	 * Some BIOSen report the same device multiple times.
-	 */
-	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
-		struct pci_dev *probed_pdev;
-
-		probed_pdev = ahc->dev_softc;
-		if (probed_pdev->bus->number == pdev->bus->number
-		 && probed_pdev->devfn == pdev->devfn)
-			break;
-	}
-	if (ahc != NULL) {
-		/* Skip duplicate. */
-		return (-ENODEV);
-	}
-
-	pci = pdev;
-	entry = ahc_find_pci_device(pci);
-	if (entry == NULL)
-		return (-ENODEV);
-
-	/*
-	 * Allocate a softc for this card and
-	 * set it up for attachment by our
-	 * common detect routine.
-	 */
-	sprintf(buf, "ahc_pci:%d:%d:%d",
-		ahc_get_pci_bus(pci),
-		ahc_get_pci_slot(pci),
-		ahc_get_pci_function(pci));
-	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
-	if (name == NULL)
-		return (-ENOMEM);
-	strcpy(name, buf);
-	ahc = ahc_alloc(NULL, name);
-	if (ahc == NULL)
-		return (-ENOMEM);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-	if (pci_enable_device(pdev)) {
-		ahc_free(ahc);
-		return (-ENODEV);
-	}
-	pci_set_master(pdev);
-
-	if (sizeof(bus_addr_t) > 4
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
-	 && ahc_linux_get_memsize() > 0x80000000
-	 && pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
-#else
-	 && ahc_linux_get_memsize() > 0x80000000) {
-
-		ahc->dev_softc->dma_mask = 
-		    (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
-#endif
-		ahc->flags |= AHC_39BIT_ADDRESSING;
-		ahc->platform_data->hw_dma_mask =
-		    (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
-	}
-#endif
-	ahc->dev_softc = pci;
-	ahc->platform_data->irq = pdev->irq;
-	error = ahc_pci_config(ahc, entry);
-	if (error != 0) {
-		ahc_free(ahc);
-		return (-error);
-	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-	pci_set_drvdata(pdev, ahc);
-	if (aic7xxx_detect_complete)
-		ahc_linux_register_host(ahc, aic7xxx_driver_template);
-#endif
-	return (0);
-}
-
-int
-ahc_linux_pci_probe(Scsi_Host_Template *template)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-	return (pci_module_init(&aic7xxx_pci_driver));
-#else
-	struct pci_dev *pdev;
-	u_int class;
-	int found;
-
-	/* If we don't have a PCI bus, we can't find any adapters. */
-	if (pci_present() == 0)
-		return (0);
-
-	found = 0;
-	pdev = NULL;
-	class = PCI_CLASS_STORAGE_SCSI << 8;
-	while ((pdev = pci_find_class(class, pdev)) != NULL) {
-		ahc_dev_softc_t pci;
-		int error;
-
-		pci = pdev;
-		error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
-		if (error == 0)
-			found++;
-	}
-	return (found);
-#endif
-}
-
-static int
-ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-	*base = pci_resource_start(ahc->dev_softc, 0);
-#else
-	*base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
-	*base &= PCI_BASE_ADDRESS_IO_MASK;
-#endif
-	if (base == 0)
-		return (ENOMEM);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-	if (check_region(*base, 256) != 0)
-		return (ENOMEM);
-	else
-		request_region(*base, 256, "aic7xxx");
-#else
-	if (request_region(*base, 256, "aic7xxx") == 0)
-		return (ENOMEM);
-#endif
-	return (0);
-}
-
-#ifdef MMAPIO
-static int
-ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
-				 u_long *bus_addr,
-				 uint8_t **maddr)
-{
-	u_long	start;
-	u_long	base_page;
-	u_long	base_offset;
-	int	error;
-
-	error = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-	start = pci_resource_start(ahc->dev_softc, 1);
-	base_page = start & PAGE_MASK;
-	base_offset = start - base_page;
-#else
-	start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4);
-	base_offset = start & PCI_BASE_ADDRESS_MEM_MASK;
-	base_page = base_offset & PAGE_MASK;
-	base_offset -= base_page;
-#endif
-	if (start != 0) {
-		*bus_addr = start;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
-			error = ENOMEM;
-#endif
-		if (error == 0) {
-			*maddr = ioremap_nocache(base_page, base_offset + 256);
-			if (*maddr == NULL)
-				error = ENOMEM;
-			else
-				*maddr += base_offset;
-		}
-	} else
-		error = ENOMEM;
-	return (error);
-}
-#endif /* MMAPIO */
-
-int
-ahc_pci_map_registers(struct ahc_softc *ahc)
-{
-	uint32_t command;
-	u_long	 base;
-	uint8_t	*maddr;
-	int	 error;
-	int	 io_error;
-
-	/*
-	 * We always reserve both our register spaces to avoid
-	 * other devices claiming them.
-	 */
-	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
-	command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
-	base = 0;
-	maddr = NULL;
-#ifdef MMAPIO
-	error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr);
-	if (error == 0) {
-		ahc->platform_data->mem_busaddr = base;
-		ahc->tag = BUS_SPACE_MEMIO;
-		ahc->bsh.maddr = maddr;
-		ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
-				     command | PCIM_CMD_MEMEN, 4);
-
-		/*
-		 * Do a quick test to see if memory mapped
-		 * I/O is functioning correctly.
-		 */
-		if (ahc_inb(ahc, HCNTRL) == 0xFF) {
-
-			printf("aic7xxx: PCI Device %d:%d:%d "
-			       "failed memory mapped test\n",
-			       ahc_get_pci_bus(ahc->dev_softc),
-			       ahc_get_pci_slot(ahc->dev_softc),
-			       ahc_get_pci_function(ahc->dev_softc));
-			maddr = NULL;
-		} else
-			command |= PCIM_CMD_MEMEN;
-	} else {
-		printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
-		       "unavailable. Cannot map device.\n",
-		       ahc_get_pci_bus(ahc->dev_softc),
-		       ahc_get_pci_slot(ahc->dev_softc),
-		       ahc_get_pci_function(ahc->dev_softc),
-		       base);
-	}
-#endif
-
-	/*
-	 * We always prefer memory mapped access.  Only
-	 * complain about our ioport conflicting with
-	 * another device if we are going to use it.
-	 */
-	io_error = ahc_linux_pci_reserve_io_region(ahc, &base);
-	if (maddr == NULL) {
-		error = io_error;
-		if (error != 0) {
-			printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
-			       "unavailable. Cannot map device.\n",
-			       ahc_get_pci_bus(ahc->dev_softc),
-			       ahc_get_pci_slot(ahc->dev_softc),
-			       ahc_get_pci_function(ahc->dev_softc),
-			       base);
-			base = 0;
-		} else {
-			ahc->tag = BUS_SPACE_PIO;
-			ahc->bsh.ioport = base;
-			command |= PCIM_CMD_PORTEN;
-		}
-	}
-	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
-	return (error);
-}
-
-int
-ahc_pci_map_int(struct ahc_softc *ahc)
-{
-	int error;
-
-	ahc->platform_data->irq = ahc->dev_softc->irq;
-	error = request_irq(ahc->platform_data->irq, ahc_linux_isr,
-			    SA_SHIRQ, "aic7xxx", ahc);
-	
-	return (-error);
-}
-
-void
-ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-	pci_set_power_state(ahc->dev_softc, new_state);
-#else
-	uint32_t cap;
-	u_int cap_offset;
-
-	/*
-	 * Traverse the capability list looking for
-	 * the power management capability.
-	 */
-	cap = 0;
-	cap_offset = ahc_pci_read_config(ahc->dev_softc,
-					 PCIR_CAP_PTR, /*bytes*/1);
-	while (cap_offset != 0) {
-
-		cap = ahc_pci_read_config(ahc->dev_softc,
-					  cap_offset, /*bytes*/4);
-		if ((cap & 0xFF) == 1
-		 && ((cap >> 16) & 0x3) > 0) {
-			uint32_t pm_control;
-
-			pm_control = ahc_pci_read_config(ahc->dev_softc,
-							 cap_offset + 4,
-							 /*bytes*/4);
-			pm_control &= ~0x3;
-			pm_control |= new_state;
-			ahc_pci_write_config(ahc->dev_softc,
-					     cap_offset + 4,
-					     pm_control, /*bytes*/2);
-			break;
-		}
-		cap_offset = (cap >> 8) & 0xFF;
-	}
-#endif 
-}
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm.c	Tue May 28 16:02:29 2002
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#4 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#103 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -137,6 +137,13 @@
 #include <linux/mm.h>		/* For fetching system memory size */
 #include <linux/blk.h>		/* For block_size() */
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+/*
+ * Lock protecting manipulation of the ahc softc list.
+ */
+spinlock_t ahc_list_spinlock;
+#endif
+
 /*
  * To generate the correct addresses for the controller to issue
  * on the bus.  Originally added for DEC Alpha support.
@@ -440,6 +447,7 @@
 static void ahc_linux_sem_timeout(u_long arg);
 static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc);
 static void ahc_linux_release_sim_queue(u_long arg);
+static void ahc_linux_dev_timed_unfreeze(u_long arg);
 static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
 static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
@@ -1085,7 +1093,6 @@
 			break;
 		}
 	}
-	register_reboot_notifier(&ahc_linux_notifier);
 	return 1;
 }
 
@@ -1105,6 +1112,12 @@
 	int     found;
 
 	/*
+	 * It is a bug that the upper layer takes
+	 * this lock just prior to calling us.
+	 */
+	spin_unlock_irq(&io_request_lock);
+
+	/*
 	 * Sanity checking of Linux SCSI data structures so
 	 * that some of our hacks^H^H^H^H^Hassumptions aren't
 	 * violated.
@@ -1144,6 +1157,12 @@
 	template->max_sectors = 8192;
 #endif
 
+	/*
+	 * Initialize our softc list lock prior to
+	 * probing for any adapters.
+	 */
+	ahc_list_lockinit();
+
 #ifdef CONFIG_PCI
 	ahc_linux_pci_probe(template);
 #endif
@@ -1155,6 +1174,7 @@
 	 * Register with the SCSI layer all
 	 * controllers we've found.
 	 */
+	spin_lock_irq(&io_request_lock);
 	found = 0;
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
 
@@ -1342,6 +1362,8 @@
 #endif
 	ahc->seltime = (aic7xxx_seltime & 0x3) << 4;
 	ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4;
+	if (TAILQ_EMPTY(&ahc_tailq))
+		register_reboot_notifier(&ahc_linux_notifier);
 	return (0);
 }
 
@@ -1894,6 +1916,7 @@
 	memset(targ, 0, sizeof(*targ));
 	targ->channel = channel;
 	targ->target = target;
+	targ->ahc = ahc;
 	target_offset = target;
 	if (channel != 0)
 		target_offset += 8;
@@ -1923,6 +1946,7 @@
 	if (dev == NULL)
 		return (NULL);
 	memset(dev, 0, sizeof(*dev));
+	init_timer(&dev->timer);
 	TAILQ_INIT(&dev->busyq);
 	dev->flags = AHC_DEV_UNCONFIGURED;
 	dev->lun = lun;
@@ -1951,6 +1975,7 @@
 {
 	struct ahc_linux_target *targ;
 
+	del_timer(&dev->timer);
 	targ = dev->target;
 	targ->devices[dev->lun] = NULL;
 	free(dev, M_DEVBUF);
@@ -2252,14 +2277,27 @@
 		/* FALLTHROUGH */
 	}
 	case SCSI_STATUS_BUSY:
+	{
 		/*
-		 * XXX Set a timer and handle ourselves????
-		 * For now we pray that the mid-layer does something
-		 * sane for devices that are busy.
+		 * Set a short timer to defer sending commands for
+		 * a bit since Linux will not delay in this case.
 		 */
-		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
+		if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) {
+			printf("%s:%c:%d: Device Timer still active during "
+			       "busy processing\n", ahc_name(ahc),
+				dev->target->channel, dev->target->target);
+			break;
+		}
+		dev->flags |= AHC_DEV_TIMER_ACTIVE;
+		dev->qfrozen++;
+		init_timer(&dev->timer);
+		dev->timer.data = (u_long)dev;
+		dev->timer.expires = jiffies + (HZ/2);
+		dev->timer.function = ahc_linux_dev_timed_unfreeze;
+		add_timer(&dev->timer);
 		break;
 	}
+	}
 }
 
 static void
@@ -2480,6 +2518,25 @@
 	}
 }
 
+static void
+ahc_linux_dev_timed_unfreeze(u_long arg)
+{
+	struct ahc_linux_device *dev;
+	struct ahc_softc *ahc;
+	u_long s;
+
+	dev = (struct ahc_linux_device *)arg;
+	ahc = dev->target->ahc;
+	ahc_lock(ahc, &s);
+	dev->flags &= ~AHC_DEV_TIMER_ACTIVE;
+	if (dev->qfrozen > 0)
+		dev->qfrozen--;
+	if (dev->qfrozen == 0
+	 && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0)
+		ahc_linux_run_device_queue(ahc, dev);
+	ahc_unlock(ahc, &s);
+}
+
 static int
 ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 {
@@ -2552,6 +2609,16 @@
 		}
 	}
 
+	if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
+	 && ahc_search_untagged_queues(ahc, cmd, cmd->target,
+				       cmd->channel + 'A', cmd->lun,
+				       CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {
+		printf("%s:%d:%d:%d: Command found on untagged queue\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		retval = SUCCESS;
+		goto done;
+	}
+
 	/*
 	 * See if we can find a matching cmd in the pending list.
 	 */
@@ -2565,7 +2632,7 @@
 		/* Any SCB for this device will do for a target reset */
 		LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
 		  	if (ahc_match_scb(ahc, pending_scb, cmd->target,
-					  cmd->channel, CAM_LUN_WILDCARD,
+					  cmd->channel + 'A', CAM_LUN_WILDCARD,
 					  SCB_LIST_NULL, ROLE_INITIATOR) == 0)
 				break;
 		}
@@ -2587,18 +2654,23 @@
 
 	/*
 	 * Ensure that the card doesn't do anything
-	 * behind our back.  Also make sure that we
+	 * behind our back and that no selections have occurred
+	 * that have not been serviced.  Also make sure that we
 	 * didn't "just" miss an interrupt that would
 	 * affect this cmd.
 	 */
 	ahc->flags |= AHC_ALL_INTERRUPTS;
 	do {
+		if (paused)
+			ahc_unpause(ahc);
 		ahc_intr(ahc);
 		ahc_pause(ahc);
+		paused = TRUE;
+		ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
 		ahc_clear_critical_section(ahc);
-	} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
+	} while ((ahc_inb(ahc, INTSTAT) & INT_PEND) != 0
+	      || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)));
 	ahc->flags &= ~AHC_ALL_INTERRUPTS;
-	paused = TRUE;
 
 	ahc_dump_card_state(ahc);
 
@@ -2627,6 +2699,18 @@
 		disconnected = FALSE;
 	}
 
+	if (disconnected && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) != 0) {
+		struct scb *bus_scb;
+
+		bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG));
+		if (bus_scb == pending_scb)
+			disconnected = FALSE;
+		else if (flag != SCB_ABORT
+		      && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid
+		      && ahc_inb(ahc, SAVED_LUN) == pending_scb->hscb->lun)
+			disconnected = FALSE;
+	}
+
 	/*
 	 * At this point, pending_scb is the scb associated with the
 	 * passed in command.  That command is currently active on the
@@ -2884,7 +2968,9 @@
 ahc_linux_release(struct Scsi_Host * host)
 {
 	struct ahc_softc *ahc;
+	u_long l;
 
+	ahc_list_lock(&l);
 	if (host != NULL) {
 
 		/*
@@ -2893,9 +2979,16 @@
 		 * list for extra sanity.
 		 */
 		ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
-		if (ahc != NULL)
+		if (ahc != NULL) {
+			u_long s;
+
+			ahc_lock(ahc, &s);
+			ahc_intr_enable(ahc, FALSE);
+			ahc_unlock(ahc, &s);
 			ahc_free(ahc);
+		}
 	}
+	ahc_list_unlock(&l);
 	return (0);
 }
 
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm.h	Tue May 28 16:02:29 2002
@@ -18,7 +18,7 @@
  * along with this program; see the file COPYING.  If not, write to
  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  * 
- * $Id$
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#82 $
  *
  * Copyright (c) 2000-2001 Adaptec Inc.
  * All rights reserved.
@@ -55,7 +55,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#82 $
  *
  */
 #ifndef _AIC7XXX_LINUX_H_
@@ -409,7 +409,7 @@
 #include <linux/smp.h>
 #endif
 
-#define AIC7XXX_DRIVER_VERSION  "6.2.6"
+#define AIC7XXX_DRIVER_VERSION  "6.2.8"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -468,7 +468,7 @@
 	 * The number of transactions currently
 	 * queued to the device.
 	 */
-	int		active;
+	int			active;
 
 	/*
 	 * The currently allowed number of 
@@ -478,18 +478,18 @@
 	 * mode where the device may have more
 	 * than one outstanding active transaction.
 	 */
-	int		openings;
+	int			openings;
 
 	/*
 	 * A positive count indicates that this
 	 * device's queue is halted.
 	 */
-	u_int		qfrozen;
+	u_int			qfrozen;
 	
 	/*
 	 * Cumulative command counter.
 	 */
-	u_long		commands_issued;
+	u_long			commands_issued;
 
 	/*
 	 * The number of tagged transactions when
@@ -497,21 +497,26 @@
 	 * that have been successfully received by
 	 * this device since the last QUEUE FULL.
 	 */
-	u_int		tag_success_count;
+	u_int			tag_success_count;
 #define AHC_TAG_SUCCESS_INTERVAL 50
 
-	ahc_dev_flags	flags;
+	ahc_dev_flags		flags;
+
+	/*
+	 * Per device timer.
+	 */
+	struct timer_list	timer;
 
 	/*
 	 * The high limit for the tags variable.
 	 */
-	u_int		maxtags;
+	u_int			maxtags;
 
 	/*
 	 * The computed number of tags outstanding
 	 * at the time of the last QUEUE FULL event.
 	 */
-	u_int		tags_on_last_queuefull;
+	u_int			tags_on_last_queuefull;
 
 	/*
 	 * How many times we have seen a queue full
@@ -519,7 +524,7 @@
 	 * to stop our adaptive queue depth algorithm
 	 * on devices with a fixed number of tags.
 	 */
-	u_int		last_queuefull_same_count;
+	u_int			last_queuefull_same_count;
 #define AHC_LOCK_TAGS_COUNT 50
 
 	/*
@@ -531,11 +536,11 @@
 	 * if the AHC_DEV_PERIODIC_OTAG flag is set
 	 * on this device.
 	 */
-	u_int		commands_since_idle_or_otag;
+	u_int			commands_since_idle_or_otag;
 #define AHC_OTAG_THRESH	500
 
-	int		lun;
-	struct		ahc_linux_target *target;
+	int			lun;
+	struct			ahc_linux_target *target;
 };
 
 struct ahc_linux_target {
@@ -544,6 +549,7 @@
 	int	target;
 	int	refcount;
 	struct	ahc_transinfo last_tinfo;
+	struct	ahc_softc *ahc;
 };
 
 /********************* Definitions Required by the Core ***********************/
@@ -723,6 +729,12 @@
 static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
 static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
 
+/* Lock held during ahc_list manipulation and ahc softc frees */
+extern spinlock_t ahc_list_spinlock;
+static __inline void ahc_list_lockinit(void);
+static __inline void ahc_list_lock(unsigned long *flags);
+static __inline void ahc_list_unlock(unsigned long *flags);
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
 static __inline void
 ahc_lockinit(struct ahc_softc *ahc)
@@ -762,6 +774,25 @@
 	spin_unlock_irqrestore(&io_request_lock, *flags);
 }
 
+static __inline void
+ahc_list_lockinit()
+{
+	spin_lock_init(&ahc_list_spinlock);
+}
+
+static __inline void
+ahc_list_lock(unsigned long *flags)
+{
+	*flags = 0;
+	spin_lock_irqsave(&ahc_list_spinlock, *flags);
+}
+
+static __inline void
+ahc_list_unlock(unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahc_list_spinlock, *flags);
+}
+
 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
 
 ahc_lockinit(struct ahc_softc *ahc)
@@ -782,6 +813,7 @@
 	restore_flags(*flags);
 }
 
+static __inline void
 ahc_done_lockinit(struct ahc_softc *ahc)
 {
 }
@@ -800,6 +832,25 @@
 ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
 {
 }
+
+static __inline void
+ahc_list_lockinit()
+{
+}
+
+static __inline void
+ahc_list_lock(unsigned long *flags)
+{
+	*flags = 0;
+	save_flags(*flags);
+	cli();
+}
+
+static __inline void
+ahc_list_unlock(unsigned long *flags)
+{
+	restore_flags(*flags);
+}
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
 
 /******************************* PCI Definitions ******************************/
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Tue May 28 16:02:29 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#2 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#32 $
  */
 
 #include "aic7xxx_osm.h"
@@ -85,15 +85,24 @@
 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
 {
 	struct ahc_softc *ahc;
+	u_long l;
 
 	/*
 	 * We should be able to just perform
 	 * the free directly, but check our
 	 * list for extra sanity.
 	 */
+	ahc_list_lock(&l);
 	ahc = ahc_find_softc((struct ahc_softc *)pdev->driver_data);
-	if (ahc != NULL)
+	if (ahc != NULL) {
+		u_long s;
+
+		ahc_lock(ahc, &s);
+		ahc_intr_enable(ahc, FALSE);
+		ahc_unlock(ahc, &s);
 		ahc_free(ahc);
+	}
+	ahc_list_unlock(&l);
 }
 #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
 
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_pci.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_pci.c	Tue May 28 16:02:29 2002
@@ -39,9 +39,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#46 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.2.2.14 2002/04/29 19:36:31 gibbs Exp $
  */
 
 #ifdef __linux__
@@ -667,6 +667,8 @@
 				  int pcheck, int fast, int large);
 static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
 static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
+static void ahc_parse_pci_eeprom(struct ahc_softc *ahc,
+				 struct seeprom_config *sc);
 static void configure_termination(struct ahc_softc *ahc,
 				  struct seeprom_descriptor *sd,
 				  u_int adapter_control,
@@ -770,6 +772,8 @@
 ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
 {
 	struct scb_data *shared_scb_data;
+	u_long		 l;
+	u_long		 s;
 	u_int		 command;
 	u_int		 our_id = 0;
 	u_int		 sxfrctl1;
@@ -975,19 +979,23 @@
 		return (error);
 
 	/*
-	 * Link this softc in with all other ahc instances.
-	 */
-	ahc_softc_insert(ahc);
-
-	/*
 	 * Allow interrupts now that we are completely setup.
 	 */
 	error = ahc_pci_map_int(ahc);
 	if (error != 0)
 		return (error);
 
+	ahc_list_lock(&l);
+	/*
+	 * Link this softc in with all other ahc instances.
+	 */
+	ahc_softc_insert(ahc);
+
+	ahc_lock(ahc, &s);
 	ahc_intr_enable(ahc, TRUE);
+	ahc_unlock(ahc, &s);
 
+	ahc_list_unlock(&l);
 	return (0);
 }
 
@@ -1045,6 +1053,9 @@
 		ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));
 	}
 
+	ahc->flags &= ~AHC_LSCBS_ENABLED;
+	if (large)
+		ahc->flags |= AHC_LSCBS_ENABLED;
 	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
 	if ((ahc->features & AHC_ULTRA2) != 0) {
 		u_int dscommand0;
@@ -1191,9 +1202,7 @@
 check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
 {
 	struct	seeprom_descriptor sd;
-	struct	seeprom_config sc;
-	u_int	scsi_conf;
-	u_int	adapter_control;
+	struct	seeprom_config *sc;
 	int	have_seeprom;
 	int	have_autoterm;
 
@@ -1201,6 +1210,7 @@
 	sd.sd_control_offset = SEECTL;		
 	sd.sd_status_offset = SEECTL;		
 	sd.sd_dataout_offset = SEECTL;		
+	sc = ahc->seep_config;
 
 	/*
 	 * For some multi-channel devices, the c46 is simply too
@@ -1231,12 +1241,12 @@
 
 			start_addr = 32 * (ahc->channel - 'A');
 
-			have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc,
+			have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
 							start_addr,
-							sizeof(sc)/2);
+							sizeof(*sc)/2);
 
 			if (have_seeprom)
-				have_seeprom = ahc_verify_cksum(&sc);
+				have_seeprom = ahc_verify_cksum(sc);
 
 			if (have_seeprom != 0 || sd.sd_chip == C56_66) {
 				if (bootverbose) {
@@ -1268,7 +1278,7 @@
 			uint16_t *sc_data;
 			int	  i;
 
-			sc_data = (uint16_t *)&sc;
+			sc_data = (uint16_t *)sc;
 			for (i = 0; i < 32; i++) {
 				uint16_t val;
 				int	 j;
@@ -1277,7 +1287,9 @@
 				val = ahc_inb(ahc, SRAM_BASE + j)
 				    | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
 			}
-			have_seeprom = ahc_verify_cksum(&sc);
+			have_seeprom = ahc_verify_cksum(sc);
+			if (have_seeprom)
+				ahc->flags |= AHC_SCB_CONFIG_USED;
 		}
 		/*
 		 * Clear any SCB parity errors in case this data and
@@ -1291,121 +1303,11 @@
 		if (bootverbose)
 			printf("%s: No SEEPROM available.\n", ahc_name(ahc));
 		ahc->flags |= AHC_USEDEFAULTS;
+		free(ahc->seep_config, M_DEVBUF);
+		ahc->seep_config = NULL;
+		sc = NULL;
 	} else {
-		/*
-		 * Put the data we've collected down into SRAM
-		 * where ahc_init will find it.
-		 */
-		int i;
-		int max_targ = sc.max_targets & CFMAXTARG;
-		uint16_t discenable;
-		uint16_t ultraenb;
-
-		discenable = 0;
-		ultraenb = 0;
-		if ((sc.adapter_control & CFULTRAEN) != 0) {
-			/*
-			 * Determine if this adapter has a "newstyle"
-			 * SEEPROM format.
-			 */
-			for (i = 0; i < max_targ; i++) {
-				if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){
-					ahc->flags |= AHC_NEWEEPROM_FMT;
-					break;
-				}
-			}
-		}
-
-		for (i = 0; i < max_targ; i++) {
-			u_int     scsirate;
-			uint16_t target_mask;
-
-			target_mask = 0x01 << i;
-			if (sc.device_flags[i] & CFDISC)
-				discenable |= target_mask;
-			if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
-				if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0)
-					ultraenb |= target_mask;
-			} else if ((sc.adapter_control & CFULTRAEN) != 0) {
-				ultraenb |= target_mask;
-			}
-			if ((sc.device_flags[i] & CFXFER) == 0x04
-			 && (ultraenb & target_mask) != 0) {
-				/* Treat 10MHz as a non-ultra speed */
-				sc.device_flags[i] &= ~CFXFER;
-			 	ultraenb &= ~target_mask;
-			}
-			if ((ahc->features & AHC_ULTRA2) != 0) {
-				u_int offset;
-
-				if (sc.device_flags[i] & CFSYNCH)
-					offset = MAX_OFFSET_ULTRA2;
-				else 
-					offset = 0;
-				ahc_outb(ahc, TARG_OFFSET + i, offset);
-
-				/*
-				 * The ultra enable bits contain the
-				 * high bit of the ultra2 sync rate
-				 * field.
-				 */
-				scsirate = (sc.device_flags[i] & CFXFER)
-					 | ((ultraenb & target_mask)
-					    ? 0x8 : 0x0);
-				if (sc.device_flags[i] & CFWIDEB)
-					scsirate |= WIDEXFER;
-			} else {
-				scsirate = (sc.device_flags[i] & CFXFER) << 4;
-				if (sc.device_flags[i] & CFSYNCH)
-					scsirate |= SOFS;
-				if (sc.device_flags[i] & CFWIDEB)
-					scsirate |= WIDEXFER;
-			}
-			ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
-		}
-		ahc->our_id = sc.brtime_id & CFSCSIID;
-
-		scsi_conf = (ahc->our_id & 0x7);
-		if (sc.adapter_control & CFSPARITY)
-			scsi_conf |= ENSPCHK;
-		if (sc.adapter_control & CFRESETB)
-			scsi_conf |= RESET_SCSI;
-
-		ahc->flags |=
-		    (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
-
-		if (sc.bios_control & CFEXTEND)
-			ahc->flags |= AHC_EXTENDED_TRANS_A;
-
-		if (sc.bios_control & CFBIOSEN)
-			ahc->flags |= AHC_BIOS_ENABLED;
-		if (ahc->features & AHC_ULTRA
-		 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
-			/* Should we enable Ultra mode? */
-			if (!(sc.adapter_control & CFULTRAEN))
-				/* Treat us as a non-ultra card */
-				ultraenb = 0;
-		}
-
-		if (sc.signature == CFSIGNATURE
-		 || sc.signature == CFSIGNATURE2) {
-			uint32_t devconfig;
-
-			/* Honor the STPWLEVEL settings */
-			devconfig = ahc_pci_read_config(ahc->dev_softc,
-							DEVCONFIG, /*bytes*/4);
-			devconfig &= ~STPWLEVEL;
-			if ((sc.bios_control & CFSTPWLEVEL) != 0)
-				devconfig |= STPWLEVEL;
-			ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
-					     devconfig, /*bytes*/4);
-		}
-		/* Set SCSICONF info */
-		ahc_outb(ahc, SCSICONF, scsi_conf);
-		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
-		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
-		ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
-		ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
+		ahc_parse_pci_eeprom(ahc, sc);
 	}
 
 	/*
@@ -1415,10 +1317,6 @@
 	 * hasn't failed yet...
 	 */
 	have_autoterm = have_seeprom;
-	if (have_seeprom)
-		adapter_control = sc.adapter_control;
-	else
-		adapter_control = CFAUTOTERM;
 
 	/*
 	 * Some low-cost chips have SEEPROM and auto-term control built
@@ -1426,17 +1324,141 @@
 	 * if the termination logic is enabled.
 	 */
 	if ((ahc->features & AHC_SPIOCAP) != 0) {
-		if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0)
-			have_autoterm = TRUE;
-		else
+		if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
 			have_autoterm = FALSE;
 	}
 
 	if (have_autoterm) {
 		ahc_acquire_seeprom(ahc, &sd);
-		configure_termination(ahc, &sd, adapter_control, sxfrctl1);
+		configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
 		ahc_release_seeprom(&sd);
+	} else if (have_seeprom) {
+		*sxfrctl1 &= ~STPWEN;
+		if ((sc->adapter_control & CFSTERM) != 0)
+			*sxfrctl1 |= STPWEN;
+		if (bootverbose)
+			printf("%s: Low byte termination %sabled\n",
+			       ahc_name(ahc),
+			       (*sxfrctl1 & STPWEN) ? "en" : "dis");
+	}
+}
+
+static void
+ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
+{
+	/*
+	 * Put the data we've collected down into SRAM
+	 * where ahc_init will find it.
+	 */
+	int	 i;
+	int	 max_targ = sc->max_targets & CFMAXTARG;
+	u_int	 scsi_conf;
+	uint16_t discenable;
+	uint16_t ultraenb;
+
+	discenable = 0;
+	ultraenb = 0;
+	if ((sc->adapter_control & CFULTRAEN) != 0) {
+		/*
+		 * Determine if this adapter has a "newstyle"
+		 * SEEPROM format.
+		 */
+		for (i = 0; i < max_targ; i++) {
+			if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
+				ahc->flags |= AHC_NEWEEPROM_FMT;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < max_targ; i++) {
+		u_int     scsirate;
+		uint16_t target_mask;
+
+		target_mask = 0x01 << i;
+		if (sc->device_flags[i] & CFDISC)
+			discenable |= target_mask;
+		if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
+			if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
+				ultraenb |= target_mask;
+		} else if ((sc->adapter_control & CFULTRAEN) != 0) {
+			ultraenb |= target_mask;
+		}
+		if ((sc->device_flags[i] & CFXFER) == 0x04
+		 && (ultraenb & target_mask) != 0) {
+			/* Treat 10MHz as a non-ultra speed */
+			sc->device_flags[i] &= ~CFXFER;
+		 	ultraenb &= ~target_mask;
+		}
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			u_int offset;
+
+			if (sc->device_flags[i] & CFSYNCH)
+				offset = MAX_OFFSET_ULTRA2;
+			else 
+				offset = 0;
+			ahc_outb(ahc, TARG_OFFSET + i, offset);
+
+			/*
+			 * The ultra enable bits contain the
+			 * high bit of the ultra2 sync rate
+			 * field.
+			 */
+			scsirate = (sc->device_flags[i] & CFXFER)
+				 | ((ultraenb & target_mask) ? 0x8 : 0x0);
+			if (sc->device_flags[i] & CFWIDEB)
+				scsirate |= WIDEXFER;
+		} else {
+			scsirate = (sc->device_flags[i] & CFXFER) << 4;
+			if (sc->device_flags[i] & CFSYNCH)
+				scsirate |= SOFS;
+			if (sc->device_flags[i] & CFWIDEB)
+				scsirate |= WIDEXFER;
+		}
+		ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
+	}
+	ahc->our_id = sc->brtime_id & CFSCSIID;
+
+	scsi_conf = (ahc->our_id & 0x7);
+	if (sc->adapter_control & CFSPARITY)
+		scsi_conf |= ENSPCHK;
+	if (sc->adapter_control & CFRESETB)
+		scsi_conf |= RESET_SCSI;
+
+	ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
+
+	if (sc->bios_control & CFEXTEND)
+		ahc->flags |= AHC_EXTENDED_TRANS_A;
+
+	if (sc->bios_control & CFBIOSEN)
+		ahc->flags |= AHC_BIOS_ENABLED;
+	if (ahc->features & AHC_ULTRA
+	 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
+		/* Should we enable Ultra mode? */
+		if (!(sc->adapter_control & CFULTRAEN))
+			/* Treat us as a non-ultra card */
+			ultraenb = 0;
+	}
+
+	if (sc->signature == CFSIGNATURE
+	 || sc->signature == CFSIGNATURE2) {
+		uint32_t devconfig;
+
+		/* Honor the STPWLEVEL settings */
+		devconfig = ahc_pci_read_config(ahc->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		devconfig &= ~STPWLEVEL;
+		if ((sc->bios_control & CFSTPWLEVEL) != 0)
+			devconfig |= STPWLEVEL;
+		ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+				     devconfig, /*bytes*/4);
 	}
+	/* Set SCSICONF info */
+	ahc_outb(ahc, SCSICONF, scsi_conf);
+	ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+	ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+	ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
+	ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
 }
 
 static void
@@ -1479,10 +1501,10 @@
 		enablePRI_high = 0;
 		if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
 			ahc_new_term_detect(ahc, &enableSEC_low,
-					       &enableSEC_high,
-					       &enablePRI_low,
-					       &enablePRI_high,
-					       &eeprom_present);
+					    &enableSEC_high,
+					    &enablePRI_low,
+					    &enablePRI_high,
+					    &eeprom_present);
 			if ((adapter_control & CFSEAUTOTERM) == 0) {
 				if (bootverbose)
 					printf("%s: Manual SE Termination\n",
@@ -1731,7 +1753,12 @@
 		     int *externalcable_present, int *eeprom_present)
 {
 	uint8_t brdctl;
+	uint8_t spiocap;
 
+	spiocap = ahc_inb(ahc, SPIOCAP);
+	spiocap &= ~SOFTCMDEN;
+	spiocap |= EXT_BRDCTL;
+	ahc_outb(ahc, SPIOCAP, spiocap);
 	ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
 	ahc_outb(ahc, BRDCTL, 0);
 	brdctl = ahc_inb(ahc, BRDCTL);
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_proc.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_proc.c	Tue May 28 16:02:29 2002
@@ -37,7 +37,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#19 $
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
@@ -52,6 +52,8 @@
 				      u_int target_id, u_int target_offset);
 static void	ahc_dump_device_state(struct info_str *info,
 				      struct ahc_linux_device *dev);
+static int	ahc_proc_write_seeprom(struct ahc_softc *ahc,
+				       char *buffer, int length);
 
 static void
 copy_mem_info(struct info_str *info, char *data, int len)
@@ -231,48 +233,89 @@
 {
 	struct seeprom_descriptor sd;
 	int have_seeprom;
+	u_long s;
+	int paused;
+	int written;
+
+	/* Default to failure. */
+	written = -EINVAL;
+	ahc_lock(ahc, &s);
+	paused = ahc_is_paused(ahc);
+	if (!paused)
+		ahc_pause(ahc);
 
 	if (length != sizeof(struct seeprom_config)) {
 		printf("ahc_proc_write_seeprom: incorrect buffer size\n");
-		return (-EINVAL);
+		goto done;
 	}
 
 	have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
 	if (have_seeprom == 0) {
-		printf("ahc_proc_write_seeprom: checksum verification failuire\n");
-		return (-EINVAL);
+		printf("ahc_proc_write_seeprom: cksum verification failed\n");
+		goto done;
 	}
 
 	sd.sd_ahc = ahc;
-	sd.sd_control_offset = SEECTL;
-	sd.sd_status_offset = SEECTL;
-	sd.sd_dataout_offset = SEECTL;
-	if (ahc->flags & AHC_LARGE_SEEPROM)
-		sd.sd_chip = C56_66;
-	else
+	if ((ahc->chip & AHC_VL) != 0) {
+		sd.sd_control_offset = SEECTL_2840;
+		sd.sd_status_offset = STATUS_2840;
+		sd.sd_dataout_offset = STATUS_2840;		
 		sd.sd_chip = C46;
-	sd.sd_MS = SEEMS;
-	sd.sd_RDY = SEERDY;
-	sd.sd_CS = SEECS;
-	sd.sd_CK = SEECK;
-	sd.sd_DO = SEEDO;
-	sd.sd_DI = SEEDI;
+		sd.sd_MS = 0;
+		sd.sd_RDY = EEPROM_TF;
+		sd.sd_CS = CS_2840;
+		sd.sd_CK = CK_2840;
+		sd.sd_DO = DO_2840;
+		sd.sd_DI = DI_2840;
+		have_seeprom = TRUE;
+	} else {
+		sd.sd_control_offset = SEECTL;
+		sd.sd_status_offset = SEECTL;
+		sd.sd_dataout_offset = SEECTL;
+		if (ahc->flags & AHC_LARGE_SEEPROM)
+			sd.sd_chip = C56_66;
+		else
+			sd.sd_chip = C46;
+		sd.sd_MS = SEEMS;
+		sd.sd_RDY = SEERDY;
+		sd.sd_CS = SEECS;
+		sd.sd_CK = SEECK;
+		sd.sd_DO = SEEDO;
+		sd.sd_DI = SEEDI;
+		have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+	}
 
-	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
 	if (!have_seeprom) {
 		printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
-		return (-EINVAL);
+		goto done;
 	} else {
 		u_int start_addr;
 
+		if (ahc->seep_config == NULL) {
+			ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+						  M_DEVBUF, M_NOWAIT);
+			if (ahc->seep_config == NULL) {
+				printf("aic7xxx: Unable to allocate serial "
+				       "eeprom buffer.  Write failing\n");
+				goto done;
+			}
+		}
 		printf("aic7xxx: Writing Serial EEPROM\n");
 		start_addr = 32 * (ahc->channel - 'A');
 		ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
-				  sizeof(struct seeprom_config));
-		ahc_release_seeprom(&sd);
+				  sizeof(struct seeprom_config)/2);
+		ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config,
+				 start_addr, sizeof(struct seeprom_config)/2);
+		if ((ahc->chip & AHC_VL) == 0)
+			ahc_release_seeprom(&sd);
+		written = length;
 	}
 
-	return (length);
+done:
+	if (!paused)
+		ahc_unpause(ahc);
+	ahc_unlock(ahc, &s);
+	return (written);
 }
 
 /*
@@ -284,24 +327,27 @@
 {
 	struct	ahc_softc *ahc;
 	struct	info_str info;
-	struct	seeprom_descriptor sd;
 	char	ahc_info[256];
-	u_int16_t buf[32];
+	u_long	s;
 	u_int	max_targ;
 	u_int	i;
-	int	have_seeprom;
+	int	retval;
 
+	retval = -EINVAL;
+	ahc_list_lock(&s);
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
 		if (ahc->platform_data->host->host_no == hostno)
 			break;
 	}
 
 	if (ahc == NULL)
-		return (-EINVAL);
+		goto done;
 
 	 /* Has data been written to the file? */ 
-	if (inout == TRUE)
-		return (ahc_proc_write_seeprom(ahc, buffer, length));
+	if (inout == TRUE) {
+		retval = ahc_proc_write_seeprom(ahc, buffer, length);
+		goto done;
+	}
 
 	if (start)
 		*start = buffer;
@@ -316,48 +362,19 @@
 	ahc_controller_info(ahc, ahc_info);
 	copy_info(&info, "%s\n\n", ahc_info);
 
-	sd.sd_ahc = ahc;
-	sd.sd_control_offset = SEECTL;
-	sd.sd_status_offset = SEECTL;
-	sd.sd_dataout_offset = SEECTL;
-	if (ahc->flags & AHC_LARGE_SEEPROM)
-		sd.sd_chip = C56_66;
-	else
-		sd.sd_chip = C46;
-	sd.sd_MS = SEEMS;
-	sd.sd_RDY = SEERDY;
-	sd.sd_CS = SEECS;
-	sd.sd_CK = SEECK;
-	sd.sd_DO = SEEDO;
-	sd.sd_DI = SEEDI;
-
-	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
-	if (!have_seeprom)
+	if (ahc->seep_config == NULL)
 		copy_info(&info, "No Serial EEPROM\n");
 	else {
-		u_int start_addr;
-
-		start_addr = 32 * (ahc->channel - 'A');
-		have_seeprom = ahc_read_seeprom(&sd, (u_int16_t *)&buf,
-						start_addr, sizeof(buf)/2);
-		if (have_seeprom)
-			have_seeprom =
-			    ahc_verify_cksum((struct seeprom_config*)&buf);
-		if (have_seeprom == 0)
-			copy_info(&info, "Corrupted Serial EEPROM\n");
-		else {
-			copy_info(&info, "Serial EEPROM:\n");
-			for (i = 0; i < sizeof(buf)/2; i++) {
-				if (((i % 8) == 0) && (i != 0)) {
-					copy_info(&info, "\n");
-				}
-				copy_info(&info, "0x%.4x ", buf[i]);
+		copy_info(&info, "Serial EEPROM:\n");
+		for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
+			if (((i % 8) == 0) && (i != 0)) {
+				copy_info(&info, "\n");
 			}
-			copy_info(&info, "\n");
+			copy_info(&info, "0x%.4x ",
+				  ((uint16_t*)ahc->seep_config)[i]);
 		}
-		ahc_release_seeprom(&sd);
+		copy_info(&info, "\n");
 	}
-
 	copy_info(&info, "\n");
 
 	max_targ = 15;
@@ -381,5 +398,8 @@
 		ahc_dump_target_state(ahc, &info, our_id,
 				      channel, target_id, i);
 	}
-	return (info.pos > info.offset ? info.pos - info.offset : 0);
+	retval = info.pos > info.offset ? info.pos - info.offset : 0;
+done:
+	ahc_list_unlock(&s);
+	return (retval);
 }
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_reg.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_reg.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_reg.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_reg.h	Tue May 28 16:02:29 2002
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#43 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#30 $
  */
 
 #define	SCSISEQ         		0x00
@@ -184,7 +184,7 @@
 #define		SOFT1           	0x80
 #define		SOFT0           	0x40
 #define		SOFTCMDEN       	0x20
-#define		HAS_BRDCTL      	0x10
+#define		EXT_BRDCTL      	0x10
 #define		SEEPROM         	0x08
 #define		EEPROM          	0x04
 #define		ROM             	0x02
@@ -327,7 +327,9 @@
 
 #define	DATA_COUNT_ODD  		0x55
 
+#define	HA_274_BIOSGLOBAL		0x56
 #define	INITIATOR_TAG   		0x56
+#define		HA_274_EXTENDED_TRANS	0x01
 
 #define	SEQ_FLAGS2      		0x57
 #define		TARGET_MSG_PENDING	0x02
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_seq.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_seq.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aic7xxx_seq.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aic7xxx_seq.h	Tue May 28 16:02:29 2002
@@ -2,13 +2,13 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#43 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#30 $
  */
 static uint8_t seqprog[] = {
 	0xb2, 0x00, 0x00, 0x08,
 	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0xe0, 0x59,
+	0x00, 0x65, 0xe4, 0x59,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x6a, 0x24, 0x08,
 	0x40, 0x00, 0x40, 0x68,
@@ -21,15 +21,15 @@
 	0x01, 0x4d, 0xc8, 0x30,
 	0x00, 0x4c, 0x12, 0x70,
 	0x01, 0x39, 0xa2, 0x30,
-	0x00, 0x6a, 0xb2, 0x5e,
+	0x00, 0x6a, 0xb6, 0x5e,
 	0x01, 0x51, 0x20, 0x31,
 	0x01, 0x57, 0xae, 0x00,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0x04, 0x5e,
+	0x00, 0x51, 0x08, 0x5e,
 	0x01, 0x51, 0xc8, 0x30,
 	0x00, 0x39, 0xc8, 0x60,
 	0x00, 0xbb, 0x30, 0x70,
-	0xc1, 0x6a, 0xca, 0x5e,
+	0xc1, 0x6a, 0xce, 0x5e,
 	0x01, 0xbf, 0x72, 0x30,
 	0x01, 0x40, 0x7e, 0x31,
 	0x01, 0x90, 0x80, 0x30,
@@ -49,10 +49,10 @@
 	0x08, 0x3c, 0x78, 0x00,
 	0x01, 0x50, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xee, 0x5d,
+	0x48, 0x6a, 0xf2, 0x5d,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xee, 0x5d,
+	0x48, 0x6a, 0xf2, 0x5d,
 	0x01, 0x6a, 0x26, 0x01,
 	0xf0, 0x19, 0x7a, 0x08,
 	0x0f, 0x18, 0xc8, 0x08,
@@ -63,7 +63,7 @@
 	0x80, 0x3d, 0x7a, 0x00,
 	0x01, 0x3d, 0xd8, 0x31,
 	0x01, 0x3d, 0x32, 0x31,
-	0x10, 0x03, 0x46, 0x79,
+	0x10, 0x03, 0x48, 0x79,
 	0x00, 0x65, 0xf4, 0x58,
 	0x80, 0x66, 0xae, 0x78,
 	0x01, 0x66, 0xd8, 0x31,
@@ -79,7 +79,7 @@
 	0x00, 0x65, 0xaa, 0x48,
 	0x01, 0x66, 0xd8, 0x31,
 	0x01, 0x66, 0x32, 0x31,
-	0x10, 0x03, 0x46, 0x79,
+	0x10, 0x03, 0x48, 0x79,
 	0x00, 0x65, 0xf4, 0x58,
 	0x01, 0x66, 0xd8, 0x31,
 	0x01, 0x66, 0x32, 0x31,
@@ -88,12 +88,12 @@
 	0xff, 0x6a, 0xd8, 0x01,
 	0xff, 0x6a, 0x32, 0x01,
 	0x90, 0x3c, 0x78, 0x00,
-	0x02, 0x57, 0x3a, 0x69,
-	0x10, 0x03, 0x38, 0x69,
+	0x02, 0x57, 0x3c, 0x69,
+	0x10, 0x03, 0x3a, 0x69,
 	0x00, 0x65, 0x1e, 0x41,
 	0x02, 0x57, 0xae, 0x00,
 	0x00, 0x65, 0x9e, 0x40,
-	0x61, 0x6a, 0xca, 0x5e,
+	0x61, 0x6a, 0xce, 0x5e,
 	0x08, 0x51, 0x1e, 0x71,
 	0x02, 0x0b, 0xb2, 0x78,
 	0x00, 0x65, 0xae, 0x40,
@@ -105,8 +105,8 @@
 	0x08, 0x1f, 0xc4, 0x78,
 	0x80, 0x3d, 0x7a, 0x00,
 	0x20, 0x6a, 0x16, 0x00,
-	0x00, 0x65, 0xc0, 0x41,
-	0x00, 0x65, 0xa4, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
+	0x00, 0x65, 0xa8, 0x5e,
 	0x00, 0x65, 0x12, 0x40,
 	0x20, 0x11, 0xd2, 0x68,
 	0x20, 0x6a, 0x18, 0x00,
@@ -133,58 +133,59 @@
 	0xf7, 0x01, 0x02, 0x08,
 	0x01, 0x06, 0xcc, 0x34,
 	0xb2, 0x00, 0x00, 0x08,
-	0x40, 0x6a, 0x16, 0x00,
 	0x01, 0x40, 0x20, 0x31,
 	0x01, 0xbf, 0x80, 0x30,
 	0x01, 0xb9, 0x7a, 0x30,
 	0x01, 0xba, 0x7c, 0x30,
 	0x00, 0x65, 0xea, 0x58,
-	0x80, 0x0b, 0xbc, 0x79,
-	0xe4, 0x6a, 0x60, 0x5d,
-	0x80, 0xba, 0x76, 0x5d,
+	0x80, 0x0b, 0xbe, 0x79,
+	0xe4, 0x6a, 0x64, 0x5d,
+	0x40, 0x6a, 0x16, 0x00,
+	0x80, 0xba, 0x7a, 0x5d,
 	0x20, 0xb8, 0x16, 0x79,
-	0x20, 0x6a, 0x76, 0x5d,
-	0x00, 0xab, 0x76, 0x5d,
+	0x20, 0x6a, 0x7a, 0x5d,
+	0x00, 0xab, 0x7a, 0x5d,
 	0x01, 0xa9, 0x78, 0x30,
 	0x10, 0xb8, 0x1e, 0x79,
-	0xe4, 0x6a, 0x60, 0x5d,
+	0xe4, 0x6a, 0x64, 0x5d,
 	0x00, 0x65, 0xae, 0x40,
-	0x10, 0x03, 0x36, 0x69,
-	0x08, 0x3c, 0x52, 0x69,
-	0x04, 0x3c, 0x8a, 0x69,
-	0x02, 0x3c, 0x90, 0x69,
-	0x01, 0x3c, 0x3c, 0x79,
+	0x10, 0x03, 0x38, 0x69,
+	0x08, 0x3c, 0x54, 0x69,
+	0x04, 0x3c, 0x8c, 0x69,
+	0x02, 0x3c, 0x92, 0x69,
+	0x01, 0x3c, 0x3e, 0x79,
 	0x01, 0x6a, 0xa2, 0x30,
-	0x00, 0x65, 0x9c, 0x59,
+	0x00, 0x65, 0x9e, 0x59,
 	0x04, 0x51, 0x2c, 0x61,
-	0x00, 0x6a, 0xb2, 0x5e,
+	0x00, 0x6a, 0xb6, 0x5e,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0x04, 0x5e,
+	0x00, 0xbb, 0x08, 0x5e,
+	0x00, 0x65, 0xec, 0x58,
 	0x00, 0x65, 0x16, 0x41,
 	0xa4, 0x6a, 0x06, 0x00,
 	0x00, 0x65, 0xf4, 0x58,
 	0x00, 0x65, 0xae, 0x40,
-	0xe4, 0x6a, 0x60, 0x5d,
-	0x20, 0x3c, 0x42, 0x79,
-	0x02, 0x6a, 0x76, 0x5d,
-	0x04, 0x6a, 0x76, 0x5d,
-	0x01, 0x03, 0x44, 0x69,
+	0xe4, 0x6a, 0x64, 0x5d,
+	0x20, 0x3c, 0x44, 0x79,
+	0x02, 0x6a, 0x7a, 0x5d,
+	0x04, 0x6a, 0x7a, 0x5d,
+	0x01, 0x03, 0x46, 0x69,
 	0xf7, 0x11, 0x22, 0x08,
 	0xff, 0x6a, 0x24, 0x08,
 	0xff, 0x6a, 0x06, 0x08,
 	0x01, 0x6a, 0x7e, 0x00,
-	0x00, 0x65, 0x9c, 0x59,
+	0x00, 0x65, 0x9e, 0x59,
 	0x00, 0x65, 0x04, 0x40,
 	0x80, 0x86, 0xc8, 0x08,
 	0x01, 0x4f, 0xc8, 0x30,
-	0x00, 0x50, 0x64, 0x61,
-	0xc4, 0x6a, 0x60, 0x5d,
-	0x40, 0x3c, 0x60, 0x79,
-	0x28, 0x6a, 0x76, 0x5d,
-	0x00, 0x65, 0x44, 0x41,
-	0x08, 0x6a, 0x76, 0x5d,
-	0x00, 0x65, 0x44, 0x41,
-	0x84, 0x6a, 0x60, 0x5d,
+	0x00, 0x50, 0x66, 0x61,
+	0xc4, 0x6a, 0x64, 0x5d,
+	0x40, 0x3c, 0x62, 0x79,
+	0x28, 0x6a, 0x7a, 0x5d,
+	0x00, 0x65, 0x46, 0x41,
+	0x08, 0x6a, 0x7a, 0x5d,
+	0x00, 0x65, 0x46, 0x41,
+	0x84, 0x6a, 0x64, 0x5d,
 	0x00, 0x65, 0xf4, 0x58,
 	0x01, 0x66, 0xc8, 0x30,
 	0x01, 0x64, 0xd8, 0x31,
@@ -192,60 +193,61 @@
 	0x5b, 0x64, 0xc8, 0x28,
 	0x30, 0x64, 0xca, 0x18,
 	0x01, 0x6c, 0xc8, 0x30,
-	0xff, 0x64, 0x86, 0x79,
+	0xff, 0x64, 0x88, 0x79,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x78, 0x79,
-	0x01, 0x64, 0x7e, 0x61,
+	0x02, 0x0b, 0x7a, 0x79,
+	0x01, 0x64, 0x80, 0x61,
 	0xf7, 0x01, 0x02, 0x08,
 	0x01, 0x06, 0xd8, 0x31,
 	0x01, 0x06, 0x32, 0x31,
 	0xff, 0x64, 0xc8, 0x18,
-	0xff, 0x64, 0x78, 0x69,
+	0xff, 0x64, 0x7a, 0x69,
 	0xf7, 0x3c, 0x78, 0x08,
 	0x00, 0x65, 0x1e, 0x41,
 	0x40, 0xaa, 0x7e, 0x10,
-	0x04, 0xaa, 0x60, 0x5d,
-	0x00, 0x65, 0x52, 0x42,
-	0xc4, 0x6a, 0x60, 0x5d,
+	0x04, 0xaa, 0x64, 0x5d,
+	0x00, 0x65, 0x56, 0x42,
+	0xc4, 0x6a, 0x64, 0x5d,
 	0xc0, 0x6a, 0x7e, 0x00,
-	0x00, 0xa8, 0x76, 0x5d,
+	0x00, 0xa8, 0x7a, 0x5d,
 	0xe4, 0x6a, 0x06, 0x00,
-	0x00, 0x6a, 0x76, 0x5d,
-	0x00, 0x65, 0x44, 0x41,
-	0x10, 0x3c, 0xa0, 0x69,
-	0x00, 0xbb, 0x80, 0x44,
+	0x00, 0x6a, 0x7a, 0x5d,
+	0x00, 0x65, 0x46, 0x41,
+	0x10, 0x3c, 0xa2, 0x69,
+	0x00, 0xbb, 0x84, 0x44,
 	0x18, 0x6a, 0xda, 0x01,
 	0x01, 0x69, 0xd8, 0x31,
 	0x1c, 0x6a, 0xd0, 0x01,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xa8, 0x79,
+	0x80, 0xee, 0xaa, 0x79,
 	0xff, 0x6a, 0xdc, 0x09,
 	0x01, 0x93, 0x26, 0x01,
 	0x03, 0x6a, 0x2a, 0x01,
 	0x01, 0x69, 0x32, 0x31,
-	0x1c, 0x6a, 0xd2, 0x5d,
+	0x1c, 0x6a, 0xd6, 0x5d,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x9a, 0x5e,
+	0x00, 0x65, 0x9e, 0x5e,
 	0x01, 0x50, 0xa0, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
 	0x80, 0x6a, 0x74, 0x00,
 	0x80, 0x3c, 0x78, 0x00,
-	0x00, 0x65, 0xca, 0x5d,
+	0x40, 0x6a, 0x16, 0x00,
+	0x00, 0x65, 0xce, 0x5d,
 	0x01, 0x3f, 0xc8, 0x30,
-	0xbf, 0x64, 0x52, 0x7a,
-	0x80, 0x64, 0xa6, 0x73,
-	0xa0, 0x64, 0x04, 0x74,
-	0xc0, 0x64, 0xf8, 0x73,
-	0xe0, 0x64, 0x34, 0x74,
-	0x01, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0xc0, 0x41,
+	0xbf, 0x64, 0x56, 0x7a,
+	0x80, 0x64, 0xaa, 0x73,
+	0xa0, 0x64, 0x08, 0x74,
+	0xc0, 0x64, 0xfc, 0x73,
+	0xe0, 0x64, 0x38, 0x74,
+	0x01, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
 	0xf7, 0x11, 0x22, 0x08,
 	0x01, 0x06, 0xd4, 0x30,
 	0xff, 0x6a, 0x24, 0x08,
 	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0xda, 0x79,
+	0x09, 0x0c, 0xde, 0x79,
 	0x08, 0x0c, 0x04, 0x68,
-	0xb1, 0x6a, 0xca, 0x5e,
+	0xb1, 0x6a, 0xce, 0x5e,
 	0xff, 0x6a, 0x26, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0x02, 0x6a, 0x08, 0x30,
@@ -258,33 +260,33 @@
 	0x00, 0xa5, 0x4a, 0x21,
 	0x00, 0xa6, 0x4c, 0x21,
 	0x00, 0xa7, 0x4e, 0x25,
-	0x08, 0xeb, 0xce, 0x7e,
-	0x80, 0xeb, 0xfa, 0x79,
+	0x08, 0xeb, 0xd2, 0x7e,
+	0x80, 0xeb, 0xfe, 0x79,
 	0xff, 0x6a, 0xd6, 0x09,
-	0x08, 0xeb, 0xfe, 0x69,
+	0x08, 0xeb, 0x02, 0x6a,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0xa3, 0xce, 0x6e,
-	0x88, 0xeb, 0x14, 0x72,
-	0x08, 0xeb, 0xce, 0x6e,
-	0x04, 0xea, 0x18, 0xe2,
-	0x08, 0xee, 0xce, 0x6e,
+	0x80, 0xa3, 0xd2, 0x6e,
+	0x88, 0xeb, 0x18, 0x72,
+	0x08, 0xeb, 0xd2, 0x6e,
+	0x04, 0xea, 0x1c, 0xe2,
+	0x08, 0xee, 0xd2, 0x6e,
 	0x04, 0x6a, 0xd0, 0x81,
 	0x05, 0xa4, 0xc0, 0x89,
 	0x03, 0xa5, 0xc2, 0x31,
 	0x09, 0x6a, 0xd6, 0x05,
-	0x00, 0x65, 0xfc, 0x59,
+	0x00, 0x65, 0x00, 0x5a,
 	0x06, 0xa4, 0xd4, 0x89,
-	0x80, 0x94, 0xce, 0x7e,
+	0x80, 0x94, 0xd2, 0x7e,
 	0x07, 0xe9, 0x10, 0x31,
-	0x01, 0x8c, 0x20, 0x7a,
+	0x01, 0x8c, 0x24, 0x7a,
 	0x01, 0x55, 0xaa, 0x10,
 	0x01, 0xe9, 0x46, 0x31,
-	0x00, 0xa3, 0xac, 0x5e,
-	0x00, 0x65, 0xee, 0x59,
+	0x00, 0xa3, 0xb0, 0x5e,
+	0x00, 0x65, 0xf2, 0x59,
 	0x01, 0xa4, 0xca, 0x30,
-	0x01, 0x55, 0x2c, 0x7a,
+	0x01, 0x55, 0x30, 0x7a,
 	0x04, 0x65, 0xca, 0x00,
-	0x80, 0xa3, 0x30, 0x7a,
+	0x80, 0xa3, 0x34, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
 	0x80, 0x93, 0x26, 0x01,
@@ -292,168 +294,168 @@
 	0x01, 0x8c, 0xc8, 0x30,
 	0x00, 0x88, 0xc8, 0x18,
 	0x02, 0x64, 0xc8, 0x88,
-	0xff, 0x64, 0xce, 0x7e,
-	0xff, 0x8d, 0x46, 0x6a,
-	0xff, 0x8e, 0x46, 0x6a,
+	0xff, 0x64, 0xd2, 0x7e,
+	0xff, 0x8d, 0x4a, 0x6a,
+	0xff, 0x8e, 0x4a, 0x6a,
 	0x03, 0x8c, 0xd4, 0x98,
-	0x00, 0x65, 0xce, 0x56,
+	0x00, 0x65, 0xd2, 0x56,
 	0x01, 0x64, 0x70, 0x30,
 	0xff, 0x64, 0xc8, 0x10,
 	0x01, 0x64, 0xc8, 0x18,
 	0x00, 0x8c, 0x18, 0x19,
 	0xff, 0x8d, 0x1a, 0x21,
 	0xff, 0x8e, 0x1c, 0x25,
-	0x80, 0x3c, 0x56, 0x6a,
-	0x21, 0x6a, 0xca, 0x46,
+	0x80, 0x3c, 0x5a, 0x6a,
+	0x21, 0x6a, 0xce, 0x46,
 	0xa8, 0x6a, 0x76, 0x00,
 	0x79, 0x6a, 0x76, 0x00,
-	0x40, 0x3f, 0x5e, 0x6a,
+	0x40, 0x3f, 0x62, 0x6a,
 	0x04, 0x3b, 0x76, 0x00,
 	0x04, 0x6a, 0xd4, 0x81,
-	0x20, 0x3c, 0x66, 0x7a,
-	0x51, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0x80, 0x42,
+	0x20, 0x3c, 0x6a, 0x7a,
+	0x51, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0x84, 0x42,
 	0x20, 0x3c, 0x78, 0x00,
-	0x00, 0xb3, 0xac, 0x5e,
+	0x00, 0xb3, 0xb0, 0x5e,
 	0x07, 0xac, 0x10, 0x31,
 	0x05, 0xb3, 0x46, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xe0, 0x5d,
+	0xac, 0x6a, 0xe4, 0x5d,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0xb3, 0x6a, 0xe4, 0x5d,
-	0x00, 0x65, 0x36, 0x5a,
+	0xb3, 0x6a, 0xe8, 0x5d,
+	0x00, 0x65, 0x3a, 0x5a,
 	0xfd, 0xa4, 0x48, 0x09,
 	0x01, 0x8c, 0xaa, 0x08,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xd8, 0x5d,
-	0x01, 0xa4, 0x92, 0x7a,
+	0x00, 0x65, 0xdc, 0x5d,
+	0x01, 0xa4, 0x96, 0x7a,
 	0x04, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
 	0x80, 0x02, 0x04, 0x00,
-	0x10, 0x0c, 0x88, 0x7a,
-	0x03, 0x9e, 0x8a, 0x6a,
+	0x10, 0x0c, 0x8c, 0x7a,
+	0x03, 0x9e, 0x8e, 0x6a,
 	0x7f, 0x02, 0x04, 0x08,
-	0x91, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0xc0, 0x41,
+	0x91, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
 	0x01, 0xa4, 0xca, 0x30,
-	0x80, 0xa3, 0x98, 0x7a,
+	0x80, 0xa3, 0x9c, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
-	0x01, 0x55, 0x9c, 0x7a,
+	0x01, 0x55, 0xa0, 0x7a,
 	0x04, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
 	0x01, 0x3b, 0x26, 0x31,
-	0x00, 0x65, 0x02, 0x5a,
-	0x01, 0xfc, 0xaa, 0x6a,
-	0x80, 0x0b, 0xa0, 0x6a,
-	0x10, 0x0c, 0xa0, 0x7a,
-	0x20, 0x93, 0xa0, 0x6a,
+	0x00, 0x65, 0x06, 0x5a,
+	0x01, 0xfc, 0xae, 0x6a,
+	0x80, 0x0b, 0xa4, 0x6a,
+	0x10, 0x0c, 0xa4, 0x7a,
+	0x20, 0x93, 0xa4, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x02, 0xfc, 0xb4, 0x7a,
-	0x40, 0x0d, 0xce, 0x6a,
+	0x02, 0xfc, 0xb8, 0x7a,
+	0x40, 0x0d, 0xd2, 0x6a,
 	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0xce, 0x42,
-	0x40, 0x0d, 0xba, 0x6a,
-	0x00, 0x65, 0x02, 0x5a,
-	0x00, 0x65, 0xac, 0x42,
-	0x80, 0xfc, 0xc4, 0x7a,
-	0x80, 0xa4, 0xc4, 0x6a,
+	0x00, 0x65, 0xd2, 0x42,
+	0x40, 0x0d, 0xbe, 0x6a,
+	0x00, 0x65, 0x06, 0x5a,
+	0x00, 0x65, 0xb0, 0x42,
+	0x80, 0xfc, 0xc8, 0x7a,
+	0x80, 0xa4, 0xc8, 0x6a,
 	0xff, 0xa5, 0x4a, 0x19,
 	0xff, 0xa6, 0x4c, 0x21,
 	0xff, 0xa7, 0x4e, 0x21,
 	0xf8, 0xfc, 0x48, 0x09,
 	0xff, 0x6a, 0xaa, 0x08,
-	0x04, 0xfc, 0xcc, 0x7a,
+	0x04, 0xfc, 0xd0, 0x7a,
 	0x01, 0x55, 0xaa, 0x00,
 	0xff, 0x6a, 0x46, 0x09,
-	0x04, 0x3b, 0xe6, 0x6a,
+	0x04, 0x3b, 0xea, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0xd0, 0x7a,
-	0x01, 0x94, 0xd0, 0x7a,
-	0x01, 0x94, 0xd0, 0x7a,
-	0x01, 0x94, 0xd0, 0x7a,
-	0x01, 0x94, 0xd0, 0x7a,
-	0x01, 0xa4, 0xe4, 0x7a,
-	0x01, 0xfc, 0xde, 0x7a,
-	0x01, 0x94, 0xe6, 0x6a,
-	0x00, 0x65, 0x80, 0x42,
-	0x01, 0x94, 0xe4, 0x7a,
-	0x10, 0x94, 0xe6, 0x6a,
+	0x01, 0x94, 0xd4, 0x7a,
+	0x01, 0x94, 0xd4, 0x7a,
+	0x01, 0x94, 0xd4, 0x7a,
+	0x01, 0x94, 0xd4, 0x7a,
+	0x01, 0x94, 0xd4, 0x7a,
+	0x01, 0xa4, 0xe8, 0x7a,
+	0x01, 0xfc, 0xe2, 0x7a,
+	0x01, 0x94, 0xea, 0x6a,
+	0x00, 0x65, 0x84, 0x42,
+	0x01, 0x94, 0xe8, 0x7a,
+	0x10, 0x94, 0xea, 0x6a,
 	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xea, 0x6a,
+	0x28, 0x93, 0xee, 0x6a,
 	0x01, 0x85, 0x0a, 0x01,
-	0x02, 0xfc, 0xf2, 0x6a,
+	0x02, 0xfc, 0xf6, 0x6a,
 	0x01, 0x14, 0x46, 0x31,
 	0xff, 0x6a, 0x10, 0x09,
 	0xfe, 0x85, 0x0a, 0x09,
-	0xff, 0x38, 0x00, 0x6b,
-	0x80, 0xa3, 0x00, 0x7b,
-	0x80, 0x0b, 0xfe, 0x7a,
-	0x04, 0x3b, 0x00, 0x7b,
+	0xff, 0x38, 0x04, 0x6b,
+	0x80, 0xa3, 0x04, 0x7b,
+	0x80, 0x0b, 0x02, 0x7b,
+	0x04, 0x3b, 0x04, 0x7b,
 	0xbf, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
-	0x00, 0x65, 0x02, 0x5a,
-	0x01, 0x0b, 0x0e, 0x6b,
-	0x10, 0x0c, 0x02, 0x7b,
-	0x04, 0x93, 0x0c, 0x6b,
-	0x01, 0x94, 0x0a, 0x7b,
-	0x10, 0x94, 0x0c, 0x6b,
+	0x00, 0x65, 0x06, 0x5a,
+	0x01, 0x0b, 0x12, 0x6b,
+	0x10, 0x0c, 0x06, 0x7b,
+	0x04, 0x93, 0x10, 0x6b,
+	0x01, 0x94, 0x0e, 0x7b,
+	0x10, 0x94, 0x10, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
 	0x01, 0x99, 0xd4, 0x30,
-	0x38, 0x93, 0x10, 0x6b,
-	0xff, 0x08, 0x62, 0x6b,
-	0xff, 0x09, 0x62, 0x6b,
-	0xff, 0x0a, 0x62, 0x6b,
-	0xff, 0x38, 0x2c, 0x7b,
+	0x38, 0x93, 0x14, 0x6b,
+	0xff, 0x08, 0x66, 0x6b,
+	0xff, 0x09, 0x66, 0x6b,
+	0xff, 0x0a, 0x66, 0x6b,
+	0xff, 0x38, 0x30, 0x7b,
 	0x04, 0x14, 0x10, 0x31,
 	0x01, 0x38, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xe6, 0x5d,
-	0x00, 0x38, 0xd2, 0x5d,
+	0x14, 0x6a, 0xea, 0x5d,
+	0x00, 0x38, 0xd6, 0x5d,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x58, 0x43,
-	0x80, 0xa3, 0x32, 0x7b,
+	0x00, 0x65, 0x5c, 0x43,
+	0x80, 0xa3, 0x36, 0x7b,
 	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0x62, 0x43,
-	0x08, 0xeb, 0x38, 0x7b,
-	0x00, 0x65, 0x02, 0x5a,
-	0x08, 0xeb, 0x34, 0x6b,
+	0x00, 0x65, 0x66, 0x43,
+	0x08, 0xeb, 0x3c, 0x7b,
+	0x00, 0x65, 0x06, 0x5a,
+	0x08, 0xeb, 0x38, 0x6b,
 	0x07, 0xe9, 0x10, 0x31,
 	0x01, 0xe9, 0xca, 0x30,
 	0x01, 0x65, 0x46, 0x31,
-	0x00, 0x6a, 0xac, 0x5e,
+	0x00, 0x6a, 0xb0, 0x5e,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa4, 0x6a, 0xe6, 0x5d,
-	0x08, 0x6a, 0xd2, 0x5d,
+	0xa4, 0x6a, 0xea, 0x5d,
+	0x08, 0x6a, 0xd6, 0x5d,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x9a, 0x5e,
+	0x00, 0x65, 0x9e, 0x5e,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x00, 0x65, 0x7c, 0x5e,
+	0x00, 0x65, 0x80, 0x5e,
 	0x01, 0x99, 0x46, 0x31,
-	0x00, 0xa3, 0xac, 0x5e,
+	0x00, 0xa3, 0xb0, 0x5e,
 	0x01, 0x88, 0x10, 0x31,
-	0x00, 0x65, 0x36, 0x5a,
-	0x00, 0x65, 0xee, 0x59,
+	0x00, 0x65, 0x3a, 0x5a,
+	0x00, 0x65, 0xf2, 0x59,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xd8, 0x5d,
-	0x01, 0x8c, 0x60, 0x7b,
+	0x00, 0x65, 0xdc, 0x5d,
+	0x01, 0x8c, 0x64, 0x7b,
 	0x01, 0x55, 0xaa, 0x10,
-	0x80, 0x0b, 0x80, 0x6a,
-	0x80, 0x0b, 0x6a, 0x6b,
-	0x01, 0x0c, 0x64, 0x7b,
-	0x10, 0x0c, 0x80, 0x7a,
-	0x03, 0x9e, 0x80, 0x6a,
-	0x00, 0x65, 0xf8, 0x59,
-	0x00, 0x6a, 0xac, 0x5e,
-	0x01, 0xa4, 0x8a, 0x6b,
-	0xff, 0x38, 0x80, 0x7b,
+	0x80, 0x0b, 0x84, 0x6a,
+	0x80, 0x0b, 0x6e, 0x6b,
+	0x01, 0x0c, 0x68, 0x7b,
+	0x10, 0x0c, 0x84, 0x7a,
+	0x03, 0x9e, 0x84, 0x6a,
+	0x00, 0x65, 0xfc, 0x59,
+	0x00, 0x6a, 0xb0, 0x5e,
+	0x01, 0xa4, 0x8e, 0x6b,
+	0xff, 0x38, 0x84, 0x7b,
 	0x01, 0x38, 0xc8, 0x30,
 	0x00, 0x08, 0x40, 0x19,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x00, 0x09, 0x42, 0x21,
 	0x00, 0x0a, 0x44, 0x21,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x82, 0x43,
+	0x00, 0x65, 0x86, 0x43,
 	0x03, 0x08, 0x40, 0x31,
 	0x03, 0x08, 0x40, 0x31,
 	0x01, 0x08, 0x40, 0x31,
@@ -462,19 +464,19 @@
 	0xfd, 0xb4, 0x68, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0x12, 0x01, 0x02, 0x00,
-	0x04, 0x3c, 0xc0, 0x79,
+	0x04, 0x3c, 0xc4, 0x79,
 	0xfb, 0x3c, 0x78, 0x08,
 	0x04, 0x93, 0x1e, 0x79,
-	0x01, 0x0c, 0x96, 0x6b,
+	0x01, 0x0c, 0x9a, 0x6b,
 	0x01, 0x55, 0x1e, 0x79,
 	0x80, 0x04, 0x1e, 0x79,
-	0xe4, 0x6a, 0x60, 0x5d,
-	0x23, 0x6a, 0x76, 0x5d,
-	0x01, 0x6a, 0x76, 0x5d,
+	0xe4, 0x6a, 0x64, 0x5d,
+	0x23, 0x6a, 0x7a, 0x5d,
+	0x01, 0x6a, 0x7a, 0x5d,
 	0x00, 0x65, 0x1e, 0x41,
-	0x00, 0x65, 0xc0, 0x41,
-	0x80, 0x3c, 0xaa, 0x6b,
-	0x21, 0x6a, 0xca, 0x46,
+	0x00, 0x65, 0xc4, 0x41,
+	0x80, 0x3c, 0xae, 0x6b,
+	0x21, 0x6a, 0xce, 0x46,
 	0x01, 0xbc, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x02, 0x6a, 0xf8, 0x01,
@@ -484,16 +486,16 @@
 	0xff, 0x6a, 0x12, 0x08,
 	0xff, 0x6a, 0x14, 0x08,
 	0xf3, 0xbc, 0xd4, 0x18,
-	0xa0, 0x6a, 0xd0, 0x53,
+	0xa0, 0x6a, 0xd4, 0x53,
 	0x04, 0xa0, 0x10, 0x31,
 	0xac, 0x6a, 0x26, 0x01,
 	0x04, 0xa0, 0x10, 0x31,
 	0x03, 0x08, 0x18, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa0, 0x6a, 0xe6, 0x5d,
-	0x00, 0xbc, 0xd2, 0x5d,
+	0xa0, 0x6a, 0xea, 0x5d,
+	0x00, 0xbc, 0xd6, 0x5d,
 	0x3d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xe8, 0x43,
+	0x00, 0x65, 0xec, 0x43,
 	0xff, 0x6a, 0x10, 0x09,
 	0xa4, 0x6a, 0x26, 0x01,
 	0x0c, 0xa0, 0x32, 0x31,
@@ -503,117 +505,117 @@
 	0x36, 0x6a, 0x26, 0x01,
 	0x02, 0x93, 0x26, 0x01,
 	0x35, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x8e, 0x5e,
-	0x00, 0x65, 0x8e, 0x5e,
+	0x00, 0x65, 0x92, 0x5e,
+	0x00, 0x65, 0x92, 0x5e,
 	0x02, 0x93, 0x26, 0x01,
-	0x04, 0x0b, 0xec, 0x6b,
-	0x10, 0x0c, 0xe8, 0x7b,
-	0x01, 0x03, 0xec, 0x6b,
-	0x20, 0x93, 0xe8, 0x6b,
+	0x04, 0x0b, 0xf0, 0x6b,
+	0x10, 0x0c, 0xec, 0x7b,
+	0x01, 0x03, 0xf0, 0x6b,
+	0x20, 0x93, 0xec, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
-	0x38, 0x93, 0xf2, 0x6b,
+	0x38, 0x93, 0xf6, 0x6b,
 	0x10, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0xc0, 0x41,
-	0x80, 0x3c, 0xfc, 0x6b,
-	0x21, 0x6a, 0xca, 0x46,
+	0x00, 0x65, 0xc4, 0x41,
+	0x80, 0x3c, 0x00, 0x6c,
+	0x21, 0x6a, 0xce, 0x46,
 	0x01, 0x06, 0x50, 0x31,
-	0x00, 0x65, 0xc0, 0x41,
+	0x00, 0x65, 0xc4, 0x41,
 	0x10, 0x3f, 0x06, 0x00,
 	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x3a, 0xca, 0x30,
-	0x80, 0x65, 0x20, 0x64,
-	0x10, 0xb8, 0x44, 0x6c,
+	0x80, 0x65, 0x24, 0x64,
+	0x10, 0xb8, 0x48, 0x6c,
 	0xc0, 0xba, 0xca, 0x00,
-	0x40, 0xb8, 0x10, 0x6c,
+	0x40, 0xb8, 0x14, 0x6c,
 	0xbf, 0x65, 0xca, 0x08,
-	0x20, 0xb8, 0x24, 0x7c,
+	0x20, 0xb8, 0x28, 0x7c,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xca, 0x5d,
-	0xa0, 0x3f, 0x2c, 0x64,
+	0x00, 0x65, 0xce, 0x5d,
+	0xa0, 0x3f, 0x30, 0x64,
 	0x23, 0xb8, 0x0c, 0x08,
-	0x00, 0x65, 0xca, 0x5d,
-	0xa0, 0x3f, 0x2c, 0x64,
-	0x00, 0xbb, 0x24, 0x44,
-	0xff, 0x65, 0x24, 0x64,
-	0x00, 0x65, 0x44, 0x44,
+	0x00, 0x65, 0xce, 0x5d,
+	0xa0, 0x3f, 0x30, 0x64,
+	0x00, 0xbb, 0x28, 0x44,
+	0xff, 0x65, 0x28, 0x64,
+	0x00, 0x65, 0x48, 0x44,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xca, 0x5d,
-	0xa0, 0x3f, 0x00, 0x74,
+	0x00, 0x65, 0xce, 0x5d,
+	0xa0, 0x3f, 0x04, 0x74,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x3a, 0xa6, 0x30,
 	0x08, 0x6a, 0x74, 0x00,
-	0x00, 0x65, 0xc0, 0x41,
-	0x64, 0x6a, 0x5a, 0x5d,
-	0x80, 0x64, 0xca, 0x6c,
-	0x04, 0x64, 0x90, 0x74,
-	0x02, 0x64, 0x9e, 0x74,
-	0x00, 0x6a, 0x60, 0x74,
-	0x03, 0x64, 0xbc, 0x74,
-	0x23, 0x64, 0x4c, 0x74,
-	0x08, 0x64, 0x5c, 0x74,
-	0x61, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0xca, 0x5d,
-	0x08, 0x51, 0xc2, 0x71,
-	0x00, 0x65, 0x44, 0x44,
-	0x80, 0x04, 0x5a, 0x7c,
-	0x51, 0x6a, 0x50, 0x5d,
-	0x01, 0x51, 0x5a, 0x64,
-	0x01, 0xa4, 0x56, 0x7c,
-	0x01, 0x55, 0x5c, 0x7c,
-	0x41, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0x5c, 0x44,
-	0x07, 0x6a, 0x46, 0x5d,
+	0x00, 0x65, 0xc4, 0x41,
+	0x64, 0x6a, 0x5e, 0x5d,
+	0x80, 0x64, 0xce, 0x6c,
+	0x04, 0x64, 0x94, 0x74,
+	0x02, 0x64, 0xa2, 0x74,
+	0x00, 0x6a, 0x64, 0x74,
+	0x03, 0x64, 0xc0, 0x74,
+	0x23, 0x64, 0x50, 0x74,
+	0x08, 0x64, 0x60, 0x74,
+	0x61, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0xce, 0x5d,
+	0x08, 0x51, 0xc6, 0x71,
+	0x00, 0x65, 0x48, 0x44,
+	0x80, 0x04, 0x5e, 0x7c,
+	0x51, 0x6a, 0x54, 0x5d,
+	0x01, 0x51, 0x5e, 0x64,
+	0x01, 0xa4, 0x5a, 0x7c,
+	0x01, 0x55, 0x60, 0x7c,
+	0x41, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0x60, 0x44,
+	0x07, 0x6a, 0x4a, 0x5d,
 	0x01, 0x06, 0xd4, 0x30,
-	0x00, 0x65, 0xc0, 0x41,
-	0x10, 0xb8, 0x64, 0x7c,
-	0xa1, 0x6a, 0xca, 0x5e,
-	0x01, 0xb4, 0x6a, 0x6c,
-	0x02, 0xb4, 0x6c, 0x6c,
-	0x01, 0xa4, 0x6c, 0x7c,
-	0xff, 0xa8, 0x7c, 0x7c,
+	0x00, 0x65, 0xc4, 0x41,
+	0x10, 0xb8, 0x68, 0x7c,
+	0xa1, 0x6a, 0xce, 0x5e,
+	0x01, 0xb4, 0x6e, 0x6c,
+	0x02, 0xb4, 0x70, 0x6c,
+	0x01, 0xa4, 0x70, 0x7c,
+	0xff, 0xa8, 0x80, 0x7c,
 	0x04, 0xb4, 0x68, 0x01,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0x04, 0x5e,
-	0xff, 0xa8, 0x7c, 0x7c,
-	0x71, 0x6a, 0xca, 0x5e,
-	0x40, 0x51, 0x7c, 0x64,
-	0x00, 0x65, 0xa4, 0x5e,
-	0x00, 0x65, 0xd2, 0x41,
-	0x00, 0xbb, 0x80, 0x5c,
-	0x00, 0x65, 0xd2, 0x41,
-	0x00, 0x65, 0xa4, 0x5e,
+	0x00, 0xbb, 0x08, 0x5e,
+	0xff, 0xa8, 0x80, 0x7c,
+	0x71, 0x6a, 0xce, 0x5e,
+	0x40, 0x51, 0x80, 0x64,
+	0x00, 0x65, 0xa8, 0x5e,
+	0x00, 0x65, 0xd6, 0x41,
+	0x00, 0xbb, 0x84, 0x5c,
+	0x00, 0x65, 0xd6, 0x41,
+	0x00, 0x65, 0xa8, 0x5e,
 	0x01, 0x65, 0xa2, 0x30,
 	0x01, 0xf8, 0xc8, 0x30,
 	0x01, 0x4e, 0xc8, 0x30,
-	0x00, 0x6a, 0xa8, 0xdd,
-	0x00, 0x51, 0xba, 0x5d,
+	0x00, 0x6a, 0xac, 0xdd,
+	0x00, 0x51, 0xbe, 0x5d,
 	0x01, 0x4e, 0x9c, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
 	0x04, 0xb8, 0x70, 0x01,
-	0x00, 0x65, 0xc6, 0x5e,
-	0x20, 0xb8, 0xd2, 0x69,
+	0x00, 0x65, 0xca, 0x5e,
+	0x20, 0xb8, 0xd6, 0x69,
 	0x01, 0xbb, 0xa2, 0x30,
 	0x01, 0xba, 0x7c, 0x30,
-	0x00, 0xb9, 0xc0, 0x5c,
-	0x00, 0x65, 0xd2, 0x41,
+	0x00, 0xb9, 0xc4, 0x5c,
+	0x00, 0x65, 0xd6, 0x41,
 	0x01, 0x06, 0xd4, 0x30,
-	0x20, 0x3c, 0xc0, 0x79,
-	0x20, 0x3c, 0x5c, 0x7c,
-	0x01, 0xa4, 0xac, 0x7c,
+	0x20, 0x3c, 0xc4, 0x79,
+	0x20, 0x3c, 0x60, 0x7c,
+	0x01, 0xa4, 0xb0, 0x7c,
 	0x01, 0xb4, 0x68, 0x01,
-	0x00, 0x65, 0xc0, 0x41,
-	0x00, 0x65, 0x5c, 0x44,
+	0x00, 0x65, 0xc4, 0x41,
+	0x00, 0x65, 0x60, 0x44,
 	0x04, 0x14, 0x58, 0x31,
 	0x01, 0x06, 0xd4, 0x30,
 	0x08, 0xa0, 0x60, 0x31,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xe6, 0x5d,
+	0x14, 0x6a, 0xea, 0x5d,
 	0x01, 0x06, 0xd4, 0x30,
-	0xa0, 0x6a, 0xde, 0x5d,
-	0x00, 0x65, 0xc0, 0x41,
+	0xa0, 0x6a, 0xe2, 0x5d,
+	0x00, 0x65, 0xc4, 0x41,
 	0xdf, 0x3c, 0x78, 0x08,
-	0x00, 0x65, 0x5c, 0x44,
+	0x00, 0x65, 0x60, 0x44,
 	0x4c, 0x65, 0xcc, 0x28,
 	0x01, 0x3e, 0x20, 0x31,
 	0xd0, 0x66, 0xcc, 0x18,
@@ -624,102 +626,102 @@
 	0xd0, 0x65, 0xca, 0x18,
 	0x01, 0x3e, 0x20, 0x31,
 	0x30, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xd8, 0x4c,
+	0x00, 0x65, 0xdc, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xe0, 0x54,
+	0x00, 0x65, 0xe4, 0x54,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xca, 0x18,
 	0xe0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xea, 0x4c,
+	0x00, 0x65, 0xee, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xd0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xf2, 0x54,
+	0x00, 0x65, 0xf6, 0x54,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x01, 0x6c, 0xa2, 0x30,
-	0xff, 0x51, 0x04, 0x75,
-	0x00, 0x51, 0x80, 0x5d,
+	0xff, 0x51, 0x08, 0x75,
+	0x00, 0x51, 0x84, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
-	0x00, 0x65, 0x26, 0x45,
+	0x00, 0x65, 0x2a, 0x45,
 	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0x26, 0x75,
-	0x00, 0x65, 0xa2, 0x5e,
+	0x00, 0x3e, 0x2a, 0x75,
+	0x00, 0x65, 0xa6, 0x5e,
 	0x80, 0x3c, 0x78, 0x00,
 	0x01, 0x06, 0xd4, 0x30,
-	0x00, 0x65, 0xca, 0x5d,
+	0x00, 0x65, 0xce, 0x5d,
 	0x01, 0x3c, 0x78, 0x00,
-	0xe0, 0x3f, 0x42, 0x65,
+	0xe0, 0x3f, 0x46, 0x65,
 	0x02, 0x3c, 0x78, 0x00,
-	0x20, 0x12, 0x42, 0x65,
-	0x51, 0x6a, 0x50, 0x5d,
-	0x00, 0x51, 0x80, 0x5d,
-	0x51, 0x6a, 0x50, 0x5d,
+	0x20, 0x12, 0x46, 0x65,
+	0x51, 0x6a, 0x54, 0x5d,
+	0x00, 0x51, 0x84, 0x5d,
+	0x51, 0x6a, 0x54, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
 	0x04, 0x3c, 0x78, 0x00,
 	0x01, 0xb9, 0xc8, 0x30,
-	0x00, 0x3d, 0x40, 0x65,
+	0x00, 0x3d, 0x44, 0x65,
 	0x08, 0x3c, 0x78, 0x00,
 	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0x40, 0x65,
+	0x00, 0x3e, 0x44, 0x65,
 	0x10, 0x3c, 0x78, 0x00,
-	0x04, 0xb8, 0x40, 0x7d,
+	0x04, 0xb8, 0x44, 0x7d,
 	0xfb, 0xb8, 0x70, 0x09,
-	0x20, 0xb8, 0x36, 0x6d,
+	0x20, 0xb8, 0x3a, 0x6d,
 	0x01, 0x90, 0xc8, 0x30,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3d, 0xc0, 0x5c,
+	0x00, 0x3d, 0xc4, 0x5c,
 	0x01, 0x64, 0x20, 0x31,
 	0x80, 0x6a, 0x78, 0x00,
 	0x00, 0x65, 0xec, 0x58,
-	0x10, 0xb8, 0x5c, 0x7c,
-	0xff, 0x6a, 0x46, 0x5d,
-	0x00, 0x65, 0x5c, 0x44,
-	0x00, 0x65, 0xa2, 0x5e,
-	0x31, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0x5c, 0x44,
+	0x10, 0xb8, 0x60, 0x7c,
+	0xff, 0x6a, 0x4a, 0x5d,
+	0x00, 0x65, 0x60, 0x44,
+	0x00, 0x65, 0xa6, 0x5e,
+	0x31, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0x60, 0x44,
 	0x10, 0x3f, 0x06, 0x00,
 	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x65, 0x74, 0x34,
-	0x81, 0x6a, 0xca, 0x5e,
-	0x00, 0x65, 0x52, 0x45,
+	0x81, 0x6a, 0xce, 0x5e,
+	0x00, 0x65, 0x56, 0x45,
 	0x01, 0x06, 0xd4, 0x30,
-	0x01, 0x0c, 0x52, 0x7d,
-	0x04, 0x0c, 0x4c, 0x6d,
+	0x01, 0x0c, 0x56, 0x7d,
+	0x04, 0x0c, 0x50, 0x6d,
 	0xe0, 0x03, 0x7e, 0x08,
-	0xe0, 0x3f, 0xc0, 0x61,
+	0xe0, 0x3f, 0xc4, 0x61,
 	0x01, 0x65, 0xcc, 0x30,
 	0x01, 0x12, 0xda, 0x34,
 	0x01, 0x06, 0xd4, 0x34,
-	0x01, 0x03, 0x60, 0x6d,
+	0x01, 0x03, 0x64, 0x6d,
 	0x40, 0x03, 0xcc, 0x08,
 	0x01, 0x65, 0x06, 0x30,
 	0x40, 0x65, 0xc8, 0x08,
-	0x00, 0x66, 0x6e, 0x75,
-	0x40, 0x65, 0x6e, 0x7d,
-	0x00, 0x65, 0x6e, 0x5d,
+	0x00, 0x66, 0x72, 0x75,
+	0x40, 0x65, 0x72, 0x7d,
+	0x00, 0x65, 0x72, 0x5d,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x78, 0x7d,
-	0x01, 0x65, 0x0c, 0x30,
 	0x02, 0x0b, 0x7c, 0x7d,
+	0x01, 0x65, 0x0c, 0x30,
+	0x02, 0x0b, 0x80, 0x7d,
 	0xf7, 0x01, 0x02, 0x0c,
 	0x01, 0x65, 0xc8, 0x30,
-	0xff, 0x41, 0xa0, 0x75,
+	0xff, 0x41, 0xa4, 0x75,
 	0x01, 0x41, 0x20, 0x31,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x90, 0x45,
-	0xff, 0xbf, 0xa0, 0x75,
+	0x00, 0x65, 0x94, 0x45,
+	0xff, 0xbf, 0xa4, 0x75,
 	0x01, 0x90, 0xa4, 0x30,
 	0x01, 0xbf, 0x20, 0x31,
-	0x00, 0xbb, 0x8a, 0x65,
-	0xff, 0x52, 0x9e, 0x75,
+	0x00, 0xbb, 0x8e, 0x65,
+	0xff, 0x52, 0xa2, 0x75,
 	0x01, 0xbf, 0xcc, 0x30,
 	0x01, 0x90, 0xca, 0x30,
 	0x01, 0x52, 0x20, 0x31,
@@ -727,28 +729,28 @@
 	0x01, 0x65, 0x20, 0x35,
 	0x01, 0xbf, 0x82, 0x34,
 	0x01, 0x64, 0xa2, 0x30,
-	0x00, 0x6a, 0xb2, 0x5e,
+	0x00, 0x6a, 0xb6, 0x5e,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0x04, 0x46,
+	0x00, 0x51, 0x08, 0x46,
 	0x01, 0x65, 0xa4, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xf8, 0x5d,
+	0x48, 0x6a, 0xfc, 0x5d,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xf8, 0x5d,
-	0x01, 0x6a, 0xd2, 0x5d,
+	0x48, 0x6a, 0xfc, 0x5d,
+	0x01, 0x6a, 0xd6, 0x5d,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xbe, 0x7d,
+	0x80, 0xee, 0xc2, 0x7d,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0x01, 0x65, 0x32, 0x31,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x9a, 0x46,
-	0x81, 0x6a, 0xca, 0x5e,
-	0x01, 0x0c, 0xca, 0x7d,
-	0x04, 0x0c, 0xc8, 0x6d,
+	0x00, 0x65, 0x9e, 0x46,
+	0x81, 0x6a, 0xce, 0x5e,
+	0x01, 0x0c, 0xce, 0x7d,
+	0x04, 0x0c, 0xcc, 0x6d,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7e, 0x0c,
 	0x01, 0x65, 0x18, 0x31,
@@ -767,7 +769,7 @@
 	0x01, 0x6c, 0xda, 0x34,
 	0x3d, 0x64, 0xa4, 0x28,
 	0x55, 0x64, 0xc8, 0x28,
-	0x00, 0x65, 0xf8, 0x45,
+	0x00, 0x65, 0xfc, 0x45,
 	0x2e, 0x64, 0xa4, 0x28,
 	0x66, 0x64, 0xc8, 0x28,
 	0x00, 0x6c, 0xda, 0x18,
@@ -778,63 +780,63 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0x01, 0x65, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0xf4, 0x5d,
+	0x44, 0x6a, 0xf8, 0x5d,
 	0x01, 0x90, 0xe2, 0x31,
-	0x04, 0x3b, 0x18, 0x7e,
+	0x04, 0x3b, 0x1c, 0x7e,
 	0x30, 0x6a, 0xd0, 0x01,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0x14, 0x66,
-	0x00, 0x65, 0x30, 0x46,
+	0xdc, 0xee, 0x18, 0x66,
+	0x00, 0x65, 0x34, 0x46,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x20, 0x7e,
+	0x80, 0xee, 0x24, 0x7e,
 	0x11, 0x6a, 0xdc, 0x01,
-	0x50, 0xee, 0x24, 0x66,
+	0x50, 0xee, 0x28, 0x66,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xdc, 0x01,
-	0x88, 0xee, 0x2a, 0x66,
+	0x88, 0xee, 0x2e, 0x66,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x2e, 0x66,
+	0xd8, 0xee, 0x32, 0x66,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x32, 0x6e,
+	0x18, 0xee, 0x36, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0xf4, 0x5d,
-	0x20, 0x6a, 0xd2, 0x5d,
+	0x44, 0x6a, 0xf8, 0x5d,
+	0x20, 0x6a, 0xd6, 0x5d,
 	0x01, 0x3b, 0x26, 0x31,
-	0x04, 0x3b, 0x4c, 0x6e,
+	0x04, 0x3b, 0x50, 0x6e,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0x8a, 0x5e,
-	0x00, 0x65, 0x44, 0x66,
+	0x00, 0x65, 0x8e, 0x5e,
+	0x00, 0x65, 0x48, 0x66,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x9a, 0x46,
+	0x00, 0x65, 0x9e, 0x46,
 	0xa0, 0x6a, 0xcc, 0x00,
 	0xff, 0x6a, 0xc8, 0x08,
-	0x20, 0x94, 0x50, 0x6e,
-	0x10, 0x94, 0x52, 0x6e,
-	0x08, 0x94, 0x6c, 0x6e,
-	0x08, 0x94, 0x6c, 0x6e,
-	0x08, 0x94, 0x6c, 0x6e,
+	0x20, 0x94, 0x54, 0x6e,
+	0x10, 0x94, 0x56, 0x6e,
+	0x08, 0x94, 0x70, 0x6e,
+	0x08, 0x94, 0x70, 0x6e,
+	0x08, 0x94, 0x70, 0x6e,
 	0xff, 0x8c, 0xc8, 0x10,
 	0xc1, 0x64, 0xc8, 0x18,
 	0xf8, 0x64, 0xc8, 0x08,
 	0x01, 0x99, 0xda, 0x30,
-	0x00, 0x66, 0x60, 0x66,
-	0xc0, 0x66, 0x9c, 0x76,
+	0x00, 0x66, 0x64, 0x66,
+	0xc0, 0x66, 0xa0, 0x76,
 	0x60, 0x66, 0xc8, 0x18,
 	0x3d, 0x64, 0xc8, 0x28,
-	0x00, 0x65, 0x50, 0x46,
+	0x00, 0x65, 0x54, 0x46,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x6e, 0x6e,
+	0x08, 0x93, 0x72, 0x6e,
 	0x00, 0x62, 0xc4, 0x18,
-	0x00, 0x65, 0x9a, 0x5e,
-	0x00, 0x65, 0x7a, 0x5e,
-	0x00, 0x65, 0x7a, 0x5e,
-	0x00, 0x65, 0x7a, 0x5e,
+	0x00, 0x65, 0x9e, 0x5e,
+	0x00, 0x65, 0x7e, 0x5e,
+	0x00, 0x65, 0x7e, 0x5e,
+	0x00, 0x65, 0x7e, 0x5e,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
@@ -851,11 +853,11 @@
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x35,
-	0x08, 0x94, 0x9a, 0x7e,
+	0x08, 0x94, 0x9e, 0x7e,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x9e, 0x6e,
+	0x08, 0x93, 0xa2, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x04, 0xb8, 0xc6, 0x6e,
+	0x04, 0xb8, 0xca, 0x6e,
 	0x01, 0x42, 0x7e, 0x31,
 	0xff, 0x6a, 0x76, 0x01,
 	0x01, 0x90, 0x84, 0x34,
@@ -863,14 +865,14 @@
 	0x01, 0x85, 0x0a, 0x01,
 	0x7f, 0x65, 0x10, 0x09,
 	0xfe, 0x85, 0x0a, 0x0d,
-	0xff, 0x42, 0xc2, 0x66,
-	0xff, 0x41, 0xba, 0x66,
-	0xd1, 0x6a, 0xca, 0x5e,
+	0xff, 0x42, 0xc6, 0x66,
+	0xff, 0x41, 0xbe, 0x66,
+	0xd1, 0x6a, 0xce, 0x5e,
 	0xff, 0x6a, 0xca, 0x04,
 	0x01, 0x41, 0x20, 0x31,
 	0x01, 0xbf, 0x82, 0x30,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0x04, 0x46,
+	0x00, 0xbb, 0x08, 0x46,
 	0x01, 0x42, 0x20, 0x31,
 	0x01, 0xbf, 0x84, 0x34,
 	0x01, 0x41, 0x7e, 0x31,
@@ -1124,164 +1126,164 @@
 	{ aic_patch1_func, 120, 1, 2 },
 	{ aic_patch0_func, 121, 1, 1 },
 	{ aic_patch7_func, 122, 4, 1 },
-	{ aic_patch7_func, 133, 89, 11 },
+	{ aic_patch7_func, 132, 91, 11 },
 	{ aic_patch4_func, 151, 1, 1 },
-	{ aic_patch1_func, 164, 1, 1 },
-	{ aic_patch12_func, 169, 1, 2 },
-	{ aic_patch0_func, 170, 1, 1 },
-	{ aic_patch9_func, 181, 1, 2 },
-	{ aic_patch0_func, 182, 1, 1 },
-	{ aic_patch9_func, 191, 1, 2 },
-	{ aic_patch0_func, 192, 1, 1 },
-	{ aic_patch9_func, 208, 6, 2 },
-	{ aic_patch0_func, 214, 6, 1 },
-	{ aic_patch8_func, 222, 18, 2 },
-	{ aic_patch1_func, 235, 1, 1 },
-	{ aic_patch1_func, 242, 1, 2 },
-	{ aic_patch0_func, 243, 2, 2 },
-	{ aic_patch11_func, 244, 1, 1 },
-	{ aic_patch9_func, 252, 31, 3 },
-	{ aic_patch1_func, 268, 14, 2 },
-	{ aic_patch13_func, 273, 1, 1 },
-	{ aic_patch14_func, 283, 14, 1 },
-	{ aic_patch1_func, 299, 1, 2 },
-	{ aic_patch0_func, 300, 1, 1 },
-	{ aic_patch9_func, 303, 1, 1 },
-	{ aic_patch13_func, 308, 1, 1 },
-	{ aic_patch9_func, 309, 2, 2 },
-	{ aic_patch0_func, 311, 4, 1 },
-	{ aic_patch14_func, 315, 1, 1 },
-	{ aic_patch15_func, 318, 2, 3 },
-	{ aic_patch9_func, 318, 1, 2 },
-	{ aic_patch0_func, 319, 1, 1 },
-	{ aic_patch6_func, 324, 1, 2 },
-	{ aic_patch0_func, 325, 1, 1 },
-	{ aic_patch1_func, 329, 50, 11 },
-	{ aic_patch6_func, 338, 2, 4 },
-	{ aic_patch7_func, 338, 1, 1 },
-	{ aic_patch8_func, 339, 1, 1 },
-	{ aic_patch0_func, 340, 1, 1 },
-	{ aic_patch16_func, 341, 1, 1 },
-	{ aic_patch6_func, 360, 6, 3 },
-	{ aic_patch16_func, 360, 5, 1 },
-	{ aic_patch0_func, 366, 5, 1 },
-	{ aic_patch13_func, 374, 5, 1 },
-	{ aic_patch0_func, 379, 54, 17 },
-	{ aic_patch14_func, 379, 1, 1 },
-	{ aic_patch7_func, 381, 2, 2 },
-	{ aic_patch17_func, 382, 1, 1 },
-	{ aic_patch9_func, 385, 1, 1 },
-	{ aic_patch18_func, 392, 1, 1 },
-	{ aic_patch14_func, 397, 9, 3 },
-	{ aic_patch9_func, 398, 3, 2 },
-	{ aic_patch0_func, 401, 3, 1 },
-	{ aic_patch9_func, 409, 6, 2 },
-	{ aic_patch0_func, 415, 9, 2 },
-	{ aic_patch13_func, 415, 1, 1 },
-	{ aic_patch13_func, 424, 2, 1 },
-	{ aic_patch14_func, 426, 1, 1 },
-	{ aic_patch9_func, 428, 1, 2 },
-	{ aic_patch0_func, 429, 1, 1 },
-	{ aic_patch7_func, 432, 1, 1 },
-	{ aic_patch7_func, 433, 1, 1 },
-	{ aic_patch8_func, 434, 3, 3 },
-	{ aic_patch6_func, 435, 1, 2 },
-	{ aic_patch0_func, 436, 1, 1 },
-	{ aic_patch9_func, 437, 1, 1 },
-	{ aic_patch15_func, 438, 1, 2 },
-	{ aic_patch13_func, 438, 1, 1 },
-	{ aic_patch14_func, 440, 9, 4 },
-	{ aic_patch9_func, 440, 1, 1 },
-	{ aic_patch9_func, 447, 2, 1 },
-	{ aic_patch0_func, 449, 4, 3 },
-	{ aic_patch9_func, 449, 1, 2 },
-	{ aic_patch0_func, 450, 3, 1 },
-	{ aic_patch1_func, 454, 2, 1 },
-	{ aic_patch7_func, 456, 10, 2 },
-	{ aic_patch0_func, 466, 1, 1 },
-	{ aic_patch8_func, 467, 109, 23 },
-	{ aic_patch1_func, 469, 3, 2 },
-	{ aic_patch0_func, 472, 5, 3 },
-	{ aic_patch9_func, 472, 2, 2 },
-	{ aic_patch0_func, 474, 3, 1 },
-	{ aic_patch1_func, 479, 2, 2 },
-	{ aic_patch0_func, 481, 6, 3 },
-	{ aic_patch9_func, 481, 2, 2 },
-	{ aic_patch0_func, 483, 3, 1 },
-	{ aic_patch1_func, 489, 2, 2 },
-	{ aic_patch0_func, 491, 9, 7 },
-	{ aic_patch9_func, 491, 5, 6 },
-	{ aic_patch19_func, 491, 1, 2 },
-	{ aic_patch0_func, 492, 1, 1 },
-	{ aic_patch19_func, 494, 1, 2 },
-	{ aic_patch0_func, 495, 1, 1 },
-	{ aic_patch0_func, 496, 4, 1 },
-	{ aic_patch6_func, 500, 3, 2 },
-	{ aic_patch0_func, 503, 1, 1 },
-	{ aic_patch1_func, 506, 1, 1 },
-	{ aic_patch6_func, 512, 1, 2 },
-	{ aic_patch0_func, 513, 1, 1 },
-	{ aic_patch20_func, 550, 7, 1 },
-	{ aic_patch3_func, 578, 1, 2 },
-	{ aic_patch0_func, 579, 1, 1 },
-	{ aic_patch21_func, 582, 1, 1 },
-	{ aic_patch8_func, 584, 104, 33 },
-	{ aic_patch4_func, 585, 1, 1 },
-	{ aic_patch1_func, 591, 2, 2 },
-	{ aic_patch0_func, 593, 1, 1 },
-	{ aic_patch1_func, 596, 1, 2 },
-	{ aic_patch0_func, 597, 1, 1 },
-	{ aic_patch9_func, 598, 3, 3 },
-	{ aic_patch15_func, 599, 1, 1 },
-	{ aic_patch0_func, 601, 4, 1 },
-	{ aic_patch19_func, 609, 2, 2 },
-	{ aic_patch0_func, 611, 1, 1 },
-	{ aic_patch19_func, 615, 10, 3 },
-	{ aic_patch5_func, 617, 8, 1 },
-	{ aic_patch0_func, 625, 9, 2 },
-	{ aic_patch5_func, 626, 8, 1 },
-	{ aic_patch4_func, 636, 1, 2 },
-	{ aic_patch0_func, 637, 1, 1 },
-	{ aic_patch19_func, 638, 1, 2 },
-	{ aic_patch0_func, 639, 3, 2 },
-	{ aic_patch4_func, 641, 1, 1 },
-	{ aic_patch5_func, 642, 1, 1 },
-	{ aic_patch5_func, 645, 1, 1 },
+	{ aic_patch1_func, 165, 1, 1 },
+	{ aic_patch12_func, 170, 1, 2 },
+	{ aic_patch0_func, 171, 1, 1 },
+	{ aic_patch9_func, 182, 1, 2 },
+	{ aic_patch0_func, 183, 1, 1 },
+	{ aic_patch9_func, 192, 1, 2 },
+	{ aic_patch0_func, 193, 1, 1 },
+	{ aic_patch9_func, 209, 6, 2 },
+	{ aic_patch0_func, 215, 6, 1 },
+	{ aic_patch8_func, 223, 19, 2 },
+	{ aic_patch1_func, 237, 1, 1 },
+	{ aic_patch1_func, 244, 1, 2 },
+	{ aic_patch0_func, 245, 2, 2 },
+	{ aic_patch11_func, 246, 1, 1 },
+	{ aic_patch9_func, 254, 31, 3 },
+	{ aic_patch1_func, 270, 14, 2 },
+	{ aic_patch13_func, 275, 1, 1 },
+	{ aic_patch14_func, 285, 14, 1 },
+	{ aic_patch1_func, 301, 1, 2 },
+	{ aic_patch0_func, 302, 1, 1 },
+	{ aic_patch9_func, 305, 1, 1 },
+	{ aic_patch13_func, 310, 1, 1 },
+	{ aic_patch9_func, 311, 2, 2 },
+	{ aic_patch0_func, 313, 4, 1 },
+	{ aic_patch14_func, 317, 1, 1 },
+	{ aic_patch15_func, 320, 2, 3 },
+	{ aic_patch9_func, 320, 1, 2 },
+	{ aic_patch0_func, 321, 1, 1 },
+	{ aic_patch6_func, 326, 1, 2 },
+	{ aic_patch0_func, 327, 1, 1 },
+	{ aic_patch1_func, 331, 50, 11 },
+	{ aic_patch6_func, 340, 2, 4 },
+	{ aic_patch7_func, 340, 1, 1 },
+	{ aic_patch8_func, 341, 1, 1 },
+	{ aic_patch0_func, 342, 1, 1 },
+	{ aic_patch16_func, 343, 1, 1 },
+	{ aic_patch6_func, 362, 6, 3 },
+	{ aic_patch16_func, 362, 5, 1 },
+	{ aic_patch0_func, 368, 5, 1 },
+	{ aic_patch13_func, 376, 5, 1 },
+	{ aic_patch0_func, 381, 54, 17 },
+	{ aic_patch14_func, 381, 1, 1 },
+	{ aic_patch7_func, 383, 2, 2 },
+	{ aic_patch17_func, 384, 1, 1 },
+	{ aic_patch9_func, 387, 1, 1 },
+	{ aic_patch18_func, 394, 1, 1 },
+	{ aic_patch14_func, 399, 9, 3 },
+	{ aic_patch9_func, 400, 3, 2 },
+	{ aic_patch0_func, 403, 3, 1 },
+	{ aic_patch9_func, 411, 6, 2 },
+	{ aic_patch0_func, 417, 9, 2 },
+	{ aic_patch13_func, 417, 1, 1 },
+	{ aic_patch13_func, 426, 2, 1 },
+	{ aic_patch14_func, 428, 1, 1 },
+	{ aic_patch9_func, 430, 1, 2 },
+	{ aic_patch0_func, 431, 1, 1 },
+	{ aic_patch7_func, 434, 1, 1 },
+	{ aic_patch7_func, 435, 1, 1 },
+	{ aic_patch8_func, 436, 3, 3 },
+	{ aic_patch6_func, 437, 1, 2 },
+	{ aic_patch0_func, 438, 1, 1 },
+	{ aic_patch9_func, 439, 1, 1 },
+	{ aic_patch15_func, 440, 1, 2 },
+	{ aic_patch13_func, 440, 1, 1 },
+	{ aic_patch14_func, 442, 9, 4 },
+	{ aic_patch9_func, 442, 1, 1 },
+	{ aic_patch9_func, 449, 2, 1 },
+	{ aic_patch0_func, 451, 4, 3 },
+	{ aic_patch9_func, 451, 1, 2 },
+	{ aic_patch0_func, 452, 3, 1 },
+	{ aic_patch1_func, 456, 2, 1 },
+	{ aic_patch7_func, 458, 10, 2 },
+	{ aic_patch0_func, 468, 1, 1 },
+	{ aic_patch8_func, 469, 109, 23 },
+	{ aic_patch1_func, 471, 3, 2 },
+	{ aic_patch0_func, 474, 5, 3 },
+	{ aic_patch9_func, 474, 2, 2 },
+	{ aic_patch0_func, 476, 3, 1 },
+	{ aic_patch1_func, 481, 2, 2 },
+	{ aic_patch0_func, 483, 6, 3 },
+	{ aic_patch9_func, 483, 2, 2 },
+	{ aic_patch0_func, 485, 3, 1 },
+	{ aic_patch1_func, 491, 2, 2 },
+	{ aic_patch0_func, 493, 9, 7 },
+	{ aic_patch9_func, 493, 5, 6 },
+	{ aic_patch19_func, 493, 1, 2 },
+	{ aic_patch0_func, 494, 1, 1 },
+	{ aic_patch19_func, 496, 1, 2 },
+	{ aic_patch0_func, 497, 1, 1 },
+	{ aic_patch0_func, 498, 4, 1 },
+	{ aic_patch6_func, 502, 3, 2 },
+	{ aic_patch0_func, 505, 1, 1 },
+	{ aic_patch1_func, 508, 1, 1 },
+	{ aic_patch6_func, 514, 1, 2 },
+	{ aic_patch0_func, 515, 1, 1 },
+	{ aic_patch20_func, 552, 7, 1 },
+	{ aic_patch3_func, 580, 1, 2 },
+	{ aic_patch0_func, 581, 1, 1 },
+	{ aic_patch21_func, 584, 1, 1 },
+	{ aic_patch8_func, 586, 104, 33 },
+	{ aic_patch4_func, 587, 1, 1 },
+	{ aic_patch1_func, 593, 2, 2 },
+	{ aic_patch0_func, 595, 1, 1 },
+	{ aic_patch1_func, 598, 1, 2 },
+	{ aic_patch0_func, 599, 1, 1 },
+	{ aic_patch9_func, 600, 3, 3 },
+	{ aic_patch15_func, 601, 1, 1 },
+	{ aic_patch0_func, 603, 4, 1 },
+	{ aic_patch19_func, 611, 2, 2 },
+	{ aic_patch0_func, 613, 1, 1 },
+	{ aic_patch19_func, 617, 10, 3 },
+	{ aic_patch5_func, 619, 8, 1 },
+	{ aic_patch0_func, 627, 9, 2 },
+	{ aic_patch5_func, 628, 8, 1 },
+	{ aic_patch4_func, 638, 1, 2 },
+	{ aic_patch0_func, 639, 1, 1 },
+	{ aic_patch19_func, 640, 1, 2 },
+	{ aic_patch0_func, 641, 3, 2 },
+	{ aic_patch4_func, 643, 1, 1 },
+	{ aic_patch5_func, 644, 1, 1 },
 	{ aic_patch5_func, 647, 1, 1 },
-	{ aic_patch4_func, 649, 2, 2 },
-	{ aic_patch0_func, 651, 2, 1 },
-	{ aic_patch5_func, 653, 1, 1 },
-	{ aic_patch5_func, 656, 1, 1 },
-	{ aic_patch5_func, 659, 1, 1 },
-	{ aic_patch19_func, 663, 1, 1 },
-	{ aic_patch19_func, 666, 1, 1 },
-	{ aic_patch4_func, 672, 1, 1 },
-	{ aic_patch6_func, 675, 1, 2 },
-	{ aic_patch0_func, 676, 1, 1 },
-	{ aic_patch7_func, 688, 16, 1 },
-	{ aic_patch4_func, 704, 20, 1 },
-	{ aic_patch9_func, 725, 4, 2 },
-	{ aic_patch0_func, 729, 4, 1 },
-	{ aic_patch9_func, 733, 4, 2 },
-	{ aic_patch0_func, 737, 3, 1 },
-	{ aic_patch6_func, 743, 1, 1 },
-	{ aic_patch22_func, 745, 14, 1 },
-	{ aic_patch7_func, 759, 3, 1 },
-	{ aic_patch9_func, 771, 24, 8 },
-	{ aic_patch19_func, 775, 1, 2 },
-	{ aic_patch0_func, 776, 1, 1 },
-	{ aic_patch15_func, 781, 4, 2 },
-	{ aic_patch0_func, 785, 7, 3 },
-	{ aic_patch23_func, 785, 5, 2 },
-	{ aic_patch0_func, 790, 2, 1 },
-	{ aic_patch0_func, 795, 42, 3 },
-	{ aic_patch18_func, 807, 18, 2 },
-	{ aic_patch0_func, 825, 1, 1 },
-	{ aic_patch4_func, 849, 1, 1 },
-	{ aic_patch4_func, 850, 3, 2 },
-	{ aic_patch0_func, 853, 1, 1 },
-	{ aic_patch13_func, 854, 3, 1 },
-	{ aic_patch4_func, 857, 12, 1 }
+	{ aic_patch5_func, 649, 1, 1 },
+	{ aic_patch4_func, 651, 2, 2 },
+	{ aic_patch0_func, 653, 2, 1 },
+	{ aic_patch5_func, 655, 1, 1 },
+	{ aic_patch5_func, 658, 1, 1 },
+	{ aic_patch5_func, 661, 1, 1 },
+	{ aic_patch19_func, 665, 1, 1 },
+	{ aic_patch19_func, 668, 1, 1 },
+	{ aic_patch4_func, 674, 1, 1 },
+	{ aic_patch6_func, 677, 1, 2 },
+	{ aic_patch0_func, 678, 1, 1 },
+	{ aic_patch7_func, 690, 16, 1 },
+	{ aic_patch4_func, 706, 20, 1 },
+	{ aic_patch9_func, 727, 4, 2 },
+	{ aic_patch0_func, 731, 4, 1 },
+	{ aic_patch9_func, 735, 4, 2 },
+	{ aic_patch0_func, 739, 3, 1 },
+	{ aic_patch6_func, 745, 1, 1 },
+	{ aic_patch22_func, 747, 14, 1 },
+	{ aic_patch7_func, 761, 3, 1 },
+	{ aic_patch9_func, 773, 24, 8 },
+	{ aic_patch19_func, 777, 1, 2 },
+	{ aic_patch0_func, 778, 1, 1 },
+	{ aic_patch15_func, 783, 4, 2 },
+	{ aic_patch0_func, 787, 7, 3 },
+	{ aic_patch23_func, 787, 5, 2 },
+	{ aic_patch0_func, 792, 2, 1 },
+	{ aic_patch0_func, 797, 42, 3 },
+	{ aic_patch18_func, 809, 18, 2 },
+	{ aic_patch0_func, 827, 1, 1 },
+	{ aic_patch4_func, 851, 1, 1 },
+	{ aic_patch4_func, 852, 3, 2 },
+	{ aic_patch0_func, 855, 1, 1 },
+	{ aic_patch13_func, 856, 3, 1 },
+	{ aic_patch4_func, 859, 12, 1 }
 };
 static struct cs {
 	u_int16_t	begin;
@@ -1289,11 +1291,11 @@
 } critical_sections[] = {
 	{ 11, 18 },
 	{ 21, 30 },
-	{ 704, 720 },
-	{ 850, 853 },
-	{ 857, 863 },
-	{ 865, 867 },
-	{ 867, 869 }
+	{ 706, 722 },
+	{ 852, 855 },
+	{ 859, 865 },
+	{ 867, 869 },
+	{ 869, 871 }
 };
 static const int num_critical_sections = sizeof(critical_sections)
 				       / sizeof(*critical_sections);
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm.c	Tue May 28 16:02:29 2002
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#15 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.29 2000/10/05 04:25:42 gibbs Exp $
  */
@@ -397,9 +397,9 @@
 			skip_patch :12;
 } patches[] = {\n", patch_arg_list);
 
-	for(cur_patch = STAILQ_FIRST(&patches);
-	    cur_patch != NULL;
-	    cur_patch = STAILQ_NEXT(cur_patch,links)) {
+	for (cur_patch = STAILQ_FIRST(&patches);
+	     cur_patch != NULL;
+	     cur_patch = STAILQ_NEXT(cur_patch,links)) {
 		fprintf(ofile, "%s\t{ aic_patch%d_func, %d, %d, %d }",
 			cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n",
 			cur_patch->patch_func, cur_patch->begin,
@@ -414,9 +414,9 @@
 	u_int16_t	end;
 } critical_sections[] = {\n");
 
-	for(cs = TAILQ_FIRST(&cs_tailq);
-	    cs != NULL;
-	    cs = TAILQ_NEXT(cs, links)) {
+	for (cs = TAILQ_FIRST(&cs_tailq);
+	     cs != NULL;
+	     cs = TAILQ_NEXT(cs, links)) {
 		fprintf(ofile, "%s\t{ %d, %d }",
 			cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n",
 			cs->begin_addr, cs->end_addr);
@@ -569,9 +569,9 @@
 
 	/* Now output the listing */
 	cur_patch = STAILQ_FIRST(&patches);
-	for(cur_instr = STAILQ_FIRST(&seq_program);
-	    cur_instr != NULL;
-	    cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
+	for (cur_instr = STAILQ_FIRST(&seq_program);
+	     cur_instr != NULL;
+	     cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
 
 		if (check_patch(&cur_patch, instrcount,
 				&skip_addr, func_values) == 0) {
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm.h	Tue May 28 16:02:29 2002
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#9 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11 2000/09/22 22:19:54 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y	Tue May 28 16:02:29 2002
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#14 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_gram.y,v 1.12 2000/10/31 18:44:32 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h	Tue May 28 16:02:29 2002
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#8 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3 2000/09/22 22:19:54 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l	Tue May 28 16:02:29 2002
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#10 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13.2.3 2001/07/28 18:46:44 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Tue May 28 16:02:29 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#13 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h	Tue May 28 16:02:29 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#10 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11 2000/09/22 22:19:55 gibbs Exp $
  */
diff -urN linux-2.4.19-pre8/drivers/scsi/aic7xxx/cam.h linux-2.4.19-pre9/drivers/scsi/aic7xxx/cam.h
--- linux-2.4.19-pre8/drivers/scsi/aic7xxx/cam.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/aic7xxx/cam.h	Thu Oct 25 13:53:49 2001
@@ -29,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id$
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/cam.h#11 $
  */
 
 #ifndef _AIC7XXX_CAM_H
diff -urN linux-2.4.19-pre8/drivers/scsi/ips.c linux-2.4.19-pre9/drivers/scsi/ips.c
--- linux-2.4.19-pre8/drivers/scsi/ips.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/ips.c	Tue May 28 16:02:29 2002
@@ -543,6 +543,7 @@
    }
 
    return (1);
+}
 
 __setup("ips=", ips_setup);
 
@@ -579,10 +580,10 @@
          }
       }
    }
+}
 
 #endif
 
-}
 
 /****************************************************************************/
 /*                                                                          */
diff -urN linux-2.4.19-pre8/drivers/scsi/mesh.c linux-2.4.19-pre9/drivers/scsi/mesh.c
--- linux-2.4.19-pre8/drivers/scsi/mesh.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre9/drivers/scsi/mesh.c	Tue May 28 16:02:29 2002
@@ -6,8 +6,16 @@
  *
  * Paul Mackerras, August 1996.
  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Apr. 14 2002  - BenH		Rework bus reset code for new error handler
+ *                              Add delay after initial bus reset
+ *                              Add module parameters
+ * To do:
+ * - handle aborts correctly
+ * - retry arbitration if lost (unless higher levels do this for us)
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/types.h>
@@ -20,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -30,6 +39,7 @@
 #include <asm/processor.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
 #ifdef CONFIG_PMAC_PBOOK
 #include <linux/adb.h>
 #include <linux/pmu.h>
@@ -39,35 +49,39 @@
 #include "hosts.h"
 #include "mesh.h"
 
-/*
- * To do:
- * - handle aborts correctly
- * - retry arbitration if lost (unless higher levels do this for us)
- */
-
-#define MESH_NEW_STYLE_EH
-
 #if 1
 #undef KERN_DEBUG
 #define KERN_DEBUG KERN_WARNING
 #endif
 
-#if CONFIG_SCSI_MESH_SYNC_RATE == 0
-int mesh_sync_period = 100;
-int mesh_sync_offset = 0;
-#else
-int mesh_sync_period = 1000 / CONFIG_SCSI_MESH_SYNC_RATE;	/* ns */
-int mesh_sync_offset = 15;
-#endif
-
-int mesh_sync_targets = 0xff;	/* targets to set synchronous (bitmap) */
-int mesh_resel_targets = 0xff;	/* targets that we let disconnect (bitmap) */
-int mesh_debug_targets = 0;	/* print debug for these targets */
-unsigned char use_active_neg = 0;  /* bit mask for SEQ_ACTIVE_NEG if used */
-
-#define ALLOW_SYNC(tgt)		((mesh_sync_targets >> (tgt)) & 1)
-#define ALLOW_RESEL(tgt)	((mesh_resel_targets >> (tgt)) & 1)
-#define ALLOW_DEBUG(tgt)	((mesh_debug_targets >> (tgt)) & 1)
+MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)");
+MODULE_DESCRIPTION("PowerMac MESH SCSI driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(sync_rate, "i");
+MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
+MODULE_PARM(sync_targets, "i");
+MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
+MODULE_PARM(resel_targets, "i");
+MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
+MODULE_PARM(debug_targets, "i");
+MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
+MODULE_PARM(init_reset_delay, "i");
+MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
+
+static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE;
+static int sync_targets = 0xff;
+static int resel_targets = 0xff;
+static int debug_targets = 0;	/* print debug for these targets */
+static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS;
+
+static int mesh_sync_period = 100;
+static int mesh_sync_offset = 0;
+static unsigned char use_active_neg = 0;  /* bit mask for SEQ_ACTIVE_NEG if used */
+
+#define ALLOW_SYNC(tgt)		((sync_targets >> (tgt)) & 1)
+#define ALLOW_RESEL(tgt)	((resel_targets >> (tgt)) & 1)
+#define ALLOW_DEBUG(tgt)	((debug_targets >> (tgt)) & 1)
 #define DEBUG_TARGET(cmd)	((cmd) && ALLOW_DEBUG((cmd)->target))
 
 #undef MESH_DBG
@@ -95,7 +109,8 @@
 	statusing,
 	busfreeing,
 	disconnecting,
-	reselecting
+	reselecting,
+	sleeping
 };
 
 enum msg_phase {
@@ -119,7 +134,6 @@
 	int	data_goes_out;		/* guess as to data direction */
 	Scsi_Cmnd *current_req;
 	u32	saved_ptr;
-	int	want_abort;
 #ifdef MESH_DBG
 	int	log_ix;
 	int	n_log;
@@ -156,11 +170,7 @@
 	struct mesh_target tgts[8];
 	void	*dma_cmd_space;
 	struct device_node *ofnode;
-#ifndef MESH_NEW_STYLE_EH
-	Scsi_Cmnd *completed_q;
-	Scsi_Cmnd *completed_qtail;
-	struct tq_struct tqueue;
-#endif
+	struct pci_dev* pdev;
 #ifdef MESH_DBG
 	int	log_ix;
 	int	n_log;
@@ -192,9 +202,6 @@
 static void mesh_dump_regs(struct mesh_state *);
 static void mesh_start(struct mesh_state *);
 static void mesh_start_cmd(struct mesh_state *, Scsi_Cmnd *);
-#ifndef MESH_NEW_STYLE_EH
-static void finish_cmds(void *);
-#endif
 static void add_sdtr_msg(struct mesh_state *);
 static void set_sdtr(struct mesh_state *, int, int);
 static void start_phase(struct mesh_state *);
@@ -240,6 +247,12 @@
 	struct Scsi_Host *mesh_host;
 	void *dma_cmd_space;
 
+	/* The SCSI layer is dumb ! It calls us with the IO request
+	 * lock held and interrupts disabled here... This doesn't happen
+	 * in 2.5
+	 */
+	spin_unlock_irq(&io_request_lock);
+	
 	if (_machine == _MACH_Pmac) {
 	    use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG);
 	} else {
@@ -247,6 +260,16 @@
 	    use_active_neg = SEQ_ACTIVE_NEG;
 	}
 
+	/* Calculate sync rate from module parameters */
+	if (sync_rate > 10)
+		sync_rate = 10;
+	if (sync_rate > 0) {
+		printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);
+		mesh_sync_period = 1000 / sync_rate;	/* ns */
+		mesh_sync_offset = 15;
+	} else
+		printk(KERN_INFO "mesh: configured for asynchronous\n");
+
 	nmeshes = 0;
 	prev_statep = &all_meshes;
 	/*
@@ -258,11 +281,23 @@
 	if (mesh == 0)
 		mesh = find_compatible_devices("scsi", "chrp,mesh0");
 	for (; mesh != 0; mesh = mesh->next) {
+		u8 pci_bus, pci_devfn;
+		struct pci_dev* pdev = NULL;
+		
 		if (mesh->n_addrs != 2 || mesh->n_intrs != 2) {
 			printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
-			       " (got %d,%d)", mesh->n_addrs, mesh->n_intrs);
+			       " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+			continue;
+		}
+		if (mesh->parent != NULL
+		    && pci_device_from_OF_node(mesh->parent, &pci_bus,
+					       &pci_devfn) == 0)
+			pdev = pci_find_slot(pci_bus, pci_devfn);
+		if (pdev == NULL) {
+			printk(KERN_ERR "mesh: Can't locate PCI entry\n");
 			continue;
 		}
+
 		mesh_host = scsi_register(tp, sizeof(struct mesh_state));
 		if (mesh_host == 0) {
 			printk(KERN_ERR "mesh: couldn't register host");
@@ -279,6 +314,7 @@
 		memset(ms, 0, sizeof(*ms));
 		ms->host = mesh_host;
 		ms->ofnode = mesh;
+		ms->pdev = pdev;
 		ms->mesh = (volatile struct mesh_regs *)
 			ioremap(mesh->addrs[0].address, 0x1000);
 		ms->dma = (volatile struct dbdma_regs *)
@@ -303,10 +339,6 @@
 			ms->tgts[tgt].sync_params = ASYNC_PARAMS;
 			ms->tgts[tgt].current_req = 0;
 		}
-#ifndef MESH_NEW_STYLE_EH
-		ms->tqueue.routine = finish_cmds;
-		ms->tqueue.data = ms;
-#endif
 		*prev_statep = ms;
 		prev_statep = &ms->next;
 
@@ -341,6 +373,9 @@
 		register_reboot_notifier(&mesh_notifier);
 	}
 
+	/* Return to the SCSI layer in the same state we got called */
+	spin_lock_irq(&io_request_lock);
+
 	return nmeshes;
 }
 
@@ -395,15 +430,33 @@
 		
 	case PBOOK_SLEEP_NOW:
 		for (ms = all_meshes; ms != 0; ms = ms->next) {
+			unsigned long flags;
+
+			scsi_block_requests(ms->host);
+			spin_lock_irqsave(&io_request_lock, flags);
+			while(ms->phase != idle) {
+				spin_unlock_irqrestore(&io_request_lock, flags);
+				current->state = TASK_UNINTERRUPTIBLE;
+				schedule_timeout(1);
+				spin_lock_irqsave(&io_request_lock, flags);
+			}
+			ms->phase = sleeping;
+			spin_unlock_irqrestore(&io_request_lock, flags);
 			disable_irq(ms->meshintr);
 			set_mesh_power(ms, 0);
 		}
 		break;
 	case PBOOK_WAKE:
 		for (ms = all_meshes; ms != 0; ms = ms->next) {
+			unsigned long flags;
+			
 			set_mesh_power(ms, 1);
 			mesh_init(ms);
+			spin_lock_irqsave(&io_request_lock, flags);
+			mesh_start(ms);
+			spin_unlock_irqrestore(&io_request_lock, flags);
 			enable_irq(ms->meshintr);
+			scsi_unblock_requests(ms->host);
 		}
 		break;
 	}
@@ -411,10 +464,13 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
+/*
+ * Called by midlayer with host locked to queue a new
+ * request
+ */
 int
 mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-	unsigned long flags;
 	struct mesh_state *ms;
 
 	cmd->scsi_done = done;
@@ -422,8 +478,6 @@
 
 	ms = (struct mesh_state *) cmd->host->hostdata;
 
-	save_flags(flags);
-	cli();
 	if (ms->request_q == NULL)
 		ms->request_q = cmd;
 	else
@@ -433,19 +487,25 @@
 	if (ms->phase == idle)
 		mesh_start(ms);
 
-	restore_flags(flags);
 	return 0;
 }
 
+/* Todo: here we can at least try to remove the command from the
+ * queue if it isn't connected yet, and for pending command, assert
+ * ATN until the bus gets freed.
+ */
 int
 mesh_abort(Scsi_Cmnd *cmd)
 {
 	struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
+	unsigned long flags;
 
 	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+	spin_lock_irqsave(&io_request_lock, flags);
 	mesh_dump_regs(ms);
 	dumplog(ms, cmd->target);
 	dumpslog(ms);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
@@ -482,49 +542,41 @@
 	}
 }
 
+/*
+ * Called by the midlayer with the lock held to reset the
+ * SCSI host and bus.
+ * The midlayer will wait for devices to come back, we don't need
+ * to do that ourselves
+ */
 int
-mesh_reset(Scsi_Cmnd *cmd, unsigned how)
+mesh_host_reset(Scsi_Cmnd *cmd)
 {
 	struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
 	volatile struct mesh_regs *mr = ms->mesh;
 	volatile struct dbdma_regs *md = ms->dma;
-	unsigned long flags;
-	int ret;
 
-	printk(KERN_DEBUG "mesh_reset %x\n", how);
-	ret = SCSI_RESET_BUS_RESET;
-	save_flags(flags);
-	cli();
+	printk(KERN_DEBUG "mesh_host_reset\n");
+
+	/* Reset the controller & dbdma channel */
 	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
 	out_8(&mr->exception, 0xff);	/* clear all exception bits */
 	out_8(&mr->error, 0xff);	/* clear all error bits */
-	if (how & SCSI_RESET_SUGGEST_HOST_RESET) {
-		out_8(&mr->sequence, SEQ_RESETMESH);
-		ret |= SCSI_RESET_HOST_RESET;
-		udelay(1);
-		out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-		out_8(&mr->source_id, ms->host->this_id);
-		out_8(&mr->sel_timeout, 25);	/* 250ms */
-		out_8(&mr->sync_params, ASYNC_PARAMS);
-	}
+	out_8(&mr->sequence, SEQ_RESETMESH);
+	udelay(1);
+	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->source_id, ms->host->this_id);
+	out_8(&mr->sel_timeout, 25);	/* 250ms */
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	/* Reset the bus */
 	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
 	udelay(30);			/* leave it on for >= 25us */
 	out_8(&mr->bus_status1, 0);	/* negate RST */
-#ifdef DO_ASYNC_RESET
-	if (how & SCSI_RESET_ASYNCHRONOUS) {
-		restore_flags(flags);
-		ret |= SCSI_RESET_PENDING;
-	} else
-#endif
-	{
-		handle_reset(ms);
-		restore_flags(flags);
-#ifndef MESH_NEW_STYLE_EH
-		finish_cmds(ms);
-#endif
-		ret |= SCSI_RESET_SUCCESS;
-	}
-	return ret;
+
+	/* Complete pending commands */
+	handle_reset(ms);
+	
+	return SUCCESS;
 }
 
 /*
@@ -553,13 +605,10 @@
 	return NOTIFY_DONE;
 }
 
-int
-mesh_command(Scsi_Cmnd *cmd)
-{
-	printk(KERN_WARNING "whoops... mesh_command called\n");
-	return -1;
-}
-
+/* Called with  meshinterrupt disabled, initialize the chipset
+ * and eventually do the initial bus reset. The lock must not be
+ * held since we can schedule.
+ */
 static void
 mesh_init(struct mesh_state *ms)
 {
@@ -568,6 +617,7 @@
 
 	udelay(100);
 
+	/* Reset controller */
 	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
 	out_8(&mr->exception, 0xff);	/* clear all exception bits */
 	out_8(&mr->error, 0xff);	/* clear all error bits */
@@ -578,15 +628,28 @@
 	out_8(&mr->sel_timeout, 25);	/* 250ms */
 	out_8(&mr->sync_params, ASYNC_PARAMS);
 
-	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
-	udelay(30);			/* leave it on for >= 25us */
-	out_8(&mr->bus_status1, 0);	/* negate RST */
-
+	if (init_reset_delay) {
+		printk(KERN_INFO "mesh: performing initial bus reset...\n");
+		
+		/* Reset bus */
+		out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+		udelay(30);			/* leave it on for >= 25us */
+		out_8(&mr->bus_status1, 0);	/* negate RST */
+
+		/* Wait for bus to come back */
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout((init_reset_delay * HZ) / 1000);
+	}
+	
+	/* Reconfigure controller */
+	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
 	out_8(&mr->sequence, SEQ_FLUSHFIFO);
 	udelay(1);
 	out_8(&mr->sync_params, ASYNC_PARAMS);
 	out_8(&mr->sequence, SEQ_ENBRESEL);
-	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
+
+	ms->phase = idle;
+	ms->msgphase = msg_none;
 }
 
 /*
@@ -646,6 +709,8 @@
 		       cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
 	}
 #endif
+	if (ms->dma_started)
+		panic("mesh: double DMA start !\n");
 
 	ms->phase = arbitrating;
 	ms->msgphase = msg_none;
@@ -770,28 +835,6 @@
 	}
 }
 
-#ifndef MESH_NEW_STYLE_EH
-static void
-finish_cmds(void *data)
-{
-	struct mesh_state *ms = data;
-	Scsi_Cmnd *cmd;
-	unsigned long flags;
-
-	for (;;) {
-		spin_lock_irqsave(&io_request_lock, flags);
-		cmd = ms->completed_q;
-		if (cmd == NULL) {
-			spin_unlock_irqrestore(&io_request_lock, flags);
-			break;
-		}
-		ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;
-		(*cmd->scsi_done)(cmd);
-		spin_unlock_irqrestore(&io_request_lock, flags);
-	}
-}
-#endif /* MESH_NEW_STYLE_EH */
-
 static inline void
 add_sdtr_msg(struct mesh_state *ms)
 {
@@ -1316,10 +1359,13 @@
 		dumpslog(ms);
 	}
 
+	if (ms->dma_started) {
+		printk(KERN_ERR "mesh: reselected with DMA started !\n");
+		halt_dma(ms);
+	}
 	ms->current_req = NULL;
 	ms->phase = dataing;
 	ms->msgphase = msg_in;
-	ms->dma_started = 0;
 	ms->n_msgout = 0;
 	ms->last_n_msgout = 0;
 	prev = ms->conn_tgt;
@@ -1738,18 +1784,7 @@
 static void
 mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
 {
-#ifdef MESH_NEW_STYLE_EH
 	(*cmd->scsi_done)(cmd);
-#else
-	if (ms->completed_q == NULL)
-		ms->completed_q = cmd;
-	else
-		ms->completed_qtail->host_scribble = (void *) cmd;
-	ms->completed_qtail = cmd;
-	cmd->host_scribble = NULL;
-	queue_task(&ms->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-#endif /* MESH_NEW_STYLE_EH */
 }
 
 /*
@@ -1769,24 +1804,29 @@
 	if (cmd) {
 		cmd->SCp.this_residual = cmd->request_bufflen;
 		if (cmd->use_sg > 0) {
+			int nseg;
 			total = 0;
 			scl = (struct scatterlist *) cmd->buffer;
 			off = ms->data_ptr;
-			for (i = 0; i < cmd->use_sg; ++i, ++scl) {
+			nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
+				 scsi_to_pci_dma_dir(cmd ->sc_data_direction));
+			for (i = 0; i <nseg; ++i, ++scl) {
+				u32 dma_addr = sg_dma_address(scl);
+				u32 dma_len = sg_dma_len(scl);
+				
 				total += scl->length;
-				if (off >= scl->length) {
-					off -= scl->length;
+				if (off >= dma_len) {
+					off -= dma_len;
 					continue;
 				}
-				if (scl->length > 0xffff)
+				if (dma_len > 0xffff)
 					panic("mesh: scatterlist element >= 64k");
-				st_le16(&dcmds->req_count, scl->length - off);
+				st_le16(&dcmds->req_count, dma_len - off);
 				st_le16(&dcmds->command, dma_cmd);
-				st_le32(&dcmds->phy_addr,
-					virt_to_phys(scl->address) + off);
+				st_le32(&dcmds->phy_addr, dma_addr + off);
 				dcmds->xfer_status = 0;
 				++dcmds;
-				dtot += scl->length - off;
+				dtot += dma_len - off;
 				off = 0;
 			}
 		} else if (ms->data_ptr < cmd->request_bufflen) {
@@ -1794,6 +1834,7 @@
 			if (dtot > 0xffff)
 				panic("mesh: transfer size >= 64k");
 			st_le16(&dcmds->req_count, dtot);
+			/* XXX Use pci DMA API here ... */
 			st_le32(&dcmds->phy_addr,
 				virt_to_phys(cmd->request_buffer) + ms->data_ptr);
 			dcmds->xfer_status = 0;
@@ -1860,6 +1901,12 @@
 		       ms->conn_tgt, ms->data_ptr, cmd->request_bufflen,
 		       ms->tgts[ms->conn_tgt].data_goes_out);
 	}
+	if (cmd->use_sg != 0) {
+		struct scatterlist *sg;
+		sg = (struct scatterlist *)cmd->request_buffer;
+		pci_unmap_sg(ms->pdev, sg, cmd->use_sg,
+			     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
 	ms->dma_started = 0;
 }
 
diff -urN linux-2.4.19-pre8/drivers/scsi/mesh.h linux-2.4.19-pre9/drivers/scsi/mesh.h
--- linux-2.4.19-pre8/drivers/scsi/mesh.h	Tue Sep 19 08:31:53 2000
+++ linux-2.4.19-pre9/drivers/scsi/mesh.h	Tue May 28 16:02:29 2002
@@ -9,26 +9,27 @@
 
 int mesh_detect(Scsi_Host_Template *);
 int mesh_release(struct Scsi_Host *);
-int mesh_command(Scsi_Cmnd *);
 int mesh_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int mesh_abort(Scsi_Cmnd *);
-int mesh_reset(Scsi_Cmnd *, unsigned int);
+int mesh_host_reset(Scsi_Cmnd *);
 
-#define SCSI_MESH {					\
-	proc_name:	"mesh",				\
-	name:		"MESH",				\
-	detect:		mesh_detect,			\
-	release:	mesh_release,			\
-	command:	mesh_command,			\
-	queuecommand:	mesh_queue,			\
-	abort:		mesh_abort,			\
-	reset:		mesh_reset,			\
-	can_queue:	20,				\
-	this_id:	7,				\
-	sg_tablesize:	SG_ALL,				\
-	cmd_per_lun:	2,				\
-	use_clustering:	DISABLE_CLUSTERING,		\
-	use_new_eh_code: 1,				\
+#define SCSI_MESH {						\
+	proc_name:			"mesh",			\
+	name:				"MESH",			\
+	detect:				mesh_detect,		\
+	release:			mesh_release,		\
+	command:			NULL,			\
+	queuecommand:			mesh_queue,		\
+	eh_abort_handler:		mesh_abort,		\
+	eh_device_reset_handler:	NULL,			\
+	eh_bus_reset_handler:		NULL,			\
+	eh_host_reset_handler:		mesh_host_reset,	\
+	can_queue:			20,			\
+	this_id:			7,			\
+	sg_tablesize:			SG_ALL,			\
+	cmd_per_lun:			2,			\
+	use_clustering:			DISABLE_CLUSTERING,	\
+	use_new_eh_code: 		1,			\
 }
 
 /*
diff -urN linux-2.4.19-pre8/drivers/scsi/scsi_debug.c linux-2.4.19-pre9/drivers/scsi/scsi_debug.c
--- linux-2.4.19-pre8/drivers/scsi/scsi_debug.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/scsi/scsi_debug.c	Tue May 28 16:02:29 2002
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
diff -urN linux-2.4.19-pre8/drivers/scsi/sim710.c linux-2.4.19-pre9/drivers/scsi/sim710.c
--- linux-2.4.19-pre8/drivers/scsi/sim710.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.19-pre9/drivers/scsi/sim710.c	Tue May 28 16:02:29 2002
@@ -18,6 +18,9 @@
  *----------------------------------------------------------------------------
  *
  * MCA card detection code by Trent McNair.
+ * Fixes to not explicitly nul bss data from Xavier Bestel.
+ * Some multiboard fixes from Rolf Eike Beer.
+ * Auto probing of EISA config space from Trevor Hemsley.
  *
  * Various bits of code in this driver have been copied from 53c7,8xx,c,
  * which is coyright Drew Eckhardt.  The scripts for the SCSI chip are
@@ -41,6 +44,16 @@
  * and insmod parameters similar to
  *	sim710="addr:0x9000 irq:15"
  *
+ * Multiple controllers can also be set up by comamnd line, provided the
+ * addr: parameter is specified first for each controller.  e.g.
+ *      sim710="addr:0x9000 irq:15 addr:0x8000 irq:14"
+ *
+ * To seperate the different options, ' ', '+', and ',' can be used, except
+ * that ',' can not be used in module parameters.  ' ' can be a pain, because
+ * it needs to be quoted, which causes problems with some installers.
+ * The command line above is completely equivalent to
+ *      sim710="addr:0x9000+irq:15+addr:0x8000+irq:14"
+ *
  * The complete list of options are:
  *
  * addr:0x9000		Specifies the base I/O port (or address) of the 53C710.
@@ -49,12 +62,18 @@
  * ignore:0x0a		Makes the driver ignore SCSI IDs 0 and 2.
  * nodisc:0x70		Prevents disconnects from IDs 6, 5 and 4.
  * noneg:0x10		Prevents SDTR negotiation on ID 4.
+ * disabled:1		Completely disables the driver. When present, overrides
+ *			all other options.
+ *
+ * The driver will auto-probe chip addresses and IRQs now, so typically no
+ * parameters are needed.  Auto-probing of addresses is disabled if any addr:
+ * parameters are specified.
  *
  * Current limitations:
  *
  * o  Async only
  * o  Severely lacking in error recovery
- * o  Auto detection of IRQs and chip addresses only on MCA architectures
+ * o  'debug:' should be per host really.
  *
  */
 
@@ -71,27 +90,20 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/mca.h>
+#include <linux/interrupt.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
-#include <asm/spinlock.h>
-#endif
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>
 #include <linux/blk.h>
 
-#ifdef CONFIG_TP34V_SCSI
-
-#include <asm/tp34vhw.h>
-#define MEM_MAPPED
-
-#elif defined(CONFIG_MCA)
-
+/* All targets are I/O mapped at the moment */
 #define IO_MAPPED
 
+#if defined(CONFIG_MCA)
+
 /*
  * For each known microchannel card using the 53c710 we need a list
  * of possible IRQ and IO settings, as well as their corresponding
@@ -116,12 +128,6 @@
 
 #define MCA_004F_IRQS { 5, 9, 14 }
 
-#else
-
-/* Assume an Intel platform */
-
-#define IO_MAPPED
-
 #endif
 
 #include "scsi.h"
@@ -151,7 +157,7 @@
 
 #ifdef DEBUG
 #define DEB(m,x) if (sim710_debug & m) x
-int sim710_debug = 0;
+int sim710_debug;
 #else
 #define DEB(m,x)
 #endif
@@ -178,7 +184,7 @@
 #define STATE_BUSY		3
 #define STATE_DISABLED		4
 
-#define MAXBOARDS 2	/* Increase this and the sizes of the
+#define MAXBOARDS 4	/* Increase this and the sizes of the
 			   arrays below, if you need more.. */
 
 #ifdef MODULE
@@ -193,44 +199,15 @@
 
 #endif
 
-static int sim710_errors = 0;	/* Count of error interrupts */
-static int sim710_intrs = 0;	/* Count of all interrupts */
-static int ignore_ids = 0;	/* Accept all SCSI IDs */
-static int opt_nodisc = 0;	/* Allow disconnect on all IDs */
-static int opt_noneg = 0;	/* Allow SDTR negotiation on all IDs */
-
-#ifdef CONFIG_TP34V_SCSI
-
-/* Special hardwired case for Tadpole TP34V at the moment, otherwise
- * boot parameters 'sim710=addr:0x8000,irq:15' (for example) must be given.
- */
-
-static int no_of_boards = 2;
-
-static unsigned int bases[MAXBOARDS] = {
-	TP34V_SCSI0_BASE, TP34V_SCSI1_BASE
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	TP34V_SCSI0_VECTOR, TP34V_SCSI1_VECTOR
-};
-static unsigned int irq_index[MAXBOARDS] = {
-	TP34V_SCSI0_IRQ_INDEX, TP34V_SCSI1_IRQ_INDEX
-};
-
-#else
-
-/* All other cases use boot/module params, or auto-detect */
-
-static int no_of_boards = 0;
-
-static unsigned int bases[MAXBOARDS] = {
-	0
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	0
-};
-
-#endif
+static int sim710_errors;		/* Count of error interrupts */
+static int sim710_intrs;		/* Count of all interrupts */
+static int ignore_ids[MAXBOARDS];	/* Accept all SCSI IDs */
+static int opt_nodisc[MAXBOARDS];	/* Allow disconnect on all IDs */
+static int opt_noneg[MAXBOARDS];	/* Allow SDTR negotiation on all IDs */
+static int hostdata_order;		/* Encoded size of hostdata for free_pages() */
+static int no_of_boards;		/* Actual number of boards/chips */
+static unsigned int bases[MAXBOARDS];	/* Base addresses of chips */
+static unsigned int irq_vectors[MAXBOARDS]; /* IRQ vectors used by chips */
 
 /* The SCSI Script!!! */
 
@@ -249,7 +226,6 @@
 
 #define MAX_SG		128	/* Scatter/Gather elements */
 
-
 #define MAX_MSGOUT	8
 #define MAX_MSGIN	8
 #define MAX_CMND	12
@@ -263,6 +239,9 @@
     u8 negotiate;
     u8 reselected_identify;
     u8 msgin_buf[MAX_MSGIN];
+    u8 msg_reject;
+    u32 test1_src __attribute__ ((aligned (4)));
+    u32 test1_dst;
 
     struct sim710_target {
 	Scsi_Cmnd *cur_cmd;
@@ -294,82 +273,127 @@
 
 
 /*
- * Function: int param_setup(char *str)
+ * Function : static void ncr_dump (struct Scsi_Host *host)
+ *
+ * Purpose :  Dump (possibly) useful info
+ *
+ * Inputs : host - pointer to this host adapter's structure
  */
 
-#ifdef MODULE
-#define ARG_SEP ' '
-#else
-#define ARG_SEP ','
-#endif
+static void
+ncr_dump (struct Scsi_Host *host)
+{
+    unsigned long flags;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+       host->hostdata[0];
 
-static int
+    save_flags(flags);
+    cli();
+    printk("scsi%d: Chip register contents:\n", host->host_no);
+    printk(" (script at virt %p, bus %lx)\n",
+           hostdata->script, virt_to_bus(hostdata->script));
+    printk(" 00  sien:  %02x  sdid:  %02x  scntl1:%02x  scntl0:%02x\n"
+	   " 04  socl:  %02x  sodl:  %02x  sxfer: %02x  scid:  %02x\n"
+	   " 08  sbcl:  %02x  sbdl:  %02x  sidl:  %02x  sfbr:  %02x\n"
+	   " 0C  sstat2:%02x  sstat1:%02x  sstat0:%02x  dstat: %02x\n"
+	   " 10  dsa:   %08x\n"
+	   " 14  ctest3:%02x  ctest2:%02x  ctest1:%02x  ctest0:%02x\n"
+	   " 18  ctest7:%02x  ctest6:%02x  ctest5:%02x  ctest4:%02x\n"
+	   " 1C  temp:  %08x\n"
+	   " 20  lcrc:  %02x  ctest8:%02x  istat: %02x  dfifo: %02x\n"
+	   " 24  dbc:   %08x  dnad:  %08x  dsp:   %08x\n"
+	   " 30  dsps:  %08x  scratch:%08x\n"
+	   " 38  dcntl: %02x  dwt:   %02x  dien:  %02x  dmode: %02x\n"
+	   " 3C  adder: %08x\n",
+	  NCR_read8(SIEN_REG), NCR_read8(SDID_REG), NCR_read8(SCNTL1_REG),
+	  NCR_read8(SCNTL0_REG), NCR_read8(SOCL_REG), NCR_read8(SODL_REG),
+	  NCR_read8(SXFER_REG), NCR_read8(SCID_REG), NCR_read8(SBCL_REG),
+	  NCR_read8(SBDL_REG), NCR_read8(SIDL_REG), NCR_read8(SFBR_REG),
+	  NCR_read8(SSTAT2_REG), NCR_read8(SSTAT1_REG), NCR_read8(SSTAT0_REG),
+	  NCR_read8(DSTAT_REG), NCR_read32(DSA_REG), NCR_read8(CTEST3_REG),
+	  NCR_read8(CTEST2_REG), NCR_read8(CTEST1_REG), NCR_read8(CTEST0_REG),
+	  NCR_read8(CTEST7_REG), NCR_read8(CTEST6_REG), NCR_read8(CTEST5_REG),
+	  NCR_read8(CTEST4_REG), NCR_read8(TEMP_REG), NCR_read8(LCRC_REG),
+	  NCR_read8(CTEST8_REG), NCR_read8(ISTAT_REG), NCR_read8(DFIFO_REG),
+	  NCR_read32(DBC_REG), NCR_read32(DNAD_REG), NCR_read32(DSP_REG),
+	  NCR_read32(DSPS_REG), NCR_read32(SCRATCH_REG), NCR_read8(DCNTL_REG),
+	  NCR_read8(DWT_REG), NCR_read8(DIEN_REG), NCR_read8(DMODE_REG),
+	  NCR_read32(ADDER_REG));
+
+    restore_flags(flags);
+}
+
+
+/*
+ * Function: int param_setup(char *str)
+ */
+
+__init int
 param_setup(char *str)
 {
     char *cur = str;
-    char *pc, *pv;
+    char *p, *pc, *pv;
     int val;
-    int base;
     int c;
 
     no_of_boards = 0;
-    while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+    while (no_of_boards < MAXBOARDS && cur != NULL &&
+		(pc = strchr(cur, ':')) != NULL) {
 	char *pe;
 
 	val = 0;
 	pv = pc;
 	c = *++pv;
 
-	if (c == 'n')
-	    val = 0;
-	else if	(c == 'y')
-	    val = 1;
-	else {
-	    base = 0;
-	    val = (int) simple_strtoul(pv, &pe, base);
-	}
+	val = (int) simple_strtoul(pv, &pe, 0);
+
 	if (!strncmp(cur, "addr:", 5)) {
-	    bases[0] = val;
-	    no_of_boards = 1;
+	    bases[no_of_boards++] = val;
+	}
+#ifdef DEBUG
+	else if (!strncmp(cur, "debug:", 6)) {
+	    sim710_debug = val;
+	}
+#endif
+	else if (no_of_boards == 0) {
+	    printk("sim710: Invalid parameters, addr: must come first\n");
+	    no_of_boards = -1;
+	    return 1;
 	}
 	else if	(!strncmp(cur, "irq:", 4))
-	    irq_vectors[0] = val;
+	    irq_vectors[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "ignore:", 7))
-	    ignore_ids = val;
+	    ignore_ids[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "nodisc:", 7))
-	    opt_nodisc = val;
+	    opt_nodisc[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "noneg:", 6))
-	    opt_noneg = val;
-	else if	(!strncmp(cur, "disabled:", 5)) {
+	    opt_noneg[no_of_boards-1] = val;
+	else if	(!strncmp(cur, "disabled:", 9)) {
 	    no_of_boards = -1;
 	    return 1;
 	}
-#ifdef DEBUG
-	else if (!strncmp(cur, "debug:", 6)) {
-	    sim710_debug = val;
+	else {
+	    printk("sim710: unexpected boot option '%.*s'\n", (int)(pc-cur+1), cur);
+	    no_of_boards = -1;
+	    return 1;
 	}
-#endif
-	else
-	    printk("sim710: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
-	if ((cur = strchr(cur, ARG_SEP)) != NULL)
-	    ++cur;
+	/* Allow ',', ' ', or '+' seperators.  Used to be ',' at boot and
+	 * ' ' for module load, some installers crap out on the space and
+	 * insmod doesn't like the comma.
+	 */
+       if ((p = strchr(cur, ',')) || (p = strchr(cur, ' ')) ||
+               (p = strchr(cur, '+')))
+           cur = p + 1;
+        else
+           break;
     }
     return 1;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
 #ifndef MODULE
 __setup("sim710=", param_setup);
 #endif
-#else
-/* Old boot param syntax support */
-void
-sim710_setup(char *str, int *ints)
-{
-    param_setup(str);
-}
-#endif
 
 
 /*
@@ -398,22 +422,6 @@
 
 
 /*
- * Function: static void disable (struct Scsi_Host *host)
- */
-
-static void
-disable (struct Scsi_Host *host)
-{
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-
-    hostdata->state = STATE_DISABLED;
-    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
-		            host->host_no);
-}
-
-
-/*
  * Function : static int ncr_halt (struct Scsi_Host *host)
  *
  * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
@@ -431,6 +439,8 @@
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
 	host->hostdata[0];
     int stage;
+    int timeout;
+    int res = 0;
 
     save_flags(flags);
     cli();
@@ -438,8 +448,10 @@
        Stage 1 : set ABORT
        Stage 2 : eat all but abort interrupts
        Stage 3 : eat all interrupts
+       We loop for 50000 times with a delay of 10us which should give us
+       about half a second.
      */
-    for (stage = 0;;) {
+    for (stage = 0, timeout = 50000; timeout; timeout--) {
 	if (stage == 1) {
 	    DEB(DEB_HALT, printk("ncr_halt: writing ISTAT_ABRT\n"));
 	    NCR_write8(ISTAT_REG, ISTAT_ABRT);
@@ -460,9 +472,8 @@
 		    NCR_write8(ISTAT_REG, 0);
 		    ++stage;
 		} else {
-		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
-			host->host_no);
-		    disable (host);
+		    res = 1;
+		    break;
 	    	}
     	    }
 	}
@@ -472,10 +483,18 @@
 	    else if (stage == 3)
 		break;
 	}
+	udelay(10);
     }
-    hostdata->state = STATE_HALTED;
     restore_flags(flags);
-    return 0;
+
+    if (timeout == 0 || res) {
+	printk(KERN_ALERT "scsi%d: could not halt NCR chip\n", host->host_no);
+	return 1;
+    }
+    else {
+	hostdata->state = STATE_HALTED;
+	return 0;
+    }
 }
 
 /*
@@ -494,16 +513,9 @@
 sim710_soft_reset (struct Scsi_Host *host)
 {
     unsigned long flags;
-#ifdef CONFIG_TP34V_SCSI
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-#endif
 
     save_flags(flags);
     cli();
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x80;
-#endif
     /*
      * Do a soft reset of the chip so that everything is
      * reinitialized to the power-on state.
@@ -528,6 +540,7 @@
 
     mdelay(1000);				/* Let devices recover */
 
+    NCR_write32(SCRATCH_REG, 0);
     NCR_write8(DCNTL_REG, DCNTL_10_COM | DCNTL_700_CF_3);
     NCR_write8(CTEST7_REG, CTEST7_10_CDIS|CTEST7_STD);
     NCR_write8(DMODE_REG, DMODE_10_BL_8 | DMODE_10_FC2);
@@ -544,11 +557,6 @@
     NCR_write8(SIEN_REG_700,
 	    SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
 
-
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;
-#endif
-
     restore_flags(flags);
 }
 
@@ -577,6 +585,12 @@
     	virt_to_bus((void *)&(hostdata->reselected_identify)));
     patch_abs_32 (hostdata->script, 0, msgin_buf, 
     	virt_to_bus((void *)&(hostdata->msgin_buf[0])));
+    patch_abs_32 (hostdata->script, 0, msg_reject, 
+	virt_to_bus((void *)&(hostdata->msg_reject)));
+    patch_abs_32 (hostdata->script, 0, test1_src, 
+	virt_to_bus((void *)&(hostdata->test1_src)));
+    patch_abs_32 (hostdata->script, 0, test1_dst, 
+	virt_to_bus((void *)&(hostdata->test1_dst)));
     hostdata->state = STATE_INITIALISED;
     hostdata->negotiate = 0xff;
 }
@@ -587,7 +601,7 @@
  * spurious request from the target.  Don't really expect target initiated
  * SDTRs, because we always negotiate on the first command.  Could still
  * get them though..
- * The chip is currently paused with ACK asserted o the last byte of the
+ * The chip is currently paused with ACK asserted on the last byte of the
  * SDTR.
  * resa is the resume address if the message is in response to our outgoing
  * SDTR.  Only possible on initial identify.
@@ -739,6 +753,12 @@
 		host->host_no);
 	    resume_offset = Ent_resume_cmd;
 	}
+	else if (sbcl == SBCL_PHASE_STATIN) {
+	    /* Some devices do this on parity error, at least */
+	    printk("scsi%d: Unexpected switch to STATUSIN on initial message out\n",
+		host->host_no);
+	    resume_offset = Ent_end_data_trans;
+	}
 	else {
 	    printk("scsi%d: Unexpected phase change to %s on initial msgout\n",
 		host->host_no, sbcl_to_phase(sbcl));
@@ -801,6 +821,14 @@
 	    resume_offset = Ent_resume_pmm;
 	}
     }
+    else if (sbcl == SBCL_PHASE_STATIN) {
+	/* Change to Status In at some random point; probably wants to report a
+	 * parity error or similar.
+	 */
+	printk("scsi%d: Unexpected phase change to STATUSIN at index 0x%x\n",
+		host->host_no, index);
+	resume_offset = Ent_end_data_trans;
+    }
     else {
 	printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",
 		host->host_no, sbcl_to_phase(sbcl), index);
@@ -868,12 +896,6 @@
 	printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",
 		host->host_no, sbcl_to_phase(sbcl), sbcl);
 	break;
-    case A_int_bad_extmsg1a:
-    case A_int_bad_extmsg1b:
-    case A_int_bad_extmsg2a:
-    case A_int_bad_extmsg2b:
-    case A_int_bad_extmsg3a:
-    case A_int_bad_extmsg3b:
     case A_int_bad_msg1:
     case A_int_bad_msg2:
     case A_int_bad_msg3:
@@ -917,21 +939,22 @@
 static void
 sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned int flags;
     struct Scsi_Host * host = (struct Scsi_Host *)dev_id;
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
     Scsi_Cmnd * cmd;
     unsigned char istat, dstat;
     unsigned char sstat0;
-    u32 dsps, resume_offset = 0;
+    u32 scratch, dsps, resume_offset = 0;
 
-    save_flags(flags);
-    cli();
-    sim710_intrs++;
-    while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {
+    istat = NCR_read8(ISTAT_REG);
+    if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+	return;
+    else {
+	sim710_intrs++;
 	dsps = NCR_read32(DSPS_REG);
 	hostdata->state = STATE_HALTED;
 	sstat0 = dstat = 0;
+	scratch = NCR_read32(SCRATCH_REG);
 	if (istat & ISTAT_SIP) {
 	    sstat0 = NCR_read8(SSTAT0_REG);
 	}
@@ -944,7 +967,13 @@
 		"dstat %02x, dsp [%04x], scratch %02x\n",
 	    host->host_no, sim710_intrs, istat, sstat0, dstat,
 	    (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
-	    NCR_read32(SCRATCH_REG)));
+	    scratch));
+	if (scratch & 0x100) {
+	    u8 *p = hostdata->msgin_buf;
+
+	    DEB(DEB_INTS, printk("  msgin_buf: %02x %02x %02x %02x\n",
+			p[0], p[1], p[2], p[3]));
+	}
 	if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {
 	    /* Reselected.  Identify the target from LCRC_REG, and
 	     * update current command.  If we were trying to select
@@ -1001,12 +1030,7 @@
 	    hostdata->target[cmd->target].cur_cmd = NULL;
 	    resume_offset = Ent_reselect;
 	}
-	else if (dstat & DSTAT_SIR)
-	    resume_offset = handle_script_int(host, cmd);
-	else if (sstat0 & SSTAT0_MA) {
-	    resume_offset = handle_phase_mismatch(host, cmd);
-	}
-	else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
+	else if (sstat0 & (SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
 	    printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,
 			    sstat0);
 	    sim710_errors++;
@@ -1018,6 +1042,10 @@
 	    sim710_errors++;
 	    /* resume_offset is zero, which will cause a host reset */
 	}
+	else if (dstat & DSTAT_SIR)
+	    resume_offset = handle_script_int(host, cmd);
+	else if (sstat0 & SSTAT0_MA)
+	    resume_offset = handle_phase_mismatch(host, cmd);
 	else if (dstat & DSTAT_IID) {
 	    /* This can be due to a quick reselect while doing a WAIT
 	     * DISCONNECT.
@@ -1043,18 +1071,19 @@
 #ifdef DEBUG_LIMIT_INTS
 	if (sim710_intrs < DEBUG_LIMIT_INTS)
 #endif
-	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+	{
+	    NCR_write32(SCRATCH_REG, 0);
+	    NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+	}
 	if (resume_offset == Ent_reselect)
 	    run_process_issue_queue(hostdata);
     }
     else {
 	printk("scsi%d: Failed to handle interrupt.  Failing commands "
 		"and resetting SCSI bus and chip\n", host->host_no);
-	mdelay(4000);		/* Give chance to read screen!! */
+	mdelay(1000);		/* Give chance to read screen!! */
 	full_reset(host);
     }
-
-    restore_flags(flags);
 }
 
 
@@ -1100,9 +1129,9 @@
     memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND);
 
     targdata->dsa_msgout[0] =
-		IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0);
+		IDENTIFY((opt_nodisc[hostdata->chip] & (1<<cmd->target)) ? 0 : 1 ,0);
     if (hostdata->negotiate & (1 << cmd->target)) {
-	if (opt_noneg & (1 << cmd->target)) {
+	if (opt_noneg[hostdata->chip] & (1 << cmd->target)) {
 	    hostdata->negotiate ^= (1 << cmd->target);
 	    targdata->dsa[DSA_MSGOUT] = 1;
 	}
@@ -1143,16 +1172,10 @@
 		cmd->request_bufflen;
 
 	if (datain) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_clear(virt_to_phys((void *)vbuf), cnt);
-#endif
 	    *dip++	= cnt;
 	    *dip++	= bbuf;
 	}
 	if (dataout) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_push(virt_to_phys((void *)vbuf), cnt);
-#endif
 	    *dop++	= cnt;
 	    *dop++	= bbuf;
 	}
@@ -1288,7 +1311,7 @@
     save_flags(flags);
     cli();
 
-    if (ignore_ids & (1 << cmd->target)) {
+    if (ignore_ids[hostdata->chip] & (1 << cmd->target)) {
 	printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target);
 	cmd->result = (DID_BAD_TARGET << 16);
 	done(cmd);
@@ -1320,18 +1343,25 @@
 }
 
 
-int
+__init int
 sim710_detect(Scsi_Host_Template * tpnt)
 {
-    unsigned char irq_vector;
     unsigned char scsi_id;
     unsigned int base_addr;
     struct Scsi_Host * host = NULL;
     struct sim710_hostdata *hostdata;
+    unsigned long timeout;
+    unsigned long irq_mask;
+    int requested_irq;
+    int probed_irq;
+    u32 dsps;
     int chips = 0;
+    int limit;
     int indx;
     int revision;
-    int order, size;
+    int size;
+    volatile u8 tmp;
+    struct Scsi_Host *our_hosts[MAXBOARDS+1];
 
 #ifdef MODULE
     if (sim710)
@@ -1433,83 +1463,190 @@
     }
 #endif
 
+#ifdef CONFIG_EISA
+    /* Auto probe, if no boards specified in boot parameters */
+    if (no_of_boards == 0) {
+	int io_addr;
+	/* reverse probe, so my on-board controller at 0x9000 is always scsi0 */
+	for (io_addr = 0x9000; no_of_boards < MAXBOARDS && io_addr >= 0x1000; io_addr -= 0x1000) {
+	    if (request_region(io_addr, 0x40, "sim710") != NULL) {
+		int id0 = inw(io_addr + 0xc80);
+		int id1 = inw(io_addr + 0xc82);
+		/* The on-board controller on my Proliant 2000 is 0x1044,
+		 * my EISA card is 0x1144.
+		 */
+		if (id0 == 0x110e && (id1 == 0x1044 || id1 == 0x1144)) {
+		    bases[no_of_boards] = io_addr;
+#if 0
+		    /* This should detect the IRQ, but I havn't proved it for
+		     * myself.  Leave the old probe code active for now, as
+		     * no-one has reported problems with it.
+		     */
+		    switch (inb(io_addr + 0xc88)) {
+			case (0x00):
+			    irq_vectors[no_of_boards] = 11;
+			    break;
+			case (0x01):
+			    irq_vectors[no_of_boards] = 14;
+			    break;
+			case (0x02):
+			    irq_vectors[no_of_boards] = 15;
+			    break;
+			case (0x03):
+			    irq_vectors[no_of_boards] = 10;
+			    break;
+			case (0x04):
+			    irq_vectors[no_of_boards] = 9;
+			    break;
+			default:
+			    printk("sim710.c: irq nasty\n");
+		    }
+#endif
+		    no_of_boards++;
+		}
+		release_region(io_addr, 64);
+	    }
+	}
+    }
+#endif
     if (!no_of_boards) {
-       printk("sim710: No NCR53C710 adapter found.\n");
-       return 0;
+	printk("sim710: No NCR53C710 adapter found.\n");
+	return 0;
     }
 
     size = sizeof(struct sim710_hostdata);
-    order = 0;
-    while (size > (PAGE_SIZE << order))
-	order++;
-    size = PAGE_SIZE << order;
+    hostdata_order = 0;
+    while (size > (PAGE_SIZE << hostdata_order))
+	hostdata_order++;
+    size = PAGE_SIZE << hostdata_order;
 
     DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n",
-	sizeof(struct sim710_hostdata), size, order));
+	sizeof(struct sim710_hostdata), size, hostdata_order));
 
     tpnt->proc_name = "sim710";
 
-    for(indx = 0; indx < no_of_boards; indx++) {
-        unsigned long page = __get_free_pages(GFP_ATOMIC, order);
+    memset(our_hosts, 0, sizeof(our_hosts));
+    for (indx = 0; indx < no_of_boards; indx++) {
+        unsigned long page = __get_free_pages(GFP_ATOMIC, hostdata_order);
         if(page == 0UL)
         {
-        	printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
-        	break;
+	    printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
+	    break;
         }
 	host = scsi_register(tpnt, 4);
-	if(host == NULL)
-		break;
+	if(host == NULL) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    break;
+	}
+	our_hosts[chips] = host;
 	host->hostdata[0] = page;
 	hostdata = (struct sim710_hostdata *)host->hostdata[0];
 	memset(hostdata, 0, size);
-#ifdef CONFIG_TP34V_SCSI
-	cache_push(virt_to_phys(hostdata), size);
-	cache_clear(virt_to_phys(hostdata), size);
-	kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);
-#endif
 	scsi_id = 7;
 	base_addr = bases[indx];
-	irq_vector = irq_vectors[indx];
-	printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
-	    		scsi_id, base_addr, irq_vector);
+	requested_irq = irq_vectors[indx];
+	printk("scsi%d: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
+			host->host_no, scsi_id, base_addr, requested_irq);
 	DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n",
 			hostdata, sizeof(struct sim710_hostdata),
 			 hostdata->target[0].dsa));
 	hostdata->chip = indx;
-	host->irq = irq_vector;
+	host->irq = requested_irq;
 	host->this_id = scsi_id;
 	host->unique_id = base_addr;
 	host->base = base_addr;
+	hostdata->msg_reject = MESSAGE_REJECT;
 
-	ncr_halt(host);
-
+	if (ncr_halt(host)) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    printk("scsi%d: Failed to initialise 53c710 at address %x\n",
+			host->host_no, base_addr);
+	    continue;
+	}
+	DEB(DEB_ANY,ncr_dump(host));
 	revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4;
 	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
-
 	sim710_soft_reset(host);
 
 	sim710_driver_init(host);
 
-#ifdef CONFIG_TP34V_SCSI
-	if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))
-#else
-	if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))
-#endif
-	{
-	    printk("scsi%d : IRQ%d not free, detaching\n",
-	    		host->host_no, host->irq);
-
-	    scsi_unregister (host);
+	request_region((u32)host->base, 64, "sim710");
+	/* Now run test1 */
+	hostdata->test1_src = 0x53c710aa;
+	hostdata->test1_dst = 0x76543210;
+	NCR_write32(DSPS_REG, 0x89abcdef);
+	irq_mask = probe_irq_on();
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_test1/4));
+	timeout = 5;
+	while (hostdata->test1_dst != hostdata->test1_src && timeout--)
+	    mdelay(100);
+	tmp = NCR_read8(ISTAT_REG);
+	tmp = NCR_read8(SSTAT0_REG);
+	udelay(10);
+	tmp = NCR_read8(DSTAT_REG);
+	probed_irq = probe_irq_off(irq_mask);
+	if (requested_irq == 0) {
+	    if (probed_irq > 0) {
+		printk("scsi%d: Chip is using IRQ %d\n", host->host_no,
+			probed_irq);
+		requested_irq = host->irq = probed_irq;
+	    }
+	    else {
+		printk("scsi%d: Failed to probe for IRQ (returned %d)\n",
+			host->host_no, probed_irq);
+		ncr_halt(host);
+		free_pages(host->hostdata[0], hostdata_order);
+		scsi_unregister (host);
+		release_region((u32)host->base, 64);
+		continue;
+	    }
 	}
-	else {
-#ifdef IO_MAPPED
-	    request_region((u32)host->base, 64, "sim710");
-#endif
-	    chips++;
+	else if (probed_irq > 0 && probed_irq != requested_irq)
+	    printk("scsi%d: WARNING requested IRQ %d, but probed as %d\n",
+			host->host_no, requested_irq, probed_irq);
+	else if (probed_irq <= 0)
+	    printk("scsi%d: WARNING IRQ probe failed, (returned %d)\n",
+			host->host_no, probed_irq);
+  
+	dsps = NCR_read32(DSPS_REG);
+	if (hostdata->test1_dst != 0x53c710aa || dsps != A_int_test1) {
+	    if (hostdata->test1_dst != 0x53c710aa)
+		printk("scsi%d: test 1 FAILED: data: exp 0x53c710aa, got 0x%08x\n",
+			host->host_no, hostdata->test1_dst);
+	    if (dsps != A_int_test1)
+		printk("scsi%d: test 1 FAILED: dsps: exp 0x%08x, got 0x%08x\n",
+			host->host_no, A_int_test1, dsps);
+	    ncr_dump(host);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    release_region((u32)host->base, 64);
+	    continue;
 	}
+	printk("scsi%d: test 1 completed ok.\n", host->host_no);
+
 	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
 	hostdata->state = STATE_IDLE;
+	chips++;
     }
+    /* OK, now run down our_hosts[] calling request_irq(... SA_SHIRQ ...).
+     * Couldn't call request_irq earlier, as probing would have failed.
+     */
+    for (indx = 0, limit = chips; indx < limit; indx++) {
+	host = our_hosts[indx];
+	if (request_irq(host->irq, do_sim710_intr_handle,
+                       SA_INTERRUPT | SA_SHIRQ, "sim710", host))
+	{
+	    printk("scsi%d : IRQ%d not free, detaching\n",
+			host->host_no, host->irq);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    chips--;
+	}
+    }
+
     return chips;
 }
 
@@ -1557,12 +1694,34 @@
 	    host->hostdata[0];
     int target;
     Scsi_Cmnd *cmd;
+    u32 istat, dstat = 0, sstat0 = 0, sstat1 = 0, dsp, dsps, scratch;
+    unsigned long flags;
 
-    ncr_halt(host);
-    printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n",
-	host->host_no, NCR_read32(DSP_REG),
-	((u32)bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4,
-	NCR_read32(SCRATCH_REG));
+    save_flags(flags);
+    cli();
+
+    istat = NCR_read8(ISTAT_REG);
+    if (istat & ISTAT_SIP) {
+	sstat0 = NCR_read8(SSTAT0_REG);
+	sstat1 = NCR_read8(SSTAT1_REG);
+	udelay(10);
+    }
+    if (istat & ISTAT_DIP)
+	dstat = NCR_read8(DSTAT_REG);
+
+    if (ncr_halt(host)) {
+	restore_flags(flags);
+	return FAILED;
+    }
+    restore_flags(flags);
+    dsp = NCR_read32(DSP_REG);
+    dsps = NCR_read32(DSPS_REG);
+    scratch = NCR_read32(SCRATCH_REG);
+    printk("scsi%d: istat = %02x, sstat0 = %02x, sstat1 = %02x, dstat = %02x\n",
+		host->host_no, istat, sstat0, sstat1, dstat);
+    printk("scsi%d: dsp = %08x (script[0x%04x]), dsps = %08x, scratch = %08x\n",
+		host->host_no, dsp,
+		((u32)bus_to_virt(dsp) - (u32)hostdata->script)/4, dsps, scratch);
 
     for (target = 0; target < 7; target++) {
 	if ((cmd = hostdata->target[target].cur_cmd)) {
@@ -1604,10 +1763,10 @@
 int
 sim710_release(struct Scsi_Host *host)
 {
+    ncr_halt(host);
+    free_pages(host->hostdata[0], hostdata_order);
     free_irq(host->irq, host);
-#ifdef IO_MAPPED
     release_region((u32)host->base, 64);
-#endif
     return 1;
 }
 
diff -urN linux-2.4.19-pre8/drivers/scsi/sim710.h linux-2.4.19-pre9/drivers/scsi/sim710.h
--- linux-2.4.19-pre8/drivers/scsi/sim710.h	Thu Jul 19 21:07:45 2001
+++ linux-2.4.19-pre9/drivers/scsi/sim710.h	Tue May 28 16:02:29 2002
@@ -23,8 +23,8 @@
 
 #include <scsi/scsicam.h>
 
-#define SIM710_SCSI { proc_name:		"sim710",	\
-		      name:			"Simple 53c710", 	\
+#define SIM710_SCSI { proc_name:		"sim710",		\
+		      name:			"53c710",	 	\
 		      detect:			sim710_detect,		\
 		      release:			sim710_release,		\
 		      queuecommand:		sim710_queuecommand,	\
@@ -414,7 +414,7 @@
 #define CTEST3_800_FM		0x02	/* Fetch mode pin */
 /* bit 0 is reserved on 800 series chips */
 
-#define CTEST4_REG_400		(0x18^bE)	/* Chip test 4 rw */
+#define CTEST4_REG_700		(0x18^bE)	/* Chip test 4 rw */
 #define CTEST4_REG_800		(0x21^bE)	/* Chip test 4 rw */
 /* 0x80 is reserved on 700 series chips */
 #define CTEST4_800_BDIS		0x80	/* Burst mode disable */
@@ -792,6 +792,20 @@
 
 #define ISTAT_REG	ISTAT_REG_700
 #define SCRATCH_REG	SCRATCHB_REG_10
+#define ADDER_REG	ADDER_REG_10
+#define SIEN_REG	SIEN_REG_700
+#define SDID_REG	SDID_REG_700
+#define CTEST0_REG	CTEST0_REG_700
+#define CTEST1_REG	CTEST1_REG_700
+#define CTEST2_REG	CTEST2_REG_700
+#define CTEST3_REG	CTEST3_REG_700
+#define CTEST4_REG	CTEST4_REG_700
+#define CTEST5_REG	CTEST5_REG_700
+#define CTEST6_REG	CTEST6_REG_700
+#define SODL_REG	SODL_REG_700
+#define SBDL_REG	SBDL_REG_700
+#define SIDL_REG	SIDL_REG_700
+#define LCRC_REG	LCRC_REG_10
 
 #ifdef MEM_MAPPED
 #define NCR_read8(address) 					\
diff -urN linux-2.4.19-pre8/drivers/scsi/sim710.scr linux-2.4.19-pre9/drivers/scsi/sim710.scr
--- linux-2.4.19-pre8/drivers/scsi/sim710.scr	Thu Oct  7 10:17:09 1999
+++ linux-2.4.19-pre9/drivers/scsi/sim710.scr	Tue May 28 16:02:29 2002
@@ -15,15 +15,12 @@
 
 ABSOLUTE reselected_identify = 0
 ABSOLUTE msgin_buf = 0
+ABSOLUTE msg_reject = 0
+ABSOLUTE test1_src = 0
+ABSOLUTE test1_dst = 0
 
 /* Interrupt values passed back to driver */
 
-ABSOLUTE int_bad_extmsg1a	= 0xab930000
-ABSOLUTE int_bad_extmsg1b	= 0xab930001
-ABSOLUTE int_bad_extmsg2a	= 0xab930002
-ABSOLUTE int_bad_extmsg2b	= 0xab930003
-ABSOLUTE int_bad_extmsg3a	= 0xab930004
-ABSOLUTE int_bad_extmsg3b	= 0xab930005
 ABSOLUTE int_bad_msg1		= 0xab930006
 ABSOLUTE int_bad_msg2		= 0xab930007
 ABSOLUTE int_bad_msg3		= 0xab930008
@@ -47,9 +44,9 @@
 ABSOLUTE int_disc2		= 0xab93001a
 ABSOLUTE int_disc3		= 0xab93001b
 ABSOLUTE int_not_rej		= 0xab93001c
+ABSOLUTE int_test1		= 0xab93001d
 
-
-/* Bit field settings used to record status in SCRATCH */
+/* Bit field settings used to record status in SCRATCH0 */
 
 ABSOLUTE had_select	= 0x01
 ABSOLUTE had_msgout	= 0x02
@@ -60,6 +57,9 @@
 ABSOLUTE had_msgin	= 0x40
 ABSOLUTE had_extmsg	= 0x80
 
+/* Bit field settings used to record status in SCRATCH1 */
+
+ABSOLUTE did_reject	= 0x01
 
 /* These scripts are heavily based on the examples in the NCR 53C710
  * Programmer's Guide (Preliminary).
@@ -68,7 +68,6 @@
 ENTRY do_select
 do_select:
 	CLEAR TARGET
-	MOVE SCRATCH0 & 0 TO SCRATCH0
 	; Enable selection timer
 	MOVE CTEST7 & 0xef TO CTEST7
 	SELECT ATN FROM dsa_select, reselect
@@ -401,17 +400,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg1a, IF 0x03
-	INT int_bad_extmsg1a
-ext_msg1a:
+	JUMP reject_msg1, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg1b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg1b
-ext_msg1b:
+	JUMP reject_msg1, IF NOT 0x01	; Only handle SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr1
+reject_msg1:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg1a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg1
+reject_msg1a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin1
 disc1:
 	CLEAR ACK
 ENTRY wait_disc1
@@ -446,17 +451,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg2a, IF 0x03
-	INT int_bad_extmsg2a
-ext_msg2a:
+	JUMP reject_msg2, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg2b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg2b
-ext_msg2b:
+	JUMP reject_msg2, IF NOT 0x01	; Only handle SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr2
+reject_msg2:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg2a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg2
+reject_msg2a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin2
 disc2:
 	CLEAR ACK
 ENTRY wait_disc2
@@ -491,17 +502,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg3a, IF 0x03
-	INT int_bad_extmsg3a
-ext_msg3a:
+	JUMP reject_msg3, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg3b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg3b
-ext_msg3b:
+	JUMP reject_msg3, IF NOT 0x01	; Only handle  SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr3
+reject_msg3:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg3a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg3
+reject_msg3a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin3
 disc3:
 	CLEAR ACK
 ENTRY wait_disc3
@@ -552,3 +569,8 @@
 selected:
 	INT int_selected
 
+ENTRY test1
+test1:
+	MOVE MEMORY 4, test1_src, test1_dst
+	INT int_test1
+
diff -urN linux-2.4.19-pre8/drivers/scsi/sim710_u.h linux-2.4.19-pre9/drivers/scsi/sim710_u.h
--- linux-2.4.19-pre8/drivers/scsi/sim710_u.h	Thu Oct  7 10:17:09 1999
+++ linux-2.4.19-pre9/drivers/scsi/sim710_u.h	Tue May 28 16:02:29 2002
@@ -1,3 +1,4 @@
+#undef A_did_reject
 #undef A_dsa_cmnd
 #undef A_dsa_datain
 #undef A_dsa_dataout
@@ -14,12 +15,6 @@
 #undef A_had_msgout
 #undef A_had_select
 #undef A_had_status
-#undef A_int_bad_extmsg1a
-#undef A_int_bad_extmsg1b
-#undef A_int_bad_extmsg2a
-#undef A_int_bad_extmsg2b
-#undef A_int_bad_extmsg3a
-#undef A_int_bad_extmsg3b
 #undef A_int_bad_msg1
 #undef A_int_bad_msg2
 #undef A_int_bad_msg3
@@ -43,8 +38,12 @@
 #undef A_int_sel_not_cmd
 #undef A_int_selected
 #undef A_int_status_not_msgin
+#undef A_int_test1
+#undef A_msg_reject
 #undef A_msgin_buf
 #undef A_reselected_identify
+#undef A_test1_dst
+#undef A_test1_src
 #undef Ent_do_select
 #undef Ent_done_ident
 #undef Ent_end_data_trans
@@ -61,6 +60,7 @@
 #undef Ent_resume_msgin3b
 #undef Ent_resume_pmm
 #undef Ent_resume_rej_ident
+#undef Ent_test1
 #undef Ent_wait_disc1
 #undef Ent_wait_disc2
 #undef Ent_wait_disc3
diff -urN linux-2.4.19-pre8/drivers/sound/Makefile linux-2.4.19-pre9/drivers/sound/Makefile
--- linux-2.4.19-pre8/drivers/sound/Makefile	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/Makefile	Tue May 28 16:02:30 2002
@@ -75,7 +75,6 @@
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
 obj-$(CONFIG_SOUND_BT878)	+= btaudio.o
-obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
 obj-$(CONFIG_SOUND_IT8172)	+= ite8172.o ac97_codec.o
 
 ifeq ($(CONFIG_MIDI_EMU10K1),y)
diff -urN linux-2.4.19-pre8/drivers/sound/ac97_codec.c linux-2.4.19-pre9/drivers/sound/ac97_codec.c
--- linux-2.4.19-pre8/drivers/sound/ac97_codec.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/ac97_codec.c	Tue May 28 16:02:30 2002
@@ -120,6 +120,7 @@
 	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
 	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
 	{0x414C4710, "ALC200/200P",		&null_ops},
+	{0x414C4720, "ALC650",			&null_ops},
 	{0x43525900, "Cirrus Logic CS4297",	&default_ops},
 	{0x43525903, "Cirrus Logic CS4297",	&default_ops},
 	{0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
@@ -151,6 +152,7 @@
 	{0x83847609, "SigmaTel STAC9721/23",	&sigmatel_9721_ops},
 	{0x83847644, "SigmaTel STAC9744/45",	&sigmatel_9744_ops},
 	{0x83847656, "SigmaTel STAC9756/57",	&sigmatel_9744_ops},
+	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
 	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
 	{0x57454301, "Winbond 83971D",		&null_ops},
 };
diff -urN linux-2.4.19-pre8/drivers/sound/ad1816.c linux-2.4.19-pre9/drivers/sound/ad1816.c
--- linux-2.4.19-pre8/drivers/sound/ad1816.c	Fri Nov  9 15:22:54 2001
+++ linux-2.4.19-pre9/drivers/sound/ad1816.c	Tue May 28 16:02:30 2002
@@ -1318,26 +1318,13 @@
 	return(ad1816_dev);
 }
 
-static struct ad1816_data {
-	struct pci_dev * (*initfunc)(struct pci_bus*, struct pci_dev *, struct address_info *);
-	char *name;
-} ad1816_pnp_data[] __initdata = {
-	{ &ad1816_init_generic, "Analog Devices 1815" },
-	{ &ad1816_init_generic, "Analog Devices 1816A" }
-};
-
-static struct {
-	unsigned short card_vendor, card_device;
-	unsigned short vendor;
-	unsigned short function;
-	struct ad1816_data *data;
-} isapnp_ad1816_list[] __initdata = {
+struct isapnp_device_id isapnp_ad1816_list[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7150), 
-		&ad1816_pnp_data[0] },
+		0 },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7180),
-		&ad1816_pnp_data[1] },
+		0 },
 	{0}
 };
 
@@ -1346,27 +1333,22 @@
 static int __init ad1816_init_isapnp(struct address_info *hw_config,
 	struct pci_bus *bus, struct pci_dev *card, int slot)
 {
+	char *busname = bus->name[0] ? bus->name : "Analog Devices AD1816a";
 	struct pci_dev *idev = NULL;
-	
-	/* You missed the init func? That's bad. */
-	if(isapnp_ad1816_list[slot].data->initfunc) {
-		char *busname = bus->name[0] ? bus->name : isapnp_ad1816_list[slot].data->name;
 		
-		printk(KERN_INFO "ad1816: %s detected\n", busname);
+	printk(KERN_INFO "ad1816: %s detected\n", busname);
 		
-		/* Initialize this baby. */
-		if((idev = isapnp_ad1816_list[slot].data->initfunc(bus, card, hw_config))) {
-			/* We got it. */
+	/* Initialize this baby. */
+	if ((idev = ad1816_init_generic(bus, card, hw_config))) {
+		/* We got it. */
 
-			printk(KERN_NOTICE "ad1816: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
-				busname,
-				hw_config->io_base, hw_config->irq, hw_config->dma,
-				hw_config->dma2);
-			return 1;
-		} else
-			printk(KERN_INFO "ad1816: Failed to initialize %s\n", busname);
+		printk(KERN_NOTICE "ad1816: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
+			busname,
+			hw_config->io_base, hw_config->irq, hw_config->dma,
+			hw_config->dma2);
+		return 1;
 	} else
-		printk(KERN_ERR "ad1816: Bad entry in ad1816.c PnP table\n");
+		printk(KERN_INFO "ad1816: Failed to initialize %s\n", busname);
 	
 	return 0;
 }
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/audio.c linux-2.4.19-pre9/drivers/sound/emu10k1/audio.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/audio.c	Mon Feb 25 11:38:06 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/audio.c	Tue May 28 16:02:30 2002
@@ -1365,6 +1365,13 @@
 
 	buffer->fragment_size = 1 << buffer->ossfragshift;
 
+	while (buffer->fragment_size * WAVEOUT_MINFRAGS > WAVEOUT_MAXBUFSIZE)
+		buffer->fragment_size >>= 1;
+
+	/* now we are sure that:
+	 (2^WAVEOUT_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEOUT_MAXBUFSIZE / WAVEOUT_MINFRAGS)
+	*/
+
 	if (!buffer->numfrags) {
 		u32 numfrags;
 
@@ -1379,19 +1386,14 @@
 		}
 	}
 
-	if (buffer->numfrags < MINFRAGS)
-		buffer->numfrags = MINFRAGS;
+	if (buffer->numfrags < WAVEOUT_MINFRAGS)
+		buffer->numfrags = WAVEOUT_MINFRAGS;
 
-	if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) {
+	if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE)
 		buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size;
 
-		if (buffer->numfrags < MINFRAGS) {
-			buffer->numfrags = MINFRAGS;
-			buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
-		}
-
-	} else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE)
-		buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size;
+	if (buffer->numfrags < WAVEOUT_MINFRAGS)
+		BUG();
 
 	buffer->size = buffer->fragment_size * buffer->numfrags;
 	buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
@@ -1425,24 +1427,29 @@
 
 	buffer->fragment_size = 1 << buffer->ossfragshift;
 
+	while (buffer->fragment_size * WAVEIN_MINFRAGS > WAVEIN_MAXBUFSIZE)
+		buffer->fragment_size >>= 1;
+
+	/* now we are sure that:
+	   (2^WAVEIN_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEIN_MAXBUFSIZE / WAVEIN_MINFRAGS)
+        */
+
+
 	if (!buffer->numfrags)
 		buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;
 
-	if (buffer->numfrags < MINFRAGS)
-		buffer->numfrags = MINFRAGS;
+	if (buffer->numfrags < WAVEIN_MINFRAGS)
+		buffer->numfrags = WAVEIN_MINFRAGS;
 
-	if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) {
+	if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE)
 		buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size;
 
-		if (buffer->numfrags < MINFRAGS) {
-			buffer->numfrags = MINFRAGS;
-			buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
-		}
-	} else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE)
-		buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size;
+	if (buffer->numfrags < WAVEIN_MINFRAGS)
+		BUG();
 
 	bufsize = buffer->fragment_size * buffer->numfrags;
 
+	/* the buffer size for recording is restricted to certain values, adjust it now */
 	if (bufsize >= 0x10000) {
 		buffer->size = 0x10000;
 		buffer->sizeregval = 0x1f;
@@ -1468,10 +1475,12 @@
 		}
 	}
 
+	/* adjust the fragment size so that buffer size is an integer multiple */
+	while (buffer->size % buffer->fragment_size)
+		buffer->fragment_size >>= 1;
+
 	buffer->numfrags = buffer->size / buffer->fragment_size;
 	buffer->pages =  buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
-	if (buffer->size % buffer->fragment_size)
-		BUG();
 
 	DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size);
 	DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags);
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/audio.h linux-2.4.19-pre9/drivers/sound/emu10k1/audio.h
--- linux-2.4.19-pre8/drivers/sound/emu10k1/audio.h	Mon Feb 25 11:38:06 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/audio.h	Tue May 28 16:02:30 2002
@@ -33,8 +33,6 @@
 #ifndef _AUDIO_H
 #define _AUDIO_H
 
-#define MINFRAGS	3	/* _don't_ go bellow 3 */
-
 struct emu10k1_wavedevice
 {
         struct emu10k1_card *card;
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/cardwi.h linux-2.4.19-pre9/drivers/sound/emu10k1/cardwi.h
--- linux-2.4.19-pre8/drivers/sound/emu10k1/cardwi.h	Fri Aug 10 21:02:18 2001
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/cardwi.h	Tue May 28 16:02:30 2002
@@ -69,13 +69,14 @@
 	u16 fxwc;
 };
 
-#define WAVEIN_MAXBUFSIZE         65536
-#define WAVEIN_MINBUFSIZE	  368
+#define WAVEIN_MAXBUFSIZE	65536
+#define WAVEIN_MINBUFSIZE	368
 
-#define WAVEIN_DEFAULTFRAGLEN     100 
-#define WAVEIN_DEFAULTBUFLEN      1000
+#define WAVEIN_DEFAULTFRAGLEN	100 
+#define WAVEIN_DEFAULTBUFLEN	1000
 
-#define WAVEIN_MINFRAGSHIFT   	  8 
+#define WAVEIN_MINFRAGSHIFT	8 
+#define WAVEIN_MINFRAGS		2
 
 int emu10k1_wavein_open(struct emu10k1_wavedevice *);
 void emu10k1_wavein_close(struct emu10k1_wavedevice *);
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/cardwo.h linux-2.4.19-pre9/drivers/sound/emu10k1/cardwo.h
--- linux-2.4.19-pre8/drivers/sound/emu10k1/cardwo.h	Mon Feb 25 11:38:06 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/cardwo.h	Tue May 28 16:02:30 2002
@@ -39,13 +39,13 @@
 
 /* setting this to other than a power of two may break some applications */
 #define WAVEOUT_MAXBUFSIZE	MAXBUFSIZE
-#define WAVEOUT_MINBUFSIZE	64
 
 #define WAVEOUT_DEFAULTFRAGLEN	20 /* Time to play a fragment in ms (latency) */
 #define WAVEOUT_DEFAULTBUFLEN	500 /* Time to play the entire buffer in ms */
 
-#define WAVEOUT_MINFRAGSHIFT	6
-#define WAVEOUT_MAXVOICES 6
+#define WAVEOUT_MINFRAGSHIFT	6 /* Minimum fragment size in bytes is 2^6 */
+#define WAVEOUT_MINFRAGS	3 /* _don't_ go bellow 3, it would break silence filling */
+#define WAVEOUT_MAXVOICES	6
 
 struct waveout_buffer {
 	u16 ossfragshift;
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/efxmgr.c linux-2.4.19-pre9/drivers/sound/emu10k1/efxmgr.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/efxmgr.c	Mon Feb 25 11:38:06 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/efxmgr.c	Tue May 28 16:02:30 2002
@@ -38,7 +38,7 @@
         struct dsp_patch *patch;
 	struct dsp_rpatch *rpatch;
 	char s[PATCH_NAME_SIZE + 4];
-	u32 *gpr_used;
+	unsigned long *gpr_used;
 	int i;
 
 	DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name, gpr_name);
@@ -103,7 +103,7 @@
 
 	card->ac97.mixer_state[oss_mixer] = (right << 8) | left;
 
-	if (!card->isaps)
+	if (!card->is_aps)
 		card->ac97.write_mixer(&card->ac97, oss_mixer, left, right);
 	
 	emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left,
@@ -171,7 +171,6 @@
 {
 	struct patch_manager *mgr = &card->mgr;
 	unsigned long flags;
-	int muting;
 
 	static const s32 log2lin[4] ={           //  attenuation (dB)
 		0x7fffffff,                      //       0.0         
@@ -183,12 +182,10 @@
 	if (addr < 0)
 		return;
 
-	muting = (scale == 0x10) ? 0x7f: scale;
-	
 	vol = (100 - vol ) * scale / 100;
 
 	// Thanks to the comp.dsp newsgroup for this neat trick:
-	vol = (vol >= muting) ? 0 : (log2lin[vol & 3] >> (vol >> 2));
+	vol = (vol >= scale) ? 0 : (log2lin[vol & 3] >> (vol >> 2));
 
 	spin_lock_irqsave(&mgr->lock, flags);
 	emu10k1_set_control_gpr(card, addr, vol, 0);
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/efxmgr.h linux-2.4.19-pre9/drivers/sound/emu10k1/efxmgr.h
--- linux-2.4.19-pre8/drivers/sound/emu10k1/efxmgr.h	Tue Oct  9 10:53:18 2001
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/efxmgr.h	Tue May 28 16:02:30 2002
@@ -35,9 +35,9 @@
 #define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
 
 #define OP(op, z, w, x, y) \
-        do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
-        WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
-        ++pc; } while (0)
+	do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
+	WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
+	++pc; } while (0)
 
 #define NUM_INPUTS 0x20
 #define NUM_OUTPUTS 0x20
@@ -47,52 +47,52 @@
 
 struct dsp_rpatch {
 	char name[PATCH_NAME_SIZE];
-        u16 code_start;
-        u16 code_size;
+	u16 code_start;
+	u16 code_size;
 
-        u32 gpr_used[NUM_GPRS / 32];
-        u32 gpr_input[NUM_GPRS / 32];
-        u32 route[NUM_OUTPUTS];
-        u32 route_v[NUM_OUTPUTS];
+	unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
+	unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
+	unsigned long route[NUM_OUTPUTS];
+	unsigned long route_v[NUM_OUTPUTS];
 };
 
 struct dsp_patch {
-        char name[PATCH_NAME_SIZE];
-        u8 id;
-        u32 input;                      /* bitmap of the lines used as inputs */
-	u32 output;                     /* bitmap of the lines used as outputs */
-        u16 code_start;
-        u16 code_size;
-
-        u32 gpr_used[NUM_GPRS / 32];    /* bitmap of used gprs */
-        u32 gpr_input[NUM_GPRS / 32];
-        u8 traml_istart;  /* starting address of the internal tram lines used */
-        u8 traml_isize;   /* number of internal tram lines used */
-
-        u8 traml_estart;
-        u8 traml_esize;
-
-        u16 tramb_istart;        /* starting address of the internal tram memory used */
-        u16 tramb_isize;         /* amount of internal memory used */
-        u32 tramb_estart;
-        u32 tramb_esize;
+	char name[PATCH_NAME_SIZE];
+	u8 id;
+	unsigned long input;	/* bitmap of the lines used as inputs */
+	unsigned long output;	/* bitmap of the lines used as outputs */
+	u16 code_start;
+	u16 code_size;
+
+	unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];	/* bitmap of used gprs */
+	unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
+	u8 traml_istart;	/* starting address of the internal tram lines used */
+	u8 traml_isize;		/* number of internal tram lines used */
+
+	u8 traml_estart;
+	u8 traml_esize;
+
+	u16 tramb_istart;        /* starting address of the internal tram memory used */
+	u16 tramb_isize;         /* amount of internal memory used */
+	u32 tramb_estart;
+	u32 tramb_esize;
 };
 
 struct dsp_gpr {
-        u8 type;                      /* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */
-        char name[GPR_NAME_SIZE];       /* gpr value, only valid for control gprs */
-        s32 min, max;         /* value range for this gpr, only valid for control gprs */
-        u8 line;                    /* which input/output line is the gpr attached, only valid for input/output gprs */
-        u8 usage;
+	u8 type;			/* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */
+	char name[GPR_NAME_SIZE];	/* gpr value, only valid for control gprs */
+	s32 min, max;			/* value range for this gpr, only valid for control gprs */
+	u8 line;			/* which input/output line is the gpr attached, only valid for input/output gprs */
+	u8 usage;
 };
 
 enum {
-        GPR_TYPE_NULL = 0,
-        GPR_TYPE_IO,
-        GPR_TYPE_STATIC,
-        GPR_TYPE_DYNAMIC,
-        GPR_TYPE_CONTROL,
-        GPR_TYPE_CONSTANT
+	GPR_TYPE_NULL = 0,
+	GPR_TYPE_IO,
+	GPR_TYPE_STATIC,
+	GPR_TYPE_DYNAMIC,
+	GPR_TYPE_CONTROL,
+	GPR_TYPE_CONSTANT
 };
 
 #define GPR_BASE 0x100
@@ -101,15 +101,14 @@
 #define MAX_PATCHES_PAGES 32
 
 struct patch_manager {
-        void *patch[MAX_PATCHES_PAGES];
+	void *patch[MAX_PATCHES_PAGES];
 	int current_pages;
-        struct dsp_rpatch rpatch;
-        struct dsp_gpr gpr[NUM_GPRS];   /* gpr usage table */
+	struct dsp_rpatch rpatch;
+	struct dsp_gpr gpr[NUM_GPRS];   /* gpr usage table */
 	spinlock_t lock;
 	s16 ctrl_gpr[SOUND_MIXER_NRDEVICES][2];
 };
 
-
 #define PATCHES_PER_PAGE (PAGE_SIZE / sizeof(struct dsp_patch))
 
 #define PATCH(mgr, i) ((struct dsp_patch *) (mgr)->patch[(i) / PATCHES_PER_PAGE] + (i) % PATCHES_PER_PAGE)
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/hwaccess.h linux-2.4.19-pre9/drivers/sound/emu10k1/hwaccess.h
--- linux-2.4.19-pre8/drivers/sound/emu10k1/hwaccess.h	Mon Feb 25 11:38:06 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/hwaccess.h	Tue May 28 16:02:30 2002
@@ -182,7 +182,7 @@
 
 	u8 chiprev;                    /* Chip revision                */
 
-	int isaps;
+	u8 is_aps;
 
 	struct patch_manager mgr;
 	struct pt_data pt;
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/main.c linux-2.4.19-pre9/drivers/sound/emu10k1/main.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/main.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/main.c	Tue May 28 16:02:30 2002
@@ -78,7 +78,9 @@
  *          Cleaned up poll() functions (audio and midi). Don't start input.
  *	    Restrict DMA pages used to 512Mib range.
  *	    New AC97_BOOST mixer ioctl.
- *
+ *     0.19 Real fix for kernel with highmem support (cast dma_handle to u32)
+ *	    Fix recording buffering parameters calculation
+ *	    Use unsigned long for variables in bit ops.
  *********************************************************************/
 
 /* These are only included once per module */
@@ -111,7 +113,7 @@
 #define SNDCARD_EMU10K1 46
 #endif
  
-#define DRIVER_VERSION "0.18"
+#define DRIVER_VERSION "0.19"
 
 /* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */
 #define EMU10K1_DMA_MASK                0x1fffffff	/* DMA buffer mask for pci_alloc_consist */
@@ -196,7 +198,7 @@
 
 	/* Assign default recording parameters */
 	/* FIXME */
-	if(card->isaps)
+	if (card->is_aps)
 		card->wavein.recsrc = WAVERECORD_FX;
 	else
 		card->wavein.recsrc = WAVERECORD_AC97;
@@ -229,7 +231,7 @@
 
 	card->ac97.private_data = card;
 
-	if (!card->isaps) {
+	if (!card->is_aps) {
 		card->ac97.id = 0;
 		card->ac97.codec_read = emu10k1_ac97_read;
         	card->ac97.codec_write = emu10k1_ac97_write;
@@ -287,7 +289,7 @@
 {
 	char s[32];
 
-	if (!card->isaps) {
+	if (!card->is_aps) {
 		sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
 		remove_proc_entry(s, NULL);
 
@@ -867,19 +869,19 @@
 	}
 
 	for (pagecount = 0; pagecount < MAXPAGES; pagecount++)
-		((u32 *) card->virtualpagetable.addr)[pagecount] = cpu_to_le32(((u32)card->silentpage.dma_handle * 2) | pagecount);
+		((u32 *) card->virtualpagetable.addr)[pagecount] = cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pagecount);
 
 	/* Init page table & tank memory base register */
 	sblive_writeptr_tag(card, 0,
-			    PTB, (u32)card->virtualpagetable.dma_handle,
+			    PTB, (u32) card->virtualpagetable.dma_handle,
 			    TCB, 0,
 			    TCBS, 0,
 			    TAGLIST_END);
 
 	for (nCh = 0; nCh < NUM_G; nCh++) {
 		sblive_writeptr_tag(card, nCh,
-				    MAPA, MAP_PTI_MASK |( (u32)card->silentpage.dma_handle * 2),
-				    MAPB, MAP_PTI_MASK |( (u32)card->silentpage.dma_handle * 2),
+				    MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
+				    MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
 				    TAGLIST_END);
 	}
 
@@ -1059,7 +1061,7 @@
 		card->iobase + card->length - 1, card->irq);
 
 	pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
-	card->isaps = (subsysvid == EMU_APS_SUBID);
+	card->is_aps = (subsysvid == EMU_APS_SUBID);
 
 	spin_lock_init(&card->lock);
 	init_MUTEX(&card->open_sem);
@@ -1090,7 +1092,7 @@
 		goto err_emu10k1_init;
 	}
 
-	if (card->isaps)
+	if (card->is_aps)
 		emu10k1_ecard_init(card);
 
 	list_add(&card->list, &emu10k1_devs);
@@ -1135,7 +1137,7 @@
 	pci_set_drvdata(pci_dev, NULL);
 }
 
-MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)");
+MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@lists.sourceforge.net)");
 MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd.");
 MODULE_LICENSE("GPL");
 
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/mixer.c linux-2.4.19-pre9/drivers/sound/emu10k1/mixer.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/mixer.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/mixer.c	Tue May 28 16:02:30 2002
@@ -251,7 +251,7 @@
 		case CMD_SETRECSRC:
 			switch (ctl->val[0]) {
 			case WAVERECORD_AC97:
-				if (card->isaps) {
+				if (card->is_aps) {
 					ret = -EINVAL;
 					break;
 				}
@@ -455,7 +455,7 @@
 
 			card->mgr.ctrl_gpr[id][ch] = addr;
 
-			if (card->isaps)
+			if (card->is_aps)
 				break;
 
 			if (addr >= 0) {
@@ -558,7 +558,7 @@
 
 				card->tankmem.size = size;
 
-				sblive_writeptr_tag(card, 0, TCB,(u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
+				sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
 
 				emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
 			}
@@ -621,7 +621,7 @@
 	unsigned int oss_mixer = _IOC_NR(cmd);
 	
 	ret = -EINVAL;
-	if (!card->isaps) {
+	if (!card->is_aps) {
 		if (cmd == SOUND_MIXER_INFO) {
 			mixer_info info;
 
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/recmgr.c linux-2.4.19-pre9/drivers/sound/emu10k1/recmgr.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/recmgr.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/recmgr.c	Tue May 28 16:02:30 2002
@@ -130,9 +130,9 @@
 		break;
 	}
 
-	DPD(2, "bus addx: %#lx\n", (unsigned long) buffer->dma_handle);
+	DPD(2, "bus addx: %#x\n", (u32) buffer->dma_handle);
 
-	sblive_writeptr(card, buffer->addrreg, 0, (u32)buffer->dma_handle);
+	sblive_writeptr(card, buffer->addrreg, 0, (u32) buffer->dma_handle);
 
 	return;
 }
diff -urN linux-2.4.19-pre8/drivers/sound/emu10k1/voicemgr.c linux-2.4.19-pre9/drivers/sound/emu10k1/voicemgr.c
--- linux-2.4.19-pre8/drivers/sound/emu10k1/voicemgr.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/sound/emu10k1/voicemgr.c	Tue May 28 16:02:30 2002
@@ -43,7 +43,7 @@
 int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
 {
 	u32 pageindex, pagecount;
-	unsigned long busaddx;
+	u32 busaddx;
 	int i;
 
 	DPD(2, "requested pages is: %d\n", pages);
@@ -66,9 +66,9 @@
 		DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
 
 		for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
-			busaddx = (u32)(mem->dma_handle[pagecount]) + i * EMUPAGESIZE;
+			busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
 
-			DPD(3, "Bus Addx: %#lx\n", busaddx);
+			DPD(3, "Bus Addx: %#x\n", busaddx);
 
 			pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
 
@@ -102,7 +102,7 @@
 		for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
 			pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
 			((u32 *) card->virtualpagetable.addr)[pageindex] =
-				cpu_to_le32(((u32)card->silentpage.dma_handle * 2) | pageindex);
+				cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pageindex);
 		}
 	}
 
@@ -231,8 +231,8 @@
 				    Z1, 0,
 				    Z2, 0,
 				    /* Invalidate maps */
-				    MAPA, MAP_PTI_MASK | ((u32)card->silentpage.dma_handle * 2),
-				    MAPB, MAP_PTI_MASK | ((u32)card->silentpage.dma_handle * 2),
+				    MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
+				    MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
 				/* modulation envelope */
 				    CVCF, 0x0000ffff,
 				    VTFT, 0x0000ffff,
diff -urN linux-2.4.19-pre8/drivers/usb/Config.in linux-2.4.19-pre9/drivers/usb/Config.in
--- linux-2.4.19-pre8/drivers/usb/Config.in	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/Config.in	Tue May 28 16:02:30 2002
@@ -101,5 +101,6 @@
    comment 'USB Miscellaneous drivers'
    dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
 fi
 endmenu
diff -urN linux-2.4.19-pre8/drivers/usb/Makefile linux-2.4.19-pre9/drivers/usb/Makefile
--- linux-2.4.19-pre8/drivers/usb/Makefile	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/Makefile	Tue May 28 16:02:30 2002
@@ -92,6 +92,7 @@
 obj-$(CONFIG_USB_BLUETOOTH)	+= bluetooth.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
+obj-$(CONFIG_USB_BRLVGER)	+= brlvger.o
 
 # Object files in subdirectories
 mod-subdirs	:= serial hcd
diff -urN linux-2.4.19-pre8/drivers/usb/brlvger.c linux-2.4.19-pre9/drivers/usb/brlvger.c
--- linux-2.4.19-pre8/drivers/usb/brlvger.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre9/drivers/usb/brlvger.c	Tue May 28 16:02:30 2002
@@ -0,0 +1,1034 @@
+/*
+ *      Tieman Voyager braille display USB driver.
+ *
+ *      Copyright 2001-2002 Stephane Dalton <sdalton@videotron.ca>
+ *                      and Stéphane Doyon  <s.doyon@videotron.ca>
+ *            Maintained by Stéphane Doyon  <s.doyon@videotron.ca>.
+ */
+/*
+ *  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
+ */
+/* History:
+ * 0.8 April 2002: Integration into the kernel tree.
+ * 0.7 October 2001: First public release as a module, distributed with
+ *     the BRLTTY package (beta versions around 2.99y).
+ */
+
+#define DRIVER_VERSION "v0.8"
+#define DATE "April 2002"
+#define DRIVER_AUTHOR \
+	"Stephane Dalton <sdalton@videotron.ca> " \
+	"and Stéphane Doyon <s.doyon@videotron.ca>"
+#define DRIVER_DESC "Tieman Voyager braille display USB driver for Linux 2.4"
+#define DRIVER_SHORTDESC "Voyager"
+
+#define BANNER \
+	KERN_INFO DRIVER_SHORTDESC " " DRIVER_VERSION " (" DATE ")\n" \
+	KERN_INFO "   by " DRIVER_AUTHOR "\n"
+
+static const char longbanner[] = {
+	DRIVER_DESC ", " DRIVER_VERSION " (" DATE "), by " DRIVER_AUTHOR
+};
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/poll.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/brlvger.h>
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+/* Module parameters */
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level, 0-3");
+
+static int write_repeats = 2;
+MODULE_PARM(write_repeats, "i");
+MODULE_PARM_DESC(write_repeats, "Hack: repetitions for command to "
+		 "display braille pattern");
+		 /* to get rid of weird extra dots (perhaps only on
+		    early hardware versions?) */
+
+static int stall_tries = 3;
+MODULE_PARM(stall_tries, "i");
+MODULE_PARM_DESC(stall_tries, "Hack: retransmits of stalled USB "
+		 "control messages");
+                 /* broken early hardware versions? */
+
+#define BRLVGER_RAW_VOLTAGE 89
+/* from 0->300V to 255->200V, we are told 265V is normal operating voltage,
+   but we don't know the scale. Assuming it is linear. */
+static int raw_voltage = BRLVGER_RAW_VOLTAGE;
+MODULE_PARM(raw_voltage, "i");
+MODULE_PARM_DESC(raw_voltage, "Parameter for the call to SET_DISPLAY_VOLTAGE");
+
+
+/* protocol and display type defines */
+#define MAX_BRLVGER_CELLS 72
+#define MAX_INTERRUPT_DATA 8
+/* control message request types */
+#define BRLVGER_READ_REQ 0xC2
+#define BRLVGER_WRITE_REQ 0x42
+/* control message request codes */
+#define BRLVGER_SET_DISPLAY_ON 0
+#define BRLVGER_SET_DISPLAY_VOLTAGE 1
+#define BRLVGER_GET_SERIAL 3
+#define BRLVGER_GET_HWVERSION 4
+#define BRLVGER_GET_FWVERSION 5
+#define BRLVGER_GET_LENGTH 6
+#define BRLVGER_SEND_BRAILLE 7
+#define BRLVGER_BEEP 9
+#if 0 /* not used and not sure they're working */
+#define BRLVGER_GET_DISPLAY_VOLTAGE 2
+#define BRLVGER_GET_CURRENT 8
+#endif
+
+/* Prototypes */
+static void *brlvger_probe (struct usb_device *dev, unsigned ifnum,
+			    const struct usb_device_id *id);
+static void brlvger_disconnect(struct usb_device *dev, void *ptr);
+static int brlvger_open(struct inode *inode, struct file *file);
+static int brlvger_release(struct inode *inode, struct file *file);
+static ssize_t brlvger_write(struct file *file, const char *buffer,
+			     size_t count, loff_t *pos);
+static ssize_t brlvger_read(struct file *file, char *buffer,
+			    size_t count, loff_t *unused_pos);
+static int brlvger_ioctl(struct inode *inode, struct file *file,
+			 unsigned cmd, unsigned long arg);
+static unsigned brlvger_poll(struct file *file, poll_table *wait);
+static loff_t brlvger_llseek(struct file * file, loff_t offset, int orig);
+static void intr_callback(struct urb *urb);
+struct brlvger_priv;
+static int brlvger_get_hw_version(struct brlvger_priv *priv,
+				  unsigned char *verbuf);
+static int brlvger_get_fw_version(struct brlvger_priv *priv,
+				  unsigned char *buf);
+static int brlvger_get_serial(struct brlvger_priv *priv,
+			      unsigned char *buf);
+static int brlvger_get_display_length(struct brlvger_priv *priv);
+static int brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on);
+static int brlvger_beep(struct brlvger_priv *priv, __u16 duration);
+static int brlvger_set_display_voltage(struct brlvger_priv *priv,
+				       __u16 voltage);
+static int mycontrolmsg(const char *funcname,
+                        struct brlvger_priv *priv, unsigned pipe_dir,
+                        __u8 request, __u8 requesttype, __u16 value,
+                        __u16 index, void *data, __u16 size);
+
+#define controlmsg(priv,pipe_dir,a,b,c,d,e,f) \
+     mycontrolmsg(__FUNCTION__, priv, pipe_dir, \
+                  a,b,c,d,e,f)
+#define sndcontrolmsg(priv,a,b,c,d,e,f) \
+    controlmsg(priv, 0, a,b,c,d,e,f)
+#define rcvcontrolmsg(priv,a,b,c,d,e,f) \
+    controlmsg(priv, USB_DIR_IN, a,b,c,d,e,f)
+
+extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
+
+/* ----------------------------------------------------------------------- */
+
+/* Data */
+
+/* key event queue size */
+#define MAX_INTERRUPT_BUFFER 10
+
+/* private state */
+struct brlvger_priv {
+	struct usb_device   *dev; /* USB device handle */
+	struct usb_endpoint_descriptor *in_interrupt;
+	struct urb *intr_urb;
+	devfs_handle_t devfs;
+
+	int subminor; /* which minor dev #? */
+
+	unsigned char hwver[BRLVGER_HWVER_SIZE]; /* hardware version */
+	unsigned char fwver[BRLVGER_FWVER_SIZE]; /* firmware version */
+	unsigned char serialnum[BRLVGER_SERIAL_SIZE];
+
+	int llength; /* logical length */
+	int plength; /* physical length */
+
+	__u8 obuf[MAX_BRLVGER_CELLS];
+	__u8 intr_buff[MAX_INTERRUPT_DATA];
+	__u8 event_queue[MAX_INTERRUPT_BUFFER][MAX_INTERRUPT_DATA];
+	atomic_t intr_idx, read_idx;
+	spinlock_t intr_idx_lock; /* protects intr_idx */
+	wait_queue_head_t read_wait;
+
+	int opened;
+	struct semaphore open_sem; /* protects ->opened */
+	struct semaphore dev_sem; /* protects ->dev */
+};
+
+/* Globals */
+
+/* Table of connected devices, a different minor for each. */
+static struct brlvger_priv *display_table[ MAX_NR_BRLVGER_DEVS ];
+
+/* Mutex for the operation of removing a device from display_table */
+static DECLARE_MUTEX(disconnect_sem);
+
+/* For blocking open */
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+/* Some print macros */
+#ifdef dbg
+#undef dbg
+#endif
+#ifdef info
+#undef info
+#endif
+#ifdef err
+#undef err
+#endif
+#define info(args...) \
+    ({ printk(KERN_INFO "Voyager: " args); \
+       printk("\n"); })
+#define err(args...) \
+    ({ printk(KERN_ERR "Voyager: " args); \
+       printk("\n"); })
+#define dbgprint(args...) \
+    ({ printk(KERN_DEBUG "Voyager: " __FUNCTION__ ": " args); \
+       printk("\n"); })
+#define dbg(args...) \
+    ({ if(debug >= 1) dbgprint(args); })
+#define dbg2(args...) \
+    ({ if(debug >= 2) dbgprint(args); })
+#define dbg3(args...) \
+    ({ if(debug >= 3) dbgprint(args); })
+
+/* ----------------------------------------------------------------------- */
+
+/* Driver registration */
+
+static struct usb_device_id brlvger_ids [] = {
+	{ USB_DEVICE(0x0798, 0x0001) },
+	{ }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, brlvger_ids);
+
+static struct file_operations brlvger_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		brlvger_llseek,
+	read:		brlvger_read,
+	write:		brlvger_write,
+	ioctl:		brlvger_ioctl,
+	open:		brlvger_open,
+	release:	brlvger_release,
+	poll:		brlvger_poll,
+};
+
+static struct usb_driver brlvger_driver =
+{
+	name:		"brlvger",
+	probe:		brlvger_probe,
+	disconnect:	brlvger_disconnect,
+	fops:		&brlvger_fops,
+	minor:		BRLVGER_MINOR,
+	id_table:	brlvger_ids,
+};
+
+static int
+__init brlvger_init (void)
+{
+	printk(BANNER);
+
+	if(stall_tries < 1 || write_repeats < 1)
+	  return -EINVAL;
+
+	memset(display_table, 0, sizeof(display_table));
+
+	if (usb_register(&brlvger_driver)) {
+		err("USB registration failed");
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+static void
+__exit brlvger_cleanup (void)
+{
+	usb_deregister (&brlvger_driver);
+	dbg("Driver unregistered");
+}
+
+module_init (brlvger_init);
+module_exit (brlvger_cleanup);
+
+/* ----------------------------------------------------------------------- */
+
+/* Probe and disconnect functions */
+
+static void *
+brlvger_probe (struct usb_device *dev, unsigned ifnum,
+	       const struct usb_device_id *id)
+{
+	struct brlvger_priv *priv = NULL;
+	int i;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_interface_descriptor *actifsettings;
+	/* protects against reentrance: once we've found a free slot
+	   we reserve it.*/
+	static DECLARE_MUTEX(reserve_sem);
+        char devfs_name[16];
+
+	actifsettings = dev->actconfig->interface->altsetting;
+
+	if( dev->descriptor.bNumConfigurations != 1
+			|| dev->config->bNumInterfaces != 1 
+			|| actifsettings->bNumEndpoints != 1 ) {
+		err ("Bogus braille display config info");
+		return NULL;
+	}
+
+	endpoint = actifsettings->endpoint;
+	if (!(endpoint->bEndpointAddress & 0x80) ||
+		((endpoint->bmAttributes & 3) != 0x03)) {
+		err ("Bogus braille display config info, wrong endpoints");
+		return NULL;
+	}
+
+	down(&reserve_sem);
+
+	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;
+	}
+
+	if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){
+		err("No more memory");
+		goto error;
+	}
+
+	memset(priv, 0, sizeof(*priv));
+	atomic_set(&priv->intr_idx, 0);
+	atomic_set(&priv->read_idx, MAX_INTERRUPT_BUFFER-1);
+	spin_lock_init(&priv->intr_idx_lock);
+	init_waitqueue_head(&priv->read_wait);
+	/* opened is memset'ed to 0 */
+	init_MUTEX(&priv->open_sem);
+	init_MUTEX(&priv->dev_sem);
+
+	priv->subminor = i;
+
+	/* we found a interrupt in endpoint */
+	priv->in_interrupt = endpoint;
+
+	priv->dev = dev;
+
+	if(brlvger_get_hw_version(priv, priv->hwver) <0) {
+		err("Unable to get hardware version");
+		goto error;
+	}
+	dbg("Hw ver %d.%d", priv->hwver[0], priv->hwver[1]);
+	if(brlvger_get_fw_version(priv, priv->fwver) <0) {
+		err("Unable to get firmware version");
+		goto error;
+	}
+	dbg("Fw ver: %s", priv->fwver);
+
+	if(brlvger_get_serial(priv, priv->serialnum) <0) {
+		err("Unable to get serial number");
+		goto error;
+	}
+	dbg("Serial number: %s", priv->serialnum);
+
+	if( (priv->llength = brlvger_get_display_length(priv)) <0 ){
+		err("Unable to get display length");
+		goto error;
+	}
+	switch(priv->llength) {
+	case 48:
+		priv->plength = 44;
+		break;
+	case 72:
+		priv->plength = 70;
+		break;
+	default:
+		err("Unsupported display length: %d", priv->llength);
+		goto error;
+	};
+	dbg("Display length: %d", priv->plength);
+
+	sprintf(devfs_name, "brlvger%d", priv->subminor);
+	priv->devfs = devfs_register(usb_devfs_handle, devfs_name,
+				     DEVFS_FL_DEFAULT, USB_MAJOR,
+				     BRLVGER_MINOR+priv->subminor,
+				     S_IFCHR |S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP,
+				     &brlvger_fops, NULL);
+	if (!priv->devfs) {
+#ifdef CONFIG_DEVFS_FS
+		err("devfs node registration failed");
+#endif
+	}
+
+	display_table[i] = priv;
+
+	info( "Braille display %d is device major %d minor %d",
+				i, USB_MAJOR, BRLVGER_MINOR + i);
+
+	/* Tell anyone waiting on a blocking open */
+	wake_up_interruptible(&open_wait);
+
+	goto out;
+
+ error:
+	if(priv) {
+		kfree( priv );
+		priv = NULL;
+	}
+
+ out:
+	up(&reserve_sem);
+	return priv;
+}
+
+static void
+brlvger_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct brlvger_priv *priv = (struct brlvger_priv *)ptr;
+	int r;
+
+	if(priv){
+		info("Display %d disconnecting", priv->subminor);
+
+		devfs_unregister(priv->devfs);
+		
+		down(&disconnect_sem);
+		display_table[priv->subminor] = NULL;
+		up(&disconnect_sem);
+
+		down(&priv->open_sem);
+		down(&priv->dev_sem);
+		if(priv->opened) {
+			/* Disable interrupts */
+			if((r = usb_unlink_urb(priv->intr_urb)) <0)
+				err("usb_unlink_urb returns %d", r);
+			usb_free_urb(priv->intr_urb);
+			/* mark device as dead and prevent control
+			   messages to it */
+			priv->dev = NULL;
+			/* Tell anyone hung up on a read that it
+			   won't be coming */
+			wake_up_interruptible(&priv->read_wait);
+			up(&priv->dev_sem);
+			up(&priv->open_sem);
+		}else
+			/* no corresponding up()s */
+			kfree(priv);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* fops implementation */
+
+static int
+brlvger_open(struct inode *inode, struct file *file)
+{
+	int devnum = MINOR (inode->i_rdev);
+	struct brlvger_priv *priv;
+	int n, ret;
+
+	if (devnum < BRLVGER_MINOR
+	    || devnum >= (BRLVGER_MINOR + MAX_NR_BRLVGER_DEVS))
+		return -ENXIO;
+
+	n = devnum - BRLVGER_MINOR;
+
+	MOD_INC_USE_COUNT;
+
+	do {
+		down(&disconnect_sem);
+		priv = display_table[n];
+		
+		if(!priv) {
+			up(&disconnect_sem);
+			if (file->f_flags & O_NONBLOCK) {
+				dbg3("Failing non-blocking open: "
+				     "device %d not connected", n);
+				MOD_DEC_USE_COUNT;
+				return -EAGAIN;
+			}
+			/* Blocking open. One global wait queue will
+			   suffice. We wait until a device for the selected
+			   minor is connected. */
+			dbg2("Waiting for device %d to be connected", n);
+			ret = wait_event_interruptible(open_wait,
+						       display_table[n]
+						       != NULL);
+			if(ret) {
+				dbg2("Interrupted wait for device %d", n);
+				MOD_DEC_USE_COUNT;
+				return ret;
+			}
+		}
+	} while(!priv);
+	/* We grabbed an existing device. */
+
+	if(down_interruptible(&priv->open_sem))
+		return -ERESTARTSYS;
+	up(&disconnect_sem);
+
+	/* Only one process can open each device, no sharing. */
+	ret = -EBUSY;
+	if(priv->opened)
+		goto error;
+
+	dbg("Opening display %d", priv->subminor);
+
+	/* Setup interrupt handler for receiving key input */
+	priv->intr_urb = usb_alloc_urb(0);
+	if(!priv->intr_urb) {
+		err("Unable to allocate URB");
+		goto error;
+	}
+	FILL_INT_URB( priv->intr_urb, priv->dev,
+			usb_rcvintpipe(priv->dev,
+				       priv->in_interrupt->bEndpointAddress),
+			priv->intr_buff, sizeof(priv->intr_buff),
+			intr_callback, priv, priv->in_interrupt->bInterval);
+	if((ret = usb_submit_urb(priv->intr_urb)) <0){
+		err("Error %d while submitting URB", ret);
+		goto error;
+	}
+
+	/* Set voltage */
+	if(brlvger_set_display_voltage(priv, raw_voltage) <0) {
+		err("Unable to set voltage");
+		goto error;
+	}
+
+	/* Turn display on */
+	if((ret = brlvger_set_display_on_off(priv, 1)) <0) {
+		err("Error %d while turning display on", ret);
+		goto error;
+	}
+
+	/* Mark as opened, so disconnect cannot free priv. */
+	priv->opened = 1;
+
+	file->private_data = priv;
+
+	ret = 0;
+	goto out;
+
+ error:
+	MOD_DEC_USE_COUNT;
+ out:
+	up(&priv->open_sem);
+	return ret;
+}
+
+static int
+brlvger_release(struct inode *inode, struct file *file)
+{
+	struct brlvger_priv *priv = file->private_data;
+	int r;
+
+	/* Turn display off. Safe even if disconnected. */
+	brlvger_set_display_on_off(priv, 0);
+
+	/* mutex with disconnect and with open */
+	down(&priv->open_sem);
+
+	if(!priv->dev) {
+		dbg("Releasing disconnected device %d", priv->subminor);
+		/* no up(&priv->open_sem) */
+		kfree(priv);
+	}else{
+		dbg("Closing display %d", priv->subminor);
+		/* Disable interrupts */
+		if((r = usb_unlink_urb(priv->intr_urb)) <0)
+			err("usb_unlink_urb returns %d", r);
+		usb_free_urb(priv->intr_urb);
+		priv->opened = 0;
+		up(&priv->open_sem);
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static ssize_t
+brlvger_write(struct file *file, const char *buffer,
+	      size_t count, loff_t *pos)
+{
+	struct brlvger_priv *priv = file->private_data;
+	char buf[MAX_BRLVGER_CELLS];
+	int ret;
+	int rs, off;
+	__u16 written;
+
+	if(!priv->dev)
+		return -ENOLINK;
+
+	off = *pos;
+
+	if(off > priv->plength)
+		return -ESPIPE;;
+
+	rs = priv->plength - off;
+
+	if(count > rs)
+		count = rs;
+	written = count;
+
+	if (copy_from_user (buf, buffer, count ) )
+		return -EFAULT;
+
+	memset(priv->obuf, 0xaa, sizeof(priv->obuf));
+
+	/* Firmware supports multiples of 8cells, so some cells are absent
+	   and for some reason there actually are holes! euurkkk! */
+
+	if( priv->plength == 44 ) {
+		/* Two ghost cells at the beginning of the display, plus
+		   two more after the sixth physical cell. */
+		if(off > 5) {
+			off +=4;
+			memcpy(priv->obuf, buf, count);
+		}else{
+			int firstpart = 6 - off;
+			
+#ifdef WRITE_DEBUG
+			dbg3("off: %d, rs: %d, count: %d, firstpart: %d",
+			     off, rs, count, firstpart);
+#endif
+
+			firstpart = (firstpart < count) ? firstpart : count;
+
+#ifdef WRITE_DEBUG
+			dbg3("off: %d", off);
+			dbg3("firstpart: %d", firstpart);
+#endif
+
+			memcpy(priv->obuf, buf, firstpart);
+
+			if(firstpart != count) {
+				int secondpart = count - firstpart;
+#ifdef WRITE_DEBUG
+				dbg3("secondpart: %d", secondpart);
+#endif
+
+				memcpy(priv->obuf+(firstpart+2),
+				       buf+firstpart, secondpart);
+				written +=2;
+			}
+
+			off +=2;
+
+#ifdef WRITE_DEBUG
+			dbg3("off: %d, rs: %d, count: %d, firstpart: %d, "
+				"written: %d", 	off, rs, count, firstpart, written);
+#endif
+		}
+	}else{
+		/* Two ghost cells at the beginningg of the display. */
+		memcpy(priv->obuf, buf, count);
+		off += 2;
+	}
+
+	{
+		int repeat = write_repeats;
+		/* Dirty hack: sometimes some of the dots are wrong and somehow
+		   right themselves if the command is repeated. */
+		while(repeat--) {
+			ret = sndcontrolmsg(priv,
+				BRLVGER_SEND_BRAILLE, BRLVGER_WRITE_REQ, 0,
+				off, priv->obuf, written);
+			if(ret <0)
+				return ret;
+		}
+	}
+
+	return count;
+}
+
+static int
+read_index(struct brlvger_priv *priv)
+{
+	int intr_idx, read_idx;
+
+	read_idx = atomic_read(&priv->read_idx);
+	read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
+
+	intr_idx = atomic_read(&priv->intr_idx);
+
+	return(read_idx == intr_idx ? -1 : read_idx);
+}
+
+static ssize_t
+brlvger_read(struct file *file, char *buffer,
+	     size_t count, loff_t *unused_pos)
+{
+	struct brlvger_priv *priv = file->private_data;
+	int read_idx;
+
+	if(count != MAX_INTERRUPT_DATA)
+		return -EINVAL;
+
+	if(!priv->dev)
+		return -ENOLINK;
+
+	if((read_idx = read_index(priv)) == -1) {
+		/* queue empty */
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		else{
+			int r = wait_event_interruptible(priv->read_wait,
+							 (!priv->dev || (read_idx = read_index(priv)) != -1));
+			if(!priv->dev)
+				return -ENOLINK;
+			if(r)
+				return r;
+			if(read_idx == -1)
+				/* should not happen */
+				return 0;
+		}
+	}
+
+	if (copy_to_user (buffer, priv->event_queue[read_idx], count) )
+		return( -EFAULT);
+
+	atomic_set(&priv->read_idx, read_idx);
+	/* Multiple opens are not allowed. Yet on SMP, two processes could
+	   read at the same time (on a shared file descriptor); then it is not
+	   deterministic whether or not they will get duplicates of a key
+	   event. */
+	return MAX_INTERRUPT_DATA;
+}
+
+static int
+brlvger_ioctl(struct inode *inode, struct file *file,
+	      unsigned cmd, unsigned long arg)
+{
+	struct brlvger_priv *priv = file->private_data;
+
+	if(!priv->dev)
+		return -ENOLINK;
+
+	switch(cmd) {
+	case BRLVGER_GET_INFO: {
+		struct brlvger_info vi;
+
+		strncpy(vi.driver_version, DRIVER_VERSION,
+			sizeof(vi.driver_version));
+		vi.driver_version[sizeof(vi.driver_version)-1] = 0;
+		strncpy(vi.driver_banner, longbanner,
+			sizeof(vi.driver_banner));
+		vi.driver_banner[sizeof(vi.driver_banner)-1] = 0;
+
+		vi.display_length = priv->plength;
+		
+		memcpy(&vi.hwver, priv->hwver, BRLVGER_HWVER_SIZE);
+		memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE);
+		memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE);
+
+		if(copy_to_user((void *)arg, &vi, sizeof(vi)))
+			return -EFAULT;
+		return 0;
+	}
+	case BRLVGER_DISPLAY_ON:
+		return brlvger_set_display_on_off(priv, 1);
+	case BRLVGER_DISPLAY_OFF:
+		return brlvger_set_display_on_off(priv, 0);
+	case BRLVGER_BUZZ: {
+		__u16 duration;
+		if(get_user(duration, (__u16 *)arg))
+			return -EFAULT;
+		return brlvger_beep(priv, duration);
+	}
+
+#if 0 /* Underlying commands don't seem to work for some reason; not clear if
+	 we'd want to export these anyway. */
+	case BRLVGER_SET_VOLTAGE: {
+		__u16 voltage;
+		if(get_user(voltage, (__u16 *)arg))
+			return -EFAULT;
+		return brlvger_set_display_voltage(priv, voltage);
+	}
+	case BRLVGER_GET_VOLTAGE: {
+		__u8 voltage;
+		int r = brlvger_get_display_voltage(priv);
+		if(r <0)
+			return r;
+		voltage = r;
+		if(put_user(voltage, (__u8 *)arg))
+			return -EFAULT;
+		return 0;
+	}
+#endif
+	default:
+		return -EINVAL;
+	};
+}
+
+static loff_t
+brlvger_llseek(struct file *file, loff_t offset, int orig)
+{
+	struct brlvger_priv *priv = file->private_data;
+
+	if(!priv->dev)
+		return -ENOLINK;
+
+	switch (orig) {
+		case 0:
+			/*  nothing to do */
+			break;
+		case 1:
+			offset +=file->f_pos;
+			break;
+		case 2:
+			offset += priv->plength;
+		default:
+			return -EINVAL;
+	}
+
+	if((offset >= priv->plength) || (offset < 0))
+		return -EINVAL;
+
+	return (file->f_pos = offset);
+}
+
+static unsigned
+brlvger_poll(struct file *file, poll_table *wait) 
+{
+	struct brlvger_priv *priv = file->private_data;
+
+	if(!priv->dev)
+		return POLLERR | POLLHUP;
+
+	poll_wait(file, &priv->read_wait, wait);
+
+	if(!priv->dev)
+		return POLLERR | POLLHUP;
+	if(read_index(priv) != -1)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static void
+intr_callback(struct urb *urb)
+{
+	struct brlvger_priv *priv = urb->context;
+	int intr_idx, read_idx;
+
+	if( urb->status ) {
+		if(urb->status == -ETIMEDOUT)
+			dbg2("Status -ETIMEDOUT, "
+			     "probably disconnected");
+		else if(urb->status != -ENOENT)
+			err("Status: %d", urb->status);
+		return;
+	}
+
+	read_idx = atomic_read(&priv->read_idx);
+	spin_lock(&priv->intr_idx_lock);
+	intr_idx = atomic_read(&priv->intr_idx);
+	if(read_idx == intr_idx) {
+		dbg2("Queue full, dropping braille display input");
+		spin_unlock(&priv->intr_idx_lock);
+		return;	/* queue full */
+	}
+
+	memcpy(priv->event_queue[intr_idx], urb->transfer_buffer,
+	       MAX_INTERRUPT_DATA);
+
+	intr_idx = (++intr_idx == MAX_INTERRUPT_BUFFER)? 0 : intr_idx;
+	atomic_set(&priv->intr_idx, intr_idx);
+	spin_unlock(&priv->intr_idx_lock);
+
+	wake_up_interruptible(&priv->read_wait);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Hardware access functions */
+
+static int
+mycontrolmsg(const char *funcname,
+	     struct brlvger_priv *priv, unsigned pipe_dir,
+	     __u8 request, __u8 requesttype, __u16 value,
+	     __u16 index, void *data, __u16 size)
+{
+	int ret=0, tries = stall_tries;
+
+	/* Make sure the device was not disconnected */
+	if(down_interruptible(&priv->dev_sem))
+		return -ERESTARTSYS;
+	if(!priv->dev) {
+		up(&priv->dev_sem);
+		return -ENOLINK;
+	}
+
+	/* Dirty hack for retransmission: stalls and fails all the time
+	   without this on the hardware we tested. */
+	while(tries--) {
+		ret = usb_control_msg(priv->dev,
+		    usb_sndctrlpipe(priv->dev,0) |pipe_dir,
+		    request, requesttype, value,
+		    index, data, size,
+		    HZ);
+		if(ret != -EPIPE)
+			break;
+		dbg2("Stalled, remaining %d tries", tries);
+	}
+	up(&priv->dev_sem);
+	if(ret <0) {
+		err("%s: usb_control_msg returns %d",
+				funcname, ret);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int
+brlvger_get_hw_version(struct brlvger_priv *priv, unsigned char *verbuf)
+{
+	return rcvcontrolmsg(priv,
+	    BRLVGER_GET_HWVERSION, BRLVGER_READ_REQ, 0,
+	    0, verbuf, BRLVGER_HWVER_SIZE);
+	/* verbuf should be 2 bytes */
+}
+
+static int
+brlvger_get_fw_version(struct brlvger_priv *priv, unsigned char *buf)
+{
+	unsigned char rawbuf[(BRLVGER_FWVER_SIZE-1)*2+2];
+	int i, len;
+	int r = rcvcontrolmsg(priv,
+			      BRLVGER_GET_FWVERSION, BRLVGER_READ_REQ, 0,
+			      0, rawbuf, sizeof(rawbuf));
+	if(r<0)
+		return r;
+
+	/* If I guess correctly: succession of 16bit words, the string is
+           formed of the first byte of each of these words. First byte in
+           buffer indicates total length of data; not sure what second byte is
+           for. */
+	len = rawbuf[0]-2;
+	if(len<0)
+		len = 0;
+	else if(len+1 > BRLVGER_FWVER_SIZE)
+		len = BRLVGER_FWVER_SIZE-1;
+	for(i=0; i<len; i++)
+		buf[i] = rawbuf[2+2*i];
+	buf[i] = 0;
+	return 0;
+}
+
+static int
+brlvger_get_serial(struct brlvger_priv *priv, unsigned char *buf)
+{
+	unsigned char rawserial[BRLVGER_SERIAL_BIN_SIZE];
+	int i;
+	int r = rcvcontrolmsg(priv,
+			      BRLVGER_GET_SERIAL, BRLVGER_READ_REQ, 0,
+			      0, rawserial, sizeof(rawserial));
+	if(r<0)
+		return r;
+
+	for(i=0; i<BRLVGER_SERIAL_BIN_SIZE; i++) {
+#define NUM_TO_HEX(n) (((n)>9) ? (n)+'A' : (n)+'0')
+		buf[2*i] = NUM_TO_HEX(rawserial[i] >>4);
+		buf[2*i+1] = NUM_TO_HEX(rawserial[i] &0xf);
+	}
+	buf[2*i] = 0;
+	return 0;
+}
+
+static int
+brlvger_get_display_length(struct brlvger_priv *priv)
+{
+	unsigned char data[2];
+	int ret = rcvcontrolmsg(priv,
+	    BRLVGER_GET_LENGTH, BRLVGER_READ_REQ, 0,
+	    0, data, 2);
+	if(ret<0)
+		return ret;
+	return data[1];
+}
+
+static int
+brlvger_beep(struct brlvger_priv *priv, __u16 duration)
+{
+	return sndcontrolmsg(priv,
+	    BRLVGER_BEEP, BRLVGER_WRITE_REQ, duration,
+	    0, NULL, 0);
+}
+
+static int
+brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on)
+{
+	dbg2("Turning display %s", ((on) ? "on" : "off"));
+	return sndcontrolmsg(priv,
+	    BRLVGER_SET_DISPLAY_ON,	BRLVGER_WRITE_REQ, on,
+	    0, NULL, 0);
+}
+
+static int
+brlvger_set_display_voltage(struct brlvger_priv *priv, __u16 voltage)
+{
+	dbg("SET_DISPLAY_VOLTAGE to %u", voltage);
+        return sndcontrolmsg(priv,
+	     BRLVGER_SET_DISPLAY_VOLTAGE, BRLVGER_WRITE_REQ, voltage,
+	     0, NULL, 0);
+}
+
+#if 0 /* Had problems testing these commands. Not particularly useful anyway.*/
+
+static int
+brlvger_get_display_voltage(struct brlvger_priv *priv)
+{
+	__u8 voltage = 0;
+	int ret = rcvcontrolmsg(priv,
+	    BRLVGER_GET_DISPLAY_VOLTAGE, BRLVGER_READ_REQ, 0,
+	    0, &voltage, 1);
+	if(ret<0)
+		return ret;
+	return voltage;
+}
+
+static int
+brlvger_get_current(struct brlvger_priv *priv)
+{
+	unsigned char data;
+	int ret = rcvcontrolmsg(priv,
+	    BRLVGER_GET_CURRENT,	BRLVGER_READ_REQ,	0,
+	    0, &data, 1);
+	if(ret<0)
+		return ret;
+	return data;
+}
+#endif
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci-hcd.c linux-2.4.19-pre9/drivers/usb/hcd/ehci-hcd.c
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci-hcd.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci-hcd.c	Tue May 28 16:02:30 2002
@@ -53,7 +53,7 @@
 
 /*
  * EHCI hc_driver implementation ... experimental, incomplete.
- * Based on the 0.96 register interface specification.
+ * Based on the final 1.0 register interface specification.
  *
  * There are lots of things to help out with here ... notably
  * everything "periodic", and of course testing with all sorts
@@ -70,6 +70,13 @@
  *
  * HISTORY:
  *
+ * 2002-05-07	Some error path cleanups to report better errors; wmb();
+ *	use non-CVS version id; better iso bandwidth claim.
+ * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
+ *	errors in submit path.  Bugfixes to interrupt scheduling/processing.
+ * 2002-03-05	Initial high-speed ISO support; reduce ITD memory; shift
+ *	more checking to generic hcd framework (db).  Make it work with
+ *	Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
  * 2002-01-14	Minor cleanup; version synch.
  * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
  * 2002-01-04	Control/Bulk queuing behaves.
@@ -78,13 +85,13 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "$Revision: 0.24+ $"
+#define DRIVER_VERSION "2002-May-07"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
 
 // #define EHCI_VERBOSE_DEBUG
-// #define have_iso
+// #define have_split_iso
 
 /* magic numbers that can affect system performance */
 #define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
@@ -180,6 +187,9 @@
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
+	/* cache this readonly data; minimize PCI reads */
+	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -197,11 +207,12 @@
 
 	ehci->async = 0;
 	ehci->reclaim = 0;
-	ehci->next_frame = -1;
+	ehci->next_uframe = -1;
 
 	/* controller state:  unknown --> reset */
 
 	/* EHCI spec section 4.1 */
+	// FIXME require STS_HALT before reset...
 	ehci_reset (ehci);
 	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
@@ -307,7 +318,7 @@
 
 	// root hub is shut down separately (first, when possible)
 	scan_async (ehci);
-	if (ehci->next_frame != -1)
+	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
 	ehci_mem_cleanup (ehci);
 
@@ -329,14 +340,12 @@
 static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			params;
 	int			ports;
 	int			i;
 
 	dbg ("%s: suspend to %d", hcd->bus_name, state);
 
-	params = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (params);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 
 	// FIXME:  This assumes what's probably a D3 level suspend...
 
@@ -372,14 +381,12 @@
 static int ehci_resume (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			params;
 	int			ports;
 	int			i;
 
 	dbg ("%s: resume", hcd->bus_name);
 
-	params = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (params);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 
 	// FIXME:  if controller didn't retain state,
 	// return and let generic code clean it up
@@ -425,7 +432,7 @@
 	if (ehci->reclaim_ready)
 		end_unlink_async (ehci);
 	scan_async (ehci);
-	if (ehci->next_frame != -1)
+	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
 
 	// FIXME:  when nothing is connected to the root hub,
@@ -510,8 +517,7 @@
 	case PIPE_BULK:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		submit_async (ehci, urb, &qtd_list, mem_flags);
-		break;
+		return submit_async (ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
@@ -519,20 +525,19 @@
 		return intr_submit (ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
-#ifdef have_iso
 		if (urb->dev->speed == USB_SPEED_HIGH)
-			return itd_submit (ehci, urb);
+			return itd_submit (ehci, urb, mem_flags);
+#ifdef have_split_iso
 		else
-			return sitd_submit (ehci, urb);
+			return sitd_submit (ehci, urb, mem_flags);
 #else
-		// FIXME highspeed iso stuff is written but never run/tested.
-		// and the split iso support isn't even written yet.
-		dbg ("no iso support yet");
+		dbg ("no split iso support yet");
 		return -ENOSYS;
-#endif /* have_iso */
+#endif /* have_split_iso */
 
+	default:	/* can't happen */
+		return -ENOSYS;
 	}
-	return 0;
 }
 
 /* remove from hardware lists
@@ -580,14 +585,14 @@
 		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
 		if (ehci->hcd.state == USB_STATE_HALT)
 			urb->status = -ESHUTDOWN;
-		qh_completions (ehci, &qh->qtd_list, 1);
+		qh_completions (ehci, qh, 1);
 		return 0;
 
 	case PIPE_ISOCHRONOUS:
 		// itd or sitd ...
 
 		// wait till next completion, do it then.
-		// completion irqs can wait up to 128 msec,
+		// completion irqs can wait up to 1024 msec,
 		urb->transfer_flags |= EHCI_STATE_UNLINK;
 		return 0;
 	}
@@ -614,10 +619,7 @@
 		if (dev->ep [i]) {
 			struct ehci_qh		*qh;
 
-			// FIXME:  this might be an itd/sitd too ...
-			// or an interrupt urb (not on async list)
-			// can use "union ehci_shadow"
-
+			/* dev->ep never has ITDs or SITDs */
 			qh = (struct ehci_qh *) dev->ep [i];
 			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
 			if (!list_empty (&qh->qtd_list)) {
@@ -644,7 +646,7 @@
 					spin_lock_irqsave (&ehci->lock, flags);
 				}
 			}
-			qh_unput (ehci, qh);
+			qh_put (ehci, qh);
 		}
 	}
 
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci-hub.c linux-2.4.19-pre9/drivers/usb/hcd/ehci-hub.c
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci-hub.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci-hub.c	Tue May 28 16:02:30 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -68,8 +68,7 @@
 
 	/* init status to no-changes */
 	buf [0] = 0;
-	temp = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (temp);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 	if (ports > 7) {
 		buf [1] = 0;
 		retval++;
@@ -92,7 +91,10 @@
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
 		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
-			set_bit (i, buf);
+			if (i < 7)
+			    buf [0] |= 1 << (i + 1);
+			else
+			    buf [1] |= 1 << (i - 7);
 			status = STS_PCD;
 		}
 	}
@@ -107,8 +109,7 @@
 	struct ehci_hcd			*ehci,
 	struct usb_hub_descriptor	*desc
 ) {
-	u32		params = readl (&ehci->caps->hcs_params);
-	int		ports = HCS_N_PORTS (params);
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	u16		temp;
 
 	desc->bDescriptorType = 0x29;
@@ -124,10 +125,10 @@
 	memset (&desc->bitmap [temp], 0xff, temp);
 
 	temp = 0x0008;			/* per-port overcurrent reporting */
-	if (HCS_PPC (params))		/* per-port power control */
-	    temp |= 0x0001;
-	if (HCS_INDICATOR (params))	/* per-port indicators (LEDs) */
-	    temp |= 0x0080;
+	if (HCS_PPC (ehci->hcs_params))
+		temp |= 0x0001;		/* per-port power control */
+	if (HCS_INDICATOR (ehci->hcs_params))
+		temp |= 0x0080;		/* per-port indicators (LEDs) */
 	desc->wHubCharacteristics = cpu_to_le16 (temp);
 }
 
@@ -142,9 +143,8 @@
 	u16		wLength
 ) {
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
-	u32		params = readl (&ehci->caps->hcs_params);
-	int		ports = HCS_N_PORTS (params);
-	u32		temp;
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32		temp, status;
 	unsigned long	flags;
 	int		retval = 0;
 
@@ -189,7 +189,7 @@
 			/* ? */
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (params))
+			if (HCS_PPC (ehci->hcs_params))
 				writel (temp & ~PORT_POWER,
 					&ehci->regs->port_status [wIndex]);
 			break;
@@ -222,22 +222,22 @@
 		if (!wIndex || wIndex > ports)
 			goto error;
 		wIndex--;
-		memset (buf, 0, 4);
+		status = 0;
 		temp = readl (&ehci->regs->port_status [wIndex]);
 
 		// wPortChange bits
 		if (temp & PORT_CSC)
-			set_bit (USB_PORT_FEAT_C_CONNECTION, buf);
+			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
 		if (temp & PORT_PEC)
-			set_bit (USB_PORT_FEAT_C_ENABLE, buf);
+			status |= 1 << USB_PORT_FEAT_C_ENABLE;
 		// USB_PORT_FEAT_C_SUSPEND
 		if (temp & PORT_OCC)
-			set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf);
+			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
 				&& jiffies > ehci->reset_done [wIndex]) {
-			set_bit (USB_PORT_FEAT_C_RESET, buf);
+			status |= 1 << USB_PORT_FEAT_C_RESET;
 
 			/* force reset to complete */
 			writel (temp & ~PORT_RESET,
@@ -255,26 +255,27 @@
 		// don't show wPortStatus if it's owned by a companion hc
 		if (!(temp & PORT_OWNER)) {
 			if (temp & PORT_CONNECT) {
-				set_bit (USB_PORT_FEAT_CONNECTION, buf);
-				set_bit (USB_PORT_FEAT_HIGHSPEED, buf);
+				status |= 1 << USB_PORT_FEAT_CONNECTION;
+				status |= 1 << USB_PORT_FEAT_HIGHSPEED;
 			}
 			if (temp & PORT_PE)
-				set_bit (USB_PORT_FEAT_ENABLE, buf);
+				status |= 1 << USB_PORT_FEAT_ENABLE;
 			if (temp & PORT_SUSPEND)
-				set_bit (USB_PORT_FEAT_SUSPEND, buf);
+				status |= 1 << USB_PORT_FEAT_SUSPEND;
 			if (temp & PORT_OC)
-				set_bit (USB_PORT_FEAT_OVER_CURRENT, buf);
+				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
 			if (temp & PORT_RESET)
-				set_bit (USB_PORT_FEAT_RESET, buf);
+				status |= 1 << USB_PORT_FEAT_RESET;
 			if (temp & PORT_POWER)
-				set_bit (USB_PORT_FEAT_POWER, buf);
+				status |= 1 << USB_PORT_FEAT_POWER;
 		}
 
 #ifndef	EHCI_VERBOSE_DEBUG
-	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+	if (status & ~0xffff)	/* only if wPortChange is interesting */
 #endif
 		dbg_port (hcd, "GetStatus", wIndex + 1, temp);
-		cpu_to_le32s ((u32 *) buf);
+		// we "know" this alignment is good, caller used kmalloc()...
+		*((u32 *) buf) = cpu_to_le32 (status);
 		break;
 	case SetHubFeature:
 		switch (wValue) {
@@ -300,7 +301,7 @@
 				&ehci->regs->port_status [wIndex]);
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (params))
+			if (HCS_PPC (ehci->hcs_params))
 				writel (temp | PORT_POWER,
 					&ehci->regs->port_status [wIndex]);
 			break;
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci-mem.c linux-2.4.19-pre9/drivers/usb/hcd/ehci-mem.c
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci-mem.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci-mem.c	Tue May 28 16:02:30 2002
@@ -98,16 +98,16 @@
 }
 
 /* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh)
+static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
 {
-	// dbg ("put %p (%d++)", qh, qh->refcount.counter);
+	// dbg ("get %p (%d++)", qh, qh->refcount.counter);
 	atomic_inc (&qh->refcount);
 	return qh;
 }
 
-static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-	// dbg ("unput %p (--%d)", qh, qh->refcount.counter);
+	// dbg ("put %p (--%d)", qh, qh->refcount.counter);
 	if (!atomic_dec_and_test (&qh->refcount))
 		return;
 	/* clean qtds first, and know this is not linked */
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci-q.c linux-2.4.19-pre9/drivers/usb/hcd/ehci-q.c
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci-q.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci-q.c	Tue May 28 16:02:30 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -21,17 +21,17 @@
 /*-------------------------------------------------------------------------*/
 
 /*
- * EHCI hardware queue manipulation
+ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
  *
  * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
  * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
  * buffers needed for the larger number).  We use one QH per endpoint, queue
  * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
- * A scheduled interrupt qh always has one qtd, one urb.
+ * A scheduled interrupt qh always (for now) has one qtd, one urb.
  *
  * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
  * interrupts) needs careful scheduling.  Performance improvements can be
- * an ongoing challenge.
+ * an ongoing challenge.  That's in "ehci-sched.c".
  * 
  * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
  * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
@@ -91,6 +91,7 @@
 	qh->hw_alt_next = EHCI_LIST_END;
 
 	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+	wmb ();
 	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
 }
 
@@ -105,29 +106,29 @@
 	/* don't modify error codes */
 	if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
 		if (token & QTD_STS_BABBLE) {
+			/* FIXME "must" disable babbling device's port too */
 			urb->status = -EOVERFLOW;
-		} else if (!QTD_CERR (token)) {
-			if (token & QTD_STS_DBE)
-				urb->status = (QTD_PID (token) == 1) /* IN ? */
-					? -ENOSR  /* hc couldn't read data */
-					: -ECOMM; /* hc couldn't write data */
-			else if (token & QTD_STS_MMF)	/* missed tt uframe */
-				urb->status = -EPROTO;
-			else if (token & QTD_STS_XACT) {
-				if (QTD_LENGTH (token))
-					urb->status = -EPIPE;
-				else {
-					dbg ("3strikes");
-					urb->status = -EPROTO;
-				}
-			} else	/* presumably a stall */
+		} else if (token & QTD_STS_MMF) {
+			/* fs/ls interrupt xfer missed the complete-split */
+			urb->status = -EPROTO;
+		} else if (token & QTD_STS_DBE) {
+			urb->status = (QTD_PID (token) == 1) /* IN ? */
+				? -ENOSR  /* hc couldn't read data */
+				: -ECOMM; /* hc couldn't write data */
+		} else if (token & QTD_STS_XACT) {
+			/* timeout, bad crc, wrong PID, etc; retried */
+			if (QTD_CERR (token))
 				urb->status = -EPIPE;
-
-		/* CERR nonzero + data left + halt --> stall */
-		} else if (QTD_LENGTH (token))
+			else {
+				dbg ("3strikes");
+				urb->status = -EPROTO;
+			}
+		/* CERR nonzero + no errors + halt --> stall */
+		} else if (QTD_CERR (token))
 			urb->status = -EPIPE;
 		else	/* unknown */
 			urb->status = -EPROTO;
+
 		dbg ("ep %d-%s qtd token %08x --> status %d",
 			/* devpath */
 			usb_pipeendpoint (urb->pipe),
@@ -194,7 +195,7 @@
 			    ? PCI_DMA_FROMDEVICE
 			    : PCI_DMA_TODEVICE);
 	if (likely (urb->hcpriv != 0)) {
-		qh_unput (ehci, (struct ehci_qh *) urb->hcpriv);
+		qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
 		urb->hcpriv = 0;
 	}
 
@@ -220,12 +221,11 @@
 static int
 qh_completions (
 	struct ehci_hcd		*ehci,
-	struct list_head	*qtd_list,
+	struct ehci_qh		*qh,
 	int			freeing
 ) {
 	struct ehci_qtd		*qtd, *last;
-	struct list_head	*next;
-	struct ehci_qh		*qh = 0;
+	struct list_head	*next, *qtd_list = &qh->qtd_list;
 	int			unlink = 0, halted = 0;
 	unsigned long		flags;
 	int			retval = 0;
@@ -245,9 +245,6 @@
 		struct urb	*urb = qtd->urb;
 		u32		token = 0;
 
-		/* qh is non-null iff these qtds were queued to the HC */
-		qh = (struct ehci_qh *) urb->hcpriv;
-
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
@@ -266,7 +263,7 @@
 			/* qh overlays can have HC's old cached copies of
 			 * next qtd ptrs, if an URB was queued afterwards.
 			 */
-			if (qh && cpu_to_le32 (last->qtd_dma) == qh->hw_current
+			if (cpu_to_le32 (last->qtd_dma) == qh->hw_current
 					&& last->hw_next != qh->hw_qtd_next) {
 				qh->hw_alt_next = last->hw_alt_next;
 				qh->hw_qtd_next = last->hw_next;
@@ -278,68 +275,60 @@
 		}
 		next = qtd->qtd_list.next;
 
-		/* if these qtds were queued to the HC, some may be active.
-		 * else we're cleaning up after a failed URB submission.
+		/* QTDs at tail may be active if QH+HC are running,
+		 * or when unlinking some urbs queued to this QH
 		 */
-		if (likely (qh != 0)) {
-			int		qh_halted;
+		token = le32_to_cpu (qtd->hw_token);
+		halted = halted
+			|| (__constant_cpu_to_le32 (QTD_STS_HALT)
+				& qh->hw_token) != 0
+			|| (ehci->hcd.state == USB_STATE_HALT)
+			|| (qh->qh_state == QH_STATE_IDLE);
+
+		/* fault: unlink the rest, since this qtd saw an error? */
+		if (unlikely ((token & QTD_STS_HALT) != 0)) {
+			freeing = unlink = 1;
+			/* status copied below */
+
+		/* QH halts only because of fault (above) or unlink (here). */
+		} else if (unlikely (halted != 0)) {
+
+			/* unlinking everything because of HC shutdown? */
+			if (ehci->hcd.state == USB_STATE_HALT) {
+				freeing = unlink = 1;
 
-			qh_halted = __constant_cpu_to_le32 (QTD_STS_HALT)
-					& qh->hw_token;
-			token = le32_to_cpu (qtd->hw_token);
-			halted = halted
-				|| qh_halted
-				|| (ehci->hcd.state == USB_STATE_HALT)
-				|| (qh->qh_state == QH_STATE_IDLE);
-
-			/* QH halts only because of fault or unlink; in both
-			 * cases, queued URBs get unlinked.  But for unlink,
-			 * URBs at the head of the queue can stay linked.
-			 */
-			if (unlikely (halted != 0)) {
-
-				/* unlink everything because of HC shutdown? */
-				if (ehci->hcd.state == USB_STATE_HALT) {
-					freeing = unlink = 1;
-					urb->status = -ESHUTDOWN;
-
-				/* explicit unlink, starting here? */
-				} else if (qh->qh_state == QH_STATE_IDLE
+			/* explicit unlink, maybe starting here? */
+			} else if (qh->qh_state == QH_STATE_IDLE
 					&& (urb->status == -ECONNRESET
 						|| urb->status == -ENOENT)) {
-					freeing = unlink = 1;
-
-				/* unlink everything because of error? */
-				} else if (qh_halted
-						&& !(token & QTD_STS_HALT)) {
-					freeing = unlink = 1;
-					if (urb->status == -EINPROGRESS)
-						urb->status = -ECONNRESET;
-
-				/* unlink the rest? */
-				} else if (unlink) {
-					urb->status = -ECONNRESET;
-
-				/* QH halted to unlink urbs after this?  */
-				} else if ((token & QTD_STS_ACTIVE) != 0) {
-					qtd = 0;
-					continue;
-				}
+				freeing = unlink = 1;
 
-			/* Else QH is active, so we must not modify QTDs
-			 * that HC may be working on.  Break from loop.
-			 */
-			} else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
-				next = qtd_list;
+			/* QH halted to unlink urbs _after_ this?  */
+			} else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
 				qtd = 0;
 				continue;
 			}
 
-			spin_lock (&urb->lock);
-			qtd_copy_status (urb, qtd->length, token);
-			spin_unlock (&urb->lock);
+			/* unlink the rest?  once we start unlinking, after
+			 * a fault or explicit unlink, we unlink all later
+			 * urbs.  usb spec requires that.
+			 */
+			if (unlink && urb->status == -EINPROGRESS)
+				urb->status = -ECONNRESET;
+
+		/* Else QH is active, so we must not modify QTDs
+		 * that HC may be working on.  No more qtds to check.
+		 */
+		} else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
+			next = qtd_list;
+			qtd = 0;
+			continue;
 		}
 
+		spin_lock (&urb->lock);
+		qtd_copy_status (urb, qtd->length, token);
+		spin_unlock (&urb->lock);
+
 		/*
 		 * NOTE:  this won't work right with interrupt urbs that
 		 * need multiple qtds ... only the first scan of qh->qtd_list
@@ -354,11 +343,10 @@
 			 * from an interrupt QTD
 			 */
 			qtd->hw_token = (qtd->hw_token
-					& ~__constant_cpu_to_le32 (0x8300))
+					& __constant_cpu_to_le32 (0x8300))
 				| cpu_to_le32 (qtd->length << 16)
-				| __constant_cpu_to_le32 (QTD_IOC
-					| (EHCI_TUNE_CERR << 10)
-					| QTD_STS_ACTIVE);
+				| __constant_cpu_to_le32 (QTD_STS_ACTIVE
+					| (EHCI_TUNE_CERR << 10));
 			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
 
 			/* this offset, and the length above,
@@ -385,7 +373,7 @@
 	}
 
 	/* patch up list head? */
-	if (unlikely (halted && qh && !list_empty (qtd_list))) {
+	if (unlikely (halted && !list_empty (qtd_list))) {
 		qh_update (qh, list_entry (qtd_list->next,
 				struct ehci_qtd, qtd_list));
 	}
@@ -406,6 +394,49 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * reverse of qh_urb_transaction:  free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list
+) {
+	struct list_head	*entry, *temp;
+	int			unmapped = 0;
+
+	list_for_each_safe (entry, temp, qtd_list) {
+		struct ehci_qtd	*qtd;
+
+		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+		list_del (&qtd->qtd_list);
+		if (unmapped != 2) {
+			int	direction;
+			size_t	size;
+
+			/* for ctrl unmap twice: SETUP and DATA;
+			 * else (bulk, intr) just once: DATA
+			 */
+			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
+				direction = PCI_DMA_TODEVICE;
+				size = sizeof (devrequest);
+			} else {
+				direction = usb_pipein (urb->pipe)
+					? PCI_DMA_FROMDEVICE
+					: PCI_DMA_TODEVICE;
+				size = qtd->urb->transfer_buffer_length;
+				unmapped++;
+			}
+			if (qtd->buf_dma)
+				pci_unmap_single (ehci->hcd.pdev,
+					qtd->buf_dma,
+					size, direction);
+		}
+		ehci_qtd_free (ehci, qtd);
+	}
+}
+
+/*
  * create a list of filled qtds for this URB; won't link into qh.
  */
 static struct list_head *
@@ -436,14 +467,6 @@
 
 	if (usb_pipecontrol (urb->pipe)) {
 		/* control request data is passed in the "setup" pid */
-
-		/* NOTE:  this isn't smart about 64bit DMA, since it uses the
-		 * default (32bit) mask rather than using the whole address
-		 * space.  we could set pdev->dma_mask to all-ones while
-		 * getting this mapping, locking it and restoring before
-		 * allocating qtd/qh/... or maybe only do that for the main
-		 * data phase (below).
-		 */
 		qtd->buf_dma = pci_map_single (
 					ehci->hcd.pdev,
 					urb->setup_packet,
@@ -472,7 +495,6 @@
 	 */
 	len = urb->transfer_buffer_length;
 	if (likely (len > 0)) {
-		/* NOTE:  sub-optimal mapping with 64bit DMA (see above) */
 		buf = map_buf = pci_map_single (ehci->hcd.pdev,
 			urb->transfer_buffer, len,
 			usb_pipein (urb->pipe)
@@ -556,8 +578,7 @@
 	return head;
 
 cleanup:
-	urb->status = -ENOMEM;
-	qh_completions (ehci, head, 1);
+	qtd_list_free (ehci, urb, head);
 	return 0;
 }
 
@@ -643,12 +664,19 @@
 		if (usb_pipecontrol (urb->pipe)) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
 		} else if (usb_pipebulk (urb->pipe)) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else
-			info1 |= usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe)) << 16;
+		} else {
+			u32	temp;
+			temp = usb_maxpacket (urb->dev, urb->pipe,
+						usb_pipeout (urb->pipe));
+			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
+			/* HS intr can be "high bandwidth" */
+			temp = 1 + ((temp >> 11) & 0x03);
+			info2 |= temp << 30;		/* mult */
+		}
 		break;
 	default:
 #ifdef DEBUG
@@ -695,6 +723,7 @@
 		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
 		qh->qh_next.qh = qh;
 		qh->hw_next = dma;
+		wmb ();
 		ehci->async = qh;
 		writel ((u32)qh->qh_dma, &ehci->regs->async_next);
 		cmd |= CMD_ASE | CMD_RUN;
@@ -706,6 +735,7 @@
 		qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
 		qh->qh_next = q->qh_next;
 		qh->hw_next = q->hw_next;
+		wmb ();
 		q->qh_next.qh = qh;
 		q->hw_next = dma;
 	}
@@ -715,7 +745,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void
+static int
 submit_async (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
@@ -809,21 +839,23 @@
 		if (likely (qh != 0)) {
 			// dbg_qh ("new qh", ehci, qh);
 			dev->ep [epnum] = qh;
-		} else
-			urb->status = -ENOMEM;
+		}
 	}
 
 	/* Control/bulk operations through TTs don't need scheduling,
 	 * the HC and TT handle it when the TT has a buffer ready.
 	 */
 	if (likely (qh != 0)) {
-		urb->hcpriv = qh_put (qh);
+		urb->hcpriv = qh_get (qh);
 		if (likely (qh->qh_state == QH_STATE_IDLE))
-			qh_link_async (ehci, qh_put (qh));
+			qh_link_async (ehci, qh_get (qh));
 	}
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (unlikely (!qh))
-		qh_completions (ehci, qtd_list, 1);
+	if (unlikely (qh == 0)) {
+		qtd_list_free (ehci, urb, qtd_list);
+		return -ENOMEM;
+	}
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -837,11 +869,11 @@
 
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_next.qh = 0;
-	qh_unput (ehci, qh);			// refcount from reclaim 
+	qh_put (ehci, qh);			// refcount from reclaim 
 	ehci->reclaim = 0;
 	ehci->reclaim_ready = 0;
 
-	qh_completions (ehci, &qh->qtd_list, 1);
+	qh_completions (ehci, qh, 1);
 
 	// unlink any urb should now unlink all following urbs, so that
 	// relinking only happens for urbs before the unlinked ones.
@@ -849,7 +881,7 @@
 			&& HCD_IS_RUNNING (ehci->hcd.state))
 		qh_link_async (ehci, qh);
 	else
-		qh_unput (ehci, qh);		// refcount from async list
+		qh_put (ehci, qh);		// refcount from async list
 }
 
 
@@ -874,7 +906,7 @@
 #endif
 
 	qh->qh_state = QH_STATE_UNLINK;
-	ehci->reclaim = qh = qh_put (qh);
+	ehci->reclaim = qh = qh_get (qh);
 
 	// dbg_qh ("start unlink", ehci, qh);
 
@@ -917,6 +949,7 @@
 	}
 	prev->hw_next = qh->hw_next;
 	prev->qh_next = qh->qh_next;
+	wmb ();
 
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
@@ -939,14 +972,14 @@
 			/* clean any finished work for this qh */
 			if (!list_empty (&qh->qtd_list)) {
 				// dbg_qh ("scan_async", ehci, qh);
-				qh = qh_put (qh);
+				qh = qh_get (qh);
 				spin_unlock_irqrestore (&ehci->lock, flags);
 
 				/* concurrent unlink could happen here */
-				qh_completions (ehci, &qh->qtd_list, 1);
+				qh_completions (ehci, qh, 1);
 
 				spin_lock_irqsave (&ehci->lock, flags);
-				qh_unput (ehci, qh);
+				qh_put (ehci, qh);
 			}
 
 			/* unlink idle entries (reduces PCI usage) */
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci-sched.c linux-2.4.19-pre9/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci-sched.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci-sched.c	Tue May 28 16:02:30 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -23,6 +23,14 @@
 /*
  * EHCI scheduled transaction support:  interrupt, iso, split iso
  * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ * We get some funky API restrictions from the current URB model, which
+ * works notably better for reading transfers than for writing.  (And
+ * which accordingly needs to change before it'll work inside devices,
+ * or with "USB On The Go" additions to USB 2.0 ...)
  */
 
 /*
@@ -55,12 +63,12 @@
 		return &periodic->qh->qh_next;
 	case Q_TYPE_FSTN:
 		return &periodic->fstn->fstn_next;
-#ifdef have_iso
 	case Q_TYPE_ITD:
 		return &periodic->itd->itd_next;
+#ifdef have_split_iso
 	case Q_TYPE_SITD:
 		return &periodic->sitd->sitd_next;
-#endif /* have_iso */
+#endif /* have_split_iso */
 	}
 	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
 	// BUG ();
@@ -109,9 +117,6 @@
 	u32			*hw_p = &ehci->periodic [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	unsigned		usecs = 0;
-#ifdef have_iso
-	u32			temp = 0;
-#endif
 
 	while (q->ptr) {
 		switch (Q_NEXT_TYPE (*hw_p)) {
@@ -130,15 +135,13 @@
 			}
 			q = &q->fstn->fstn_next;
 			break;
-#ifdef have_iso
 		case Q_TYPE_ITD:
-			temp = le32_to_cpu (q->itd->transaction [uframe]);
-			temp >>= 16;
-			temp &= 0x0fff;
-			if (temp)
-				usecs += HS_USECS_ISO (temp);
+			/* NOTE the "one uframe per itd" policy */
+			if (q->itd->hw_transaction [uframe] != 0)
+				usecs += q->itd->usecs;
 			q = &q->itd->itd_next;
 			break;
+#ifdef have_split_iso
 		case Q_TYPE_SITD:
 			temp = q->sitd->hw_fullspeed_ep &
 				__constant_cpu_to_le32 (1 << 31);
@@ -163,7 +166,7 @@
 			}
 			q = &q->sitd->sitd_next;
 			break;
-#endif /* have_iso */
+#endif /* have_split_iso */
 		default:
 			BUG ();
 		}
@@ -178,6 +181,45 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void enable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+
+	/* did clearing PSE did take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	while (readl (&ehci->regs->status) & STS_PSS)
+		udelay (20);
+
+	cmd = readl (&ehci->regs->command) | CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... PSS happens later */
+	ehci->hcd.state = USB_STATE_RUNNING;
+
+	/* make sure tasklet scans these */
+	ehci->next_uframe = readl (&ehci->regs->frame_index)
+				% (ehci->periodic_size << 3);
+}
+
+static void disable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+
+	/* did setting PSE not take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	while (!(readl (&ehci->regs->status) & STS_PSS))
+		udelay (20);
+
+	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... */
+
+	ehci->next_uframe = -1;
+}
+
+/*-------------------------------------------------------------------------*/
+
 static void intr_deschedule (
 	struct ehci_hcd	*ehci,
 	unsigned	frame,
@@ -186,11 +228,13 @@
 ) {
 	unsigned long	flags;
 
+	period >>= 3;		// FIXME microframe periods not handled yet
+
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	do {
 		periodic_unlink (ehci, frame, qh);
-		qh_unput (ehci, qh);
+		qh_put (ehci, qh);
 		frame += period;
 	} while (frame < ehci->periodic_size);
 
@@ -199,21 +243,9 @@
 	ehci->periodic_urbs--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs) {
-		u32	cmd = readl (&ehci->regs->command);
-
-		/* did setting PSE not take effect yet?
-		 * takes effect only at frame boundaries...
-		 */
-		while (!(readl (&ehci->regs->status) & STS_PSS))
-			udelay (20);
-
-		cmd &= ~CMD_PSE;
-		writel (cmd, &ehci->regs->command);
-		/* posted write ... */
-
-		ehci->next_frame = -1;
-	} else
+	if (!ehci->periodic_urbs)
+		disable_periodic (ehci);
+	else
 		vdbg ("periodic schedule still enabled");
 
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -234,6 +266,38 @@
 		atomic_read (&qh->refcount), ehci->periodic_urbs);
 }
 
+static int check_period (
+	struct ehci_hcd *ehci, 
+	unsigned	frame,
+	int		uframe,
+	unsigned	period,
+	unsigned	usecs
+) {
+	/*
+	 * 80% periodic == 100 usec/uframe available
+	 * convert "usecs we need" to "max already claimed" 
+	 */
+	usecs = 100 - usecs;
+
+	do {
+		int	claimed;
+
+// FIXME delete when intr_submit handles non-empty queues
+// this gives us a one intr/frame limit (vs N/uframe)
+		if (ehci->pshadow [frame].ptr)
+			return 0;
+
+		claimed = periodic_usecs (ehci, frame, uframe);
+		if (claimed > usecs)
+			return 0;
+
+// FIXME update to handle sub-frame periods
+	} while ((frame += period) < ehci->periodic_size);
+
+	// success!
+	return 1;
+}
+
 static int intr_submit (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
@@ -241,8 +305,7 @@
 	int			mem_flags
 ) {
 	unsigned		epnum, period;
-	unsigned		temp;
-	unsigned short		mult, usecs;
+	unsigned short		usecs;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
 	struct hcd_dev		*dev;
@@ -250,17 +313,9 @@
 
 	/* get endpoint and transfer data */
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe)) {
-		temp = urb->dev->epmaxpacketin [epnum];
+	if (usb_pipein (urb->pipe))
 		epnum |= 0x10;
-	} else
-		temp = urb->dev->epmaxpacketout [epnum];
-	mult = 1;
-	if (urb->dev->speed == USB_SPEED_HIGH) {
-		/* high speed "high bandwidth" is coded in ep maxpacket */
-		mult += (temp >> 11) & 0x03;
-		temp &= 0x03ff;
-	} else {
+	if (urb->dev->speed != USB_SPEED_HIGH) {
 		dbg ("no intr/tt scheduling yet"); 
 		status = -ENOSYS;
 		goto done;
@@ -270,6 +325,13 @@
 	 * NOTE: current completion/restart logic doesn't handle more than
 	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
 	 * such big requests need many periods to transfer.
+	 *
+	 * FIXME want to change hcd core submit model to expect queuing
+	 * for all transfer types ... not just ISO and (with flag) BULK.
+	 * that means: getting rid of this check; handling the "interrupt
+	 * urb already queued" case below like bulk queuing is handled (no
+	 * errors possible!); and completly getting rid of that annoying
+	 * qh restart logic.  simpler/smaller overall, and more flexible.
 	 */
 	if (unlikely (qtd_list->next != qtd_list->prev)) {
 		dbg ("only one intr qtd per urb allowed"); 
@@ -279,20 +341,13 @@
 
 	usecs = HS_USECS (urb->transfer_buffer_length);
 
-	/*
-	 * force a power-of-two (frames) sized polling interval
-	 *
-	 * NOTE: endpoint->bInterval for highspeed is measured in uframes,
-	 * while for full/low speeds it's in frames.  Here we "know" that
-	 * urb->interval doesn't give acccess to high interrupt rates.
-	 */
-	period = ehci->periodic_size;
-	temp = period;
-	if (unlikely (urb->interval < 1))
-		urb->interval = 1;
-	while (temp > urb->interval)
-		temp >>= 1;
-	period = urb->interval = temp;
+	/* FIXME handle HS periods of less than 1 frame. */
+	period = urb->interval >> 3;
+	if (period < 1) {
+		dbg ("intr period %d uframes, NYET!", urb->interval);
+		status = -EINVAL;
+		goto done;
+	}
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
@@ -318,55 +373,47 @@
 			list_splice (qtd_list, &qh->qtd_list);
 			qh_update (qh, list_entry (qtd_list->next,
 						struct ehci_qtd, qtd_list));
+			qtd_list = &qh->qtd_list;
 		}
 	} else {
 		/* can't sleep here, we have ehci->lock... */
 		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		qtd_list = &qh->qtd_list;
 		if (likely (qh != 0)) {
 			// dbg ("new INTR qh %p", qh);
 			dev->ep [epnum] = qh;
+			qtd_list = &qh->qtd_list;
 		} else
 			status = -ENOMEM;
 	}
 
 	/* Schedule this periodic QH. */
 	if (likely (status == 0)) {
-		unsigned	frame = urb->interval;
+		unsigned	frame = period;
 
 		qh->hw_next = EHCI_LIST_END;
-		qh->hw_info2 |= cpu_to_le32 (mult << 30);
 		qh->usecs = usecs;
 
-		urb->hcpriv = qh_put (qh);
+		urb->hcpriv = qh_get (qh);
 		status = -ENOSPC;
 
 		/* pick a set of schedule slots, link the QH into them */
 		do {
 			int	uframe;
 
-			/* Select some frame 0..(urb->interval - 1) with a
-			 * microframe that can hold this transaction.
+			/* pick a set of slots such that all uframes have
+			 * enough periodic bandwidth available.
 			 *
 			 * FIXME for TT splits, need uframes for start and end.
 			 * FSTNs can put end into next frame (uframes 0 or 1).
 			 */
 			frame--;
 			for (uframe = 0; uframe < 8; uframe++) {
-				int	claimed;
-				claimed = periodic_usecs (ehci, frame, uframe);
-				/* 80% periodic == 100 usec max committed */
-				if ((claimed + usecs) <= 100) {
-					vdbg ("frame %d.%d: %d usecs, plus %d",
-						frame, uframe, claimed, usecs);
+				if (check_period (ehci, frame, uframe,
+						period, usecs) != 0)
 					break;
-				}
 			}
 			if (uframe == 8)
 				continue;
-// FIXME delete when code below handles non-empty queues
-			if (ehci->pshadow [frame].ptr)
-				continue;
 
 			/* QH will run once each period, starting there  */
 			urb->start_frame = frame;
@@ -378,56 +425,38 @@
 
 			/* stuff into the periodic schedule */
 			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+			vdbg ("qh %p usecs %d period %d starting %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
 				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
-// FIXME -- just link to the end, before any qh with a shorter period,
+// FIXME -- just link toward the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
+// AS WELL AS updating the check_period() logic
 					BUG ();
 				} else {
-					ehci->pshadow [frame].qh = qh_put (qh);
+					ehci->pshadow [frame].qh = qh_get (qh);
 					ehci->periodic [frame] =
 						QH_NEXT (qh->qh_dma);
 				}
+				wmb ();
 				frame += period;
 			} while (frame < ehci->periodic_size);
 
 			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb, usecs, 0);
+			usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
 
 			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++) {
-				u32	cmd;
-
-				/* did clearing PSE did take effect yet?
-				 * takes effect only at frame boundaries...
-				 */
-				while (readl (&ehci->regs->status) & STS_PSS)
-					udelay (20);
-
-				cmd = readl (&ehci->regs->command) | CMD_PSE;
-				writel (cmd, &ehci->regs->command);
-				/* posted write ... PSS happens later */
-				ehci->hcd.state = USB_STATE_RUNNING;
-
-				/* make sure tasklet scans these */
-				ehci->next_frame = ehci_get_frame (&ehci->hcd);
-			}
+			if (!ehci->periodic_urbs++)
+				enable_periodic (ehci);
 			break;
 
 		} while (frame);
 	}
 	spin_unlock_irqrestore (&ehci->lock, flags);
 done:
-	if (status) {
-		usb_complete_t	complete = urb->complete;
+	if (status)
+		qtd_list_free (ehci, urb, qtd_list);
 
-		urb->complete = 0;
-		urb->status = status;
-		qh_completions (ehci, qtd_list, 1);
-		urb->complete = complete;
-	}
 	return status;
 }
 
@@ -446,6 +475,10 @@
 	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
 			!= 0))
 		return flags;
+	if (unlikely (list_empty (&qh->qtd_list))) {
+		dbg ("intr qh %p no TDs?", qh);
+		return flags;
+	}
 	
 	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
 	urb = qtd->urb;
@@ -454,7 +487,7 @@
 	/* call any completions, after patching for reactivation */
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	/* NOTE:  currently restricted to one qtd per qh! */
-	if (qh_completions (ehci, &qh->qtd_list, 0) == 0)
+	if (qh_completions (ehci, qh, 0) == 0)
 		urb = 0;
 	spin_lock_irqsave (&ehci->lock, flags);
 
@@ -489,53 +522,56 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef	have_iso
-
-static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+static void
+itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
 {
-	pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	struct ehci_itd *first_itd = urb->hcpriv;
+
+	pci_unmap_single (ehci->hcd.pdev,
+		first_itd->buf_dma, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	while (!list_empty (&first_itd->itd_list)) {
+		struct ehci_itd	*itd;
+
+		itd = list_entry (
+			first_itd->itd_list.next,
+			struct ehci_itd, itd_list);
+		list_del (&itd->itd_list);
+		pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	}
+	pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
+	urb->hcpriv = 0;
 }
 
-/*
- * Create itd and allocate into uframes within specified frame.
- * Caller must update the resulting uframe links.
- */
-static struct ehci_itd *
-itd_make (
+static int
+itd_fill (
 	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
 	struct urb	*urb,
 	unsigned	index,		// urb->iso_frame_desc [index]
-	unsigned	frame,		// scheduled start
-	dma_addr_t	dma,		// mapped transfer buffer
-	int		mem_flags
+	dma_addr_t	dma		// mapped transfer buffer
 ) {
-	struct ehci_itd	*itd;
 	u64		temp;
 	u32		buf1;
-	unsigned	epnum, maxp, multi, usecs;
+	unsigned	i, epnum, maxp, multi;
 	unsigned	length;
-	unsigned	i, bufnum;
-
-	/* allocate itd, start to fill it */
-	itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
-	if (!itd)
-		return itd;
 
 	itd->hw_next = EHCI_LIST_END;
 	itd->urb = urb;
 	itd->index = index;
-	INIT_LIST_HEAD (&itd->itd_list);
-	itd->uframe = (frame * 8) % ehci->periodic_size;
 
-	/* tell itd about the buffer its transfers will consume */
+	/* tell itd about its transfer buffer, max 2 pages */
 	length = urb->iso_frame_desc [index].length;
 	dma += urb->iso_frame_desc [index].offset;
 	temp = dma & ~0x0fff;
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < 2; i++) {
 		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
 		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
-		temp += 0x0fff;
+		temp += 0x1000;
 	}
+	itd->buf_dma = dma;
 
 	/*
 	 * this might be a "high bandwidth" highspeed endpoint,
@@ -544,282 +580,416 @@
 	epnum = usb_pipeendpoint (urb->pipe);
 	if (usb_pipein (urb->pipe)) {
 		maxp = urb->dev->epmaxpacketin [epnum];
-		buf1 = (1 << 11) | maxp;
+		buf1 = (1 << 11);
 	} else {
 		maxp = urb->dev->epmaxpacketout [epnum];
-		buf1 = maxp;
+		buf1 = 0;
 	}
+	buf1 |= (maxp & 0x03ff);
 	multi = 1;
-	multi += (temp >> 11) & 0x03;
+	multi += (maxp >> 11) & 0x03;
 	maxp &= 0x03ff;
+	maxp *= multi;
+
+	/* transfer can't fit in any uframe? */ 
+	if (length < 0 || maxp < length) {
+		dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
+			length, maxp, urb, index,
+			urb->iso_frame_desc [index].length);
+		return -ENOSPC;
+	}
+	itd->usecs = HS_USECS_ISO (length);
 
 	/* "plus" info in low order bits of buffer pointers */
 	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
 	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
 	itd->hw_bufp [2] |= cpu_to_le32 (multi);
 
-	/* schedule as many uframes as needed */
-	maxp *= multi;
-	usecs = HS_USECS_ISO (maxp);
-	bufnum = 0;
-	for (i = 0; i < 8; i++) {
-		unsigned	t, offset, scratch;
+	/* figure hw_transaction[] value (it's scheduled later) */
+	itd->transaction = EHCI_ISOC_ACTIVE;
+	itd->transaction |= dma & 0x0fff;		/* offset; buffer=0 */
+	if ((index + 1) == urb->number_of_packets)
+		itd->transaction |= EHCI_ITD_IOC; 	/* end-of-urb irq */
+	itd->transaction |= length << 16;
+	cpu_to_le32s (&itd->transaction);
 
-		if (length <= 0) {
-			itd->hw_transaction [i] = 0;
-			continue;
-		}
+	return 0;
+}
 
-		/* don't commit more than 80% periodic == 100 usec */
-		if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
-			continue;
+static int
+itd_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+) {
+	int			frame_index;
+	struct ehci_itd		*first_itd, *itd;
+	int			status;
+	dma_addr_t		buf_dma, itd_dma;
 
-		/* we'll use this uframe; figure hw_transaction */
-		t = EHCI_ISOC_ACTIVE;
-		t |= bufnum << 12;		// which buffer?
-		offset = temp & 0x0fff;		// offset therein
-		t |= offset;
-		if ((offset + maxp) >= 4096) 	// hc auto-wraps end-of-"page"
-			bufnum++;
-		if (length <= maxp) {
-			// interrupt only needed at end-of-urb
-			if ((index + 1) == urb->number_of_packets)
-				t |= EHCI_ITD_IOC;
-			scratch = length;
-		} else
-			scratch = maxp;
-		t |= scratch << 16;
-		t = cpu_to_le32 (t);
-
-		itd->hw_transaction [i] = itd->transaction [i] = t;
-		length -= scratch;
-	}
-	if (length > 0) {
-		dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
-			urb, index, length, urb->iso_frame_desc [index].length);
-		itd_free (ehci, itd);
-		itd = 0;
+	/* set up one dma mapping for this urb */
+	buf_dma = pci_map_single (ehci->hcd.pdev,
+		urb->transfer_buffer, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	if (buf_dma == 0)
+		return -ENOMEM;
+
+	/* allocate/init ITDs */
+	for (frame_index = 0, first_itd = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
+		if (!itd) {
+			status = -ENOMEM;
+			goto fail;
+		}
+		memset (itd, 0, sizeof *itd);
+		itd->itd_dma = itd_dma;
+
+		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+		if (status != 0)
+			goto fail;
+
+		if (first_itd)
+			list_add_tail (&itd->itd_list,
+					&first_itd->itd_list);
+		else {
+			INIT_LIST_HEAD (&itd->itd_list);
+			urb->hcpriv = first_itd = itd;
+		}
 	}
-	return itd;
+	urb->error_count = 0;
+	return 0;
+
+fail:
+	if (urb->hcpriv)
+		itd_free_list (ehci, urb);
+	return status;
 }
 
+/*-------------------------------------------------------------------------*/
+
 static inline void
 itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
 {
-	u32		ptr;
+	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
+	itd->itd_next = ehci->pshadow [frame];
+	itd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].itd = itd;
+	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
 
-	ptr = cpu_to_le32 (itd->itd_dma);	// type 0 == itd
-	if (ehci->pshadow [frame].ptr) {
-		if (!itd->itd_next.ptr) {
-			itd->itd_next = ehci->pshadow [frame];
-			itd->hw_next = ehci->periodic [frame];
-		} else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
-			dbg ("frame %d itd link goof", frame);
-			BUG ();
+/*
+ * return zero on success, else -errno
+ * - start holds first uframe to start scheduling into
+ * - max is the first uframe it's NOT (!) OK to start scheduling into
+ * math to be done modulo "mod" (ehci->periodic_size << 3)
+ */
+static int get_iso_range (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		*start,
+	unsigned		*max,
+	unsigned		mod
+) {
+	struct list_head	*lh;
+	struct hcd_dev		*dev = urb->dev->hcpriv;
+	int			last = -1;
+	unsigned		now, span, end;
+
+	span = urb->interval * urb->number_of_packets;
+
+	/* first see if we know when the next transfer SHOULD happen */
+	list_for_each (lh, &dev->urb_list) {
+		struct urb	*u;
+		struct ehci_itd	*itd;
+		unsigned	s;
+
+		u = list_entry (lh, struct urb, urb_list);
+		if (u == urb || u->pipe != urb->pipe)
+			continue;
+		if (u->interval != urb->interval) {	/* must not change! */ 
+			dbg ("urb %p interval %d ... != %p interval %d",
+				u, u->interval, urb, urb->interval);
+			return -EINVAL;
+		}
+		
+		/* URB for this endpoint... covers through when?  */
+		itd = urb->hcpriv;
+		s = itd->uframe + u->interval * u->number_of_packets;
+		if (last < 0)
+			last = s;
+		else {
+			/*
+			 * So far we can only queue two ISO URBs...
+			 *
+			 * FIXME do interval math, figure out whether
+			 * this URB is "before" or not ... also, handle
+			 * the case where the URB might have completed,
+			 * but hasn't yet been processed.
+			 */
+			dbg ("NYET: queue >2 URBs per ISO endpoint");
+			return -EDOM;
 		}
 	}
-	ehci->pshadow [frame].itd = itd;
-	ehci->periodic [frame] = ptr;
-}
 
-#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+	/* calculate the legal range [start,max) */
+	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
+	if (!ehci->periodic_urbs)
+		now += 8;				/* startup delay */
+	now %= mod;
+	end = now + mod;
+	if (last < 0) {
+		*start = now + ehci->i_thresh + /* paranoia */ 1;
+		*max = end - span;
+		if (*max < *start + 1)
+			*max = *start + 1;
+	} else {
+		*start = last % mod;
+		*max = (last + 1) % mod;
+	}
 
-static unsigned long
-itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+	/* explicit start frame? */
+	if (!(urb->transfer_flags & USB_ISO_ASAP)) {
+		unsigned	temp;
+
+		/* sanity check: must be in range */
+		urb->start_frame %= ehci->periodic_size;
+		temp = urb->start_frame << 3;
+		if (temp < *start)
+			temp += mod;
+		if (temp > *max)
+			return -EDOM;
+
+		/* use that explicit start frame */
+		*start = urb->start_frame << 3;
+		temp += 8;
+		if (temp < *max)
+			*max = temp;
+	}
+
+	// FIXME minimize wraparound to "now" ... insist max+span
+	// (and start+span) remains a few frames short of "end"
+
+	*max %= ehci->periodic_size;
+	if ((*start + span) < end)
+		return 0;
+	return -EFBIG;
+}
+
+static int
+itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
 {
-	struct urb		*urb = itd->urb;
+	unsigned	start, max, i;
+	int		status;
+	unsigned	mod = ehci->periodic_size << 3;
 
-	/* if not unlinking: */
-	if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
-			&& ehci->hcd.state != USB_STATE_HALT) {
-		int			i;
-		iso_packet_descriptor_t	*desc;
-		struct ehci_itd		*first_itd = urb->hcpriv;
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc [i].status = -EINPROGRESS;
+		urb->iso_frame_desc [i].actual_length = 0;
+	}
 
-		/* update status for this frame's transfers */
-		desc = &urb->iso_frame_desc [itd->index];
-		desc->status = 0;
-		desc->actual_length = 0;
-		for (i = 0; i < 8; i++) {
-			u32	 t = itd->hw_transaction [i];
-			if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
-				if (t & EHCI_ISOC_ACTIVE)
-					desc->status = -EXDEV;
-				else if (t & EHCI_ISOC_BUF_ERR)
-					desc->status = usb_pipein (urb->pipe)
-						? -ENOSR  /* couldn't read */
-						: -ECOMM; /* couldn't write */
-				else if (t & EHCI_ISOC_BABBLE)
-					desc->status = -EOVERFLOW;
-				else /* (t & EHCI_ISOC_XACTERR) */
-					desc->status = -EPROTO;
+	if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
+		return status;
+
+	do {
+		unsigned	uframe;
+		unsigned	usecs;
+		struct ehci_itd	*itd;
+
+		/* check schedule: enough space? */
+		itd = urb->hcpriv;
+		uframe = start;
+		for (i = 0, uframe = start;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			/* can't commit more than 80% periodic == 100 usec */
+			if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
+					> (100 - itd->usecs)) {
+				itd = 0;
 				break;
 			}
-			desc->actual_length += EHCI_ITD_LENGTH (t);
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
 		}
+		if (!itd)
+			continue;
+		
+		/* that's where we'll schedule this! */
+		itd = urb->hcpriv;
+		urb->start_frame = start >> 3;
+		vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
+			urb, urb->number_of_packets, urb->interval,
+			urb->start_frame, start & 0x7);
+		for (i = 0, uframe = start, usecs = 0;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			itd->uframe = uframe;
+			itd->hw_transaction [uframe & 0x07] = itd->transaction;
+			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
+				itd);
+			wmb ();
+			usecs += itd->usecs;
 
-		/* handle completion now? */
-		if ((itd->index + 1) != urb->number_of_packets)
-			return flags;
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		}
 
-		i = usb_pipein (urb->pipe);
-		if (i)
-			pci_dma_sync_single (ehci->hcd.pdev,
-				first_itd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_FROMDEVICE);
+		/* update bandwidth utilization records (for usbfs)
+		 *
+		 * FIXME This claims each URB queued to an endpoint, as if
+		 * transfers were concurrent, not sequential.  So bandwidth
+		 * typically gets double-billed ... comes from tying it to
+		 * URBs rather than endpoints in the schedule.  Luckily we
+		 * don't use this usbfs data for serious decision making.
+		 */
+		usecs /= urb->number_of_packets;
+		usecs /= urb->interval;
+		usecs >>= 3;
+		if (usecs < 1)
+			usecs = 1;
+		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
+
+		/* maybe enable periodic schedule processing */
+		if (!ehci->periodic_urbs++)
+			enable_periodic (ehci);
 
-		/* call completion with no locks; it can unlink ... */
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		urb->complete (urb);
-		spin_lock_irqsave (&ehci->lock, flags);
-
-		/* re-activate this URB? or unlink? */
-		if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
-				&& ehci->hcd.state != USB_STATE_HALT) {
-			if (!i)
-				pci_dma_sync_single (ehci->hcd.pdev,
-					first_itd->buf_dma,
-					urb->transfer_buffer_length,
-					PCI_DMA_TODEVICE);
+		return 0;
 
-			itd = urb->hcpriv;
-			do {
-				for (i = 0; i < 8; i++)
-					itd->hw_transaction [i]
-						= itd->transaction [i];
-				itd = list_entry (itd->itd_list.next,
-						struct ehci_itd, itd_list);
-			} while (itd != urb->hcpriv);
-			return flags;
-		}
+	} while ((start = ++start % mod) != max);
+
+	/* no room in the schedule */
+	dbg ("urb %p, CAN'T SCHEDULE", urb);
+	return -ENOSPC;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned long
+itd_complete (
+	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
+	unsigned	uframe,
+	unsigned long	flags
+) {
+	struct urb				*urb = itd->urb;
+	iso_packet_descriptor_t			*desc;
+	u32					t;
+
+	/* update status for this uframe's transfers */
+	desc = &urb->iso_frame_desc [itd->index];
+
+	t = itd->hw_transaction [uframe];
+	itd->hw_transaction [uframe] = 0;
+	if (t & EHCI_ISOC_ACTIVE)
+		desc->status = -EXDEV;
+	else if (t & ISO_ERRS) {
+		urb->error_count++;
+		if (t & EHCI_ISOC_BUF_ERR)
+			desc->status = usb_pipein (urb->pipe)
+				? -ENOSR  /* couldn't read */
+				: -ECOMM; /* couldn't write */
+		else if (t & EHCI_ISOC_BABBLE)
+			desc->status = -EOVERFLOW;
+		else /* (t & EHCI_ISOC_XACTERR) */
+			desc->status = -EPROTO;
+
+		/* HC need not update length with this error */
+		if (!(t & EHCI_ISOC_BABBLE))
+			desc->actual_length += EHCI_ITD_LENGTH (t);
+	} else {
+		desc->status = 0;
+		desc->actual_length += EHCI_ITD_LENGTH (t);
+	}
 
-	/* unlink done only on the last itd */
-	} else if ((itd->index + 1) != urb->number_of_packets)
+	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
+		itd, urb, itd->index + 1, urb->number_of_packets,
+		t, desc->status, desc->actual_length);
+
+	/* handle completion now? */
+	if ((itd->index + 1) != urb->number_of_packets)
 		return flags;
 
-	/* we're unlinking ... */
+	/*
+	 * For now, always give the urb back to the driver ... expect it
+	 * to submit a new urb (or resubmit this), and to have another
+	 * already queued when un-interrupted transfers are needed.
+	 * No, that's not what OHCI or UHCI are now doing.
+	 *
+	 * FIXME Revisit the ISO URB model.  It's cleaner not to have all
+	 * the special case magic, but it'd be faster to reuse existing
+	 * ITD/DMA setup and schedule state.  Easy to dma_sync/complete(),
+	 * then either reschedule or, if unlinking, free and giveback().
+	 * But we can't overcommit like the full and low speed HCs do, and
+	 * there's no clean way to report an error when rescheduling...
+	 *
+	 * NOTE that for now we don't accelerate ISO unlinks; they just
+	 * happen according to the current schedule.  Means a delay of
+	 * up to about a second (max).
+	 */
+	itd_free_list (ehci, urb);
+	if (urb->status == -EINPROGRESS)
+		urb->status = 0;
 
-	/* decouple urb from the hcd */
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (ehci->hcd.state == USB_STATE_HALT)
-		urb->status = -ESHUTDOWN;
-	itd = urb->hcpriv;
-	urb->hcpriv = 0;
-	ehci_urb_done (ehci, itd->buf_dma, urb);
+	usb_hcd_giveback_urb (&ehci->hcd, urb);
 	spin_lock_irqsave (&ehci->lock, flags);
 
-	/* take itds out of the hc's periodic schedule */
-	list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
-		->itd_list.next = 0;
-	do {
-		struct ehci_itd	*next;
-
-		if (itd->itd_list.next)
-			next = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		else
-			next = 0;
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_urbs--;
+	if (!ehci->periodic_urbs)
+		disable_periodic (ehci);
 
-		// FIXME:  hc WILL (!) lap us here, if we get behind
-		// by 128 msec (or less, with smaller periodic_size).
-		// Reading/caching these itds will cause trouble...
-
-		periodic_unlink (ehci, itd->uframe, itd);
-		itd_free (ehci, itd);
-		itd = next;
-	} while (itd);
 	return flags;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 {
-	struct ehci_itd		*first_itd = 0, *itd;
-	unsigned		frame_index;
-	dma_addr_t		dma;
-	unsigned long		flags;
-
-	dbg ("itd_submit");
+	int		status;
+	unsigned long	flags;
 
-	/* set up one dma mapping for this urb */
-	dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (dma == 0)
-		return -ENOMEM;
+	dbg ("itd_submit urb %p", urb);
 
+	/* NOTE DMA mapping assumes this ... */
+	if (urb->iso_frame_desc [0].offset != 0)
+		return -EINVAL;
+	
 	/*
-	 * Schedule as needed.  This is VERY optimistic about free
-	 * bandwidth!  But the API assumes drivers can pick frames
-	 * intelligently (how?), so there's no other good option.
-	 *
-	 * FIXME  this doesn't handle urb->next rings, or try to
-	 * use the iso periodicity.
+	 * NOTE doing this for now, anticipating periodic URB models
+	 * get updated to be "explicit resubmit".
 	 */
-	if (urb->transfer_flags & USB_ISO_ASAP) { 
-		urb->start_frame = ehci_get_frame (&ehci->hcd);
-		urb->start_frame++;
+	if (urb->next) {
+		dbg ("use explicit resubmit for ISO");
+		return -EINVAL;
 	}
-	urb->start_frame %= ehci->periodic_size;
 
-	/* create and populate itds (doing uframe scheduling) */
-	spin_lock_irqsave (&ehci->lock, flags);
-	for (frame_index = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		itd = itd_make (ehci, urb, frame_index,
-			urb->start_frame + frame_index,
-			dma, SLAB_ATOMIC);
-		if (itd) {
-			if (first_itd)
-				list_add_tail (&itd->itd_list,
-						&first_itd->itd_list);
-			else
-				first_itd = itd;
-		} else {
-			spin_unlock_irqrestore (&ehci->lock, flags);
-			if (first_itd) {
-				while (!list_empty (&first_itd->itd_list)) {
-					itd = list_entry (
-						first_itd->itd_list.next,
-						struct ehci_itd, itd_list);
-					list_del (&itd->itd_list);
-					itd_free (ehci, itd);
-				}
-				itd_free (ehci, first_itd);
-			}
-			pci_unmap_single (ehci->hcd.pdev,
-				dma, urb->transfer_buffer_length,
-				usb_pipein (urb->pipe)
-				    ? PCI_DMA_FROMDEVICE
-				    : PCI_DMA_TODEVICE);
-			return -ENOMEM;
-		}
-	}
-
-	/* stuff into the schedule */
-	itd = first_itd;
-	do {
-		unsigned	i;
-
-		for (i = 0; i < 8; i++) {
-			if (!itd->hw_transaction [i])
-				continue;
-			itd_link (ehci, itd->uframe + i, itd);
-		}
-		itd = list_entry (itd->itd_list.next,
-			struct ehci_itd, itd_list);
-	} while (itd != first_itd);
-	urb->hcpriv = first_itd;
+	/* allocate ITDs w/o locking anything */
+	status = itd_urb_transaction (ehci, urb, mem_flags);
+	if (status < 0)
+		return status;
 
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = itd_schedule (ehci, urb);
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	if (status < 0)
+		itd_free_list (ehci, urb);
+
+	return status;
 }
 
+#ifdef have_split_iso
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -827,7 +997,7 @@
  * the TTs in USB 2.0 hubs.
  */
 
-static inline void
+static void
 sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
 {
 	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
@@ -861,7 +1031,7 @@
 
 }
 
-static inline void
+static void
 sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
 {
 	u32		ptr;
@@ -894,12 +1064,11 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 {
 	// struct ehci_sitd	*first_sitd = 0;
 	unsigned		frame_index;
 	dma_addr_t		dma;
-	int			mem_flags;
 
 	dbg ("NYI -- sitd_submit");
 
@@ -908,8 +1077,6 @@
 	// FIXME:  setup one big dma mapping
 	dma = 0;
 
-	mem_flags = SLAB_ATOMIC;
-
 	for (frame_index = 0;
 			frame_index < urb->number_of_packets;
 			frame_index++) {
@@ -941,54 +1108,63 @@
 
 	return -ENOSYS;
 }
-
-#endif	/* have_iso */
+#endif /* have_split_iso */
 
 /*-------------------------------------------------------------------------*/
 
 static void scan_periodic (struct ehci_hcd *ehci)
 {
-	unsigned	frame;
-	unsigned	clock;
+	unsigned	frame, clock, now_uframe, mod;
 	unsigned long	flags;
 
+	mod = ehci->periodic_size << 3;
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/*
 	 * When running, scan from last scan point up to "now"
+	 * else clean up by scanning everything that's left.
 	 * Touches as few pages as possible:  cache-friendly.
-	 * It's safe to scan entries more than once, though.
+	 * Don't scan ISO entries more than once, though.
 	 */
-	if (HCD_IS_RUNNING (ehci->hcd.state)) {
-		frame = ehci->next_frame;
-		clock = ehci_get_frame (&ehci->hcd);
+	frame = ehci->next_uframe >> 3;
+	if (HCD_IS_RUNNING (ehci->hcd.state))
+		now_uframe = readl (&ehci->regs->frame_index);
+	else
+		now_uframe = (frame << 3) - 1;
+	now_uframe %= mod;
+	clock = now_uframe >> 3;
 
-	/* when shutting down, scan everything for thoroughness */
-	} else {
-		frame = 0;
-		clock = ehci->periodic_size - 1;
-	}
 	for (;;) {
-		union ehci_shadow	 q;
-		u32	type;
+		union ehci_shadow	q, *q_p;
+		u32			type, *hw_p;
+		unsigned		uframes;
 
 restart:
-		q.ptr = ehci->pshadow [frame].ptr;
-		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+		/* scan schedule to _before_ current frame index */
+		if (frame == clock)
+			uframes = now_uframe & 0x07;
+		else
+			uframes = 8;
+
+		q_p = &ehci->pshadow [frame];
+		hw_p = &ehci->periodic [frame];
+		q.ptr = q_p->ptr;
+		type = Q_NEXT_TYPE (*hw_p);
 
 		/* scan each element in frame's queue for completions */
 		while (q.ptr != 0) {
 			int			last;
+			unsigned		uf;
 			union ehci_shadow	temp;
 
 			switch (type) {
 			case Q_TYPE_QH:
 				last = (q.qh->hw_next == EHCI_LIST_END);
-				flags = intr_complete (ehci, frame,
-						qh_put (q.qh), flags);
-				type = Q_NEXT_TYPE (q.qh->hw_next);
 				temp = q.qh->qh_next;
-				qh_unput (ehci, q.qh);
+				type = Q_NEXT_TYPE (q.qh->hw_next);
+				flags = intr_complete (ehci, frame,
+						qh_get (q.qh), flags);
+				qh_put (ehci, q.qh);
 				q = temp;
 				break;
 			case Q_TYPE_FSTN:
@@ -1000,22 +1176,49 @@
 					dbg ("ignoring completions from FSTNs");
 				}
 				type = Q_NEXT_TYPE (q.fstn->hw_next);
-				temp = q.fstn->fstn_next;
+				q = q.fstn->fstn_next;
 				break;
-#ifdef have_iso
 			case Q_TYPE_ITD:
 				last = (q.itd->hw_next == EHCI_LIST_END);
-				flags = itd_complete (ehci, q.itd, flags);
-				type = Q_NEXT_TYPE (q.itd->hw_next);
-				q = q.itd->itd_next;
+
+				/* Unlink each (S)ITD we see, since the ISO
+				 * URB model forces constant rescheduling.
+				 * That complicates sharing uframes in ITDs,
+				 * and means we need to skip uframes the HC
+				 * hasn't yet processed.
+				 */
+				for (uf = 0; uf < uframes; uf++) {
+					if (q.itd->hw_transaction [uf] != 0) {
+						temp = q;
+						*q_p = q.itd->itd_next;
+						*hw_p = q.itd->hw_next;
+						type = Q_NEXT_TYPE (*hw_p);
+
+						/* might free q.itd ... */
+						flags = itd_complete (ehci,
+							temp.itd, uf, flags);
+						break;
+					}
+				}
+				/* we might skip this ITD's uframe ... */
+				if (uf == uframes) {
+					q_p = &q.itd->itd_next;
+					hw_p = &q.itd->hw_next;
+					type = Q_NEXT_TYPE (q.itd->hw_next);
+				}
+
+				q = *q_p;
 				break;
+#ifdef have_split_iso
 			case Q_TYPE_SITD:
 				last = (q.sitd->hw_next == EHCI_LIST_END);
 				flags = sitd_complete (ehci, q.sitd, flags);
 				type = Q_NEXT_TYPE (q.sitd->hw_next);
+
+				// FIXME unlink SITD after split completes
 				q = q.sitd->sitd_next;
 				break;
-#endif /* have_iso */
+#endif /* have_split_iso */
 			default:
 				dbg ("corrupt type %d frame %d shadow %p",
 					type, frame, q.ptr);
@@ -1044,13 +1247,16 @@
 
 			if (!HCD_IS_RUNNING (ehci->hcd.state))
 				break;
-			ehci->next_frame = clock;
-			now = ehci_get_frame (&ehci->hcd);
-			if (clock == now)
+			ehci->next_uframe = now_uframe;
+			now = readl (&ehci->regs->frame_index) % mod;
+			if (now_uframe == now)
 				break;
-			clock = now;
-		} else if (++frame >= ehci->periodic_size)
-			frame = 0;
+
+			/* rescan the rest of this frame, then ... */
+			now_uframe = now;
+			clock = now_uframe >> 3;
+		} else
+			frame = (frame + 1) % ehci->periodic_size;
 	} 
 	spin_unlock_irqrestore (&ehci->lock, flags);
- }
+}
diff -urN linux-2.4.19-pre8/drivers/usb/hcd/ehci.h linux-2.4.19-pre9/drivers/usb/hcd/ehci.h
--- linux-2.4.19-pre8/drivers/usb/hcd/ehci.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hcd/ehci.h	Tue May 28 16:02:30 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -49,7 +49,7 @@
 	unsigned		i_thresh;	/* uframes HC might cache */
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
-	int			next_frame;	/* scan periodic, start here */
+	int			next_uframe;	/* scan periodic, start here */
 	unsigned		periodic_urbs;	/* how many urbs scheduled? */
 
 	/* deferred work from IRQ, etc */
@@ -62,6 +62,7 @@
 	struct usb_hcd		hcd;
 	struct ehci_caps	*caps;
 	struct ehci_regs	*regs;
+	u32			hcs_params;	/* cached register copy */
 
 	/* per-HC memory pools (could be per-PCI-bus, but ...) */
 	struct pci_pool		*qh_pool;	/* qh per active urb */
@@ -324,13 +325,14 @@
 	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
 
 	struct urb		*urb;
-	unsigned		index;		/* in urb->iso_frame_desc */
 	struct list_head	itd_list;	/* list of urb frames' itds */
 	dma_addr_t		buf_dma;	/* frame's buffer address */
 
-	unsigned		uframe;		/* in periodic schedule */
-	u32			transaction [8]; /* copy of hw_transaction */
-
+	/* for now, only one hw_transaction per itd */
+	u32			transaction;
+	u16			index;		/* in urb->iso_frame_desc */
+	u16			uframe;		/* in periodic schedule */
+	u16			usecs;
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -urN linux-2.4.19-pre8/drivers/usb/hid-core.c linux-2.4.19-pre9/drivers/usb/hid-core.c
--- linux-2.4.19-pre8/drivers/usb/hid-core.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/hid-core.c	Tue May 28 16:02:30 2002
@@ -1084,6 +1084,7 @@
 #define USB_DEVICE_ID_ATEN_UC100KM	0x2004
 #define USB_DEVICE_ID_ATEN_CS124U	0x2202
 #define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
 
 struct hid_blacklist {
 	__u16 idVendor;
@@ -1113,6 +1114,7 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ 0, 0 }
 };
 
diff -urN linux-2.4.19-pre8/drivers/usb/pegasus.h linux-2.4.19-pre9/drivers/usb/pegasus.h
--- linux-2.4.19-pre8/drivers/usb/pegasus.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/pegasus.h	Tue May 28 16:02:30 2002
@@ -66,7 +66,6 @@
 #define	PEGASUS_REQ_GET_REGS	0xf0
 #define	PEGASUS_REQ_SET_REGS	0xf1
 #define	PEGASUS_REQ_SET_REG	PEGASUS_REQ_SET_REGS
-#define	ALIGN(x)		x __attribute__((aligned(L1_CACHE_BYTES)))
 
 enum pegasus_registers {
 	EthCtrl0 = 0,
@@ -103,9 +102,9 @@
 	devrequest		dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
-	unsigned char		ALIGN(rx_buff[PEGASUS_MAX_MTU]);
-	unsigned char		ALIGN(tx_buff[PEGASUS_MAX_MTU]);
-	unsigned char		ALIGN(intr_buff[8]);
+	unsigned char		rx_buff[PEGASUS_MAX_MTU];
+	unsigned char		tx_buff[PEGASUS_MAX_MTU];
+	unsigned char		intr_buff[8];
 	__u8			eth_regs[4];
 	__u8			phy;
 	__u8			gpio_res;
@@ -254,6 +253,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
 		DEFAULT_GPIO_RESET )
 
diff -urN linux-2.4.19-pre8/drivers/usb/printer.c linux-2.4.19-pre9/drivers/usb/printer.c
--- linux-2.4.19-pre8/drivers/usb/printer.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/printer.c	Tue May 28 16:02:30 2002
@@ -801,6 +801,7 @@
 	usblp_check_status(usblp, 0);
 #endif
 
+	usblp_table[usblp->minor] = usblp;
 	/* If we have devfs, create with perms=660. */
 	sprintf(name, "lp%d", usblp->minor);
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
@@ -816,7 +817,7 @@
 		usblp->current_protocol, usblp->dev->descriptor.idVendor,
 		usblp->dev->descriptor.idProduct);
 
-	return usblp_table[usblp->minor] = usblp;
+	return usblp;
 
 abort:
 	if (usblp) {
diff -urN linux-2.4.19-pre8/drivers/usb/serial/Config.in linux-2.4.19-pre9/drivers/usb/serial/Config.in
--- linux-2.4.19-pre8/drivers/usb/serial/Config.in	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/serial/Config.in	Tue May 28 16:02:30 2002
@@ -15,7 +15,7 @@
 dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-dep_tristate '  USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
+dep_tristate '  USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -urN linux-2.4.19-pre8/drivers/usb/serial/io_tables.h linux-2.4.19-pre9/drivers/usb/serial/io_tables.h
--- linux-2.4.19-pre8/drivers/usb/serial/io_tables.h	Tue Nov 13 17:45:27 2001
+++ linux-2.4.19-pre9/drivers/usb/serial/io_tables.h	Tue May 28 16:02:30 2002
@@ -25,6 +25,11 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) },
 	{ }
 };
 
@@ -37,6 +42,11 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) },
 	{ }
 };
 
@@ -44,6 +54,9 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) },
 	{ }
 };
 
@@ -66,6 +79,19 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_8I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_2_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4T) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_4_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BB_EDGEPORT_8I) },
 	{ }							/* Terminating entry */
 };
 
diff -urN linux-2.4.19-pre8/drivers/usb/serial/io_usbvend.h linux-2.4.19-pre9/drivers/usb/serial/io_usbvend.h
--- linux-2.4.19-pre8/drivers/usb/serial/io_usbvend.h	Tue Nov 13 17:45:27 2001
+++ linux-2.4.19-pre9/drivers/usb/serial/io_usbvend.h	Tue May 28 16:02:30 2002
@@ -92,6 +92,20 @@
 #define ION_DEVICE_ID_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
 #define ION_DEVICE_ID_MT4X56USB			0x1403	// OEM device
 
+// BlackBox OEM devices
+#define ION_DEVICE_ID_BB_EDGEPORT_4		0x001	// Edgeport/4 RS232
+#define ION_DEVICE_ID_BB_EDGEPORT_4T		0x004	// Edgeport/4 RS232 for Telxon (aka "Fleetport")
+#define ION_DEVICE_ID_BB_EDGEPORT_2		0x005	// Edgeport/2 RS232
+#define ION_DEVICE_ID_BB_EDGEPORT_4I		0x006	// Edgeport/4 RS422
+#define ION_DEVICE_ID_BB_EDGEPORT_2I		0x007	// Edgeport/2 RS422/RS485
+#define	ION_DEVICE_ID_BB_EDGEPORT_421		0x00C	// Edgeport/421 Hub+RS232+Parallel
+#define	ION_DEVICE_ID_BB_EDGEPORT_21		0x00D	// Edgeport/21  RS232+Parallel
+#define ION_DEVICE_ID_BB_EDGEPORT_8_DUAL_CPU	0x00E	// Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB)
+#define ION_DEVICE_ID_BB_EDGEPORT_8		0x00F	// Edgeport/8 (single-CPU)
+#define ION_DEVICE_ID_BB_EDGEPORT_2_DIN		0x010	// Edgeport/2 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_BB_EDGEPORT_4_DIN		0x011	// Edgeport/4 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU	0x012	// Half of an Edgeport/16 (the kind with 2 EP/8s)
+#define ION_DEVICE_ID_BB_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
 // These IDs are used by the Edgeport.exe program for uninstalling.
 // 
 #define EDGEPORT_DEVICE_IDS	{0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \
diff -urN linux-2.4.19-pre8/drivers/usb/serial/ipaq.c linux-2.4.19-pre9/drivers/usb/serial/ipaq.c
--- linux-2.4.19-pre8/drivers/usb/serial/ipaq.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/serial/ipaq.c	Tue May 28 16:02:30 2002
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (30/4/2002) ganesh
+ * 	Added support for the Casio EM500. Completely untested. Thanks
+ * 	to info from Nathan <wfilardo@fuse.net>
+ *
  * (19/3/2002) ganesh
  * 	Don't submit urbs while holding spinlocks. Thanks to Greg for pointing
  * 	this out.
@@ -58,7 +62,7 @@
  */
 #define DRIVER_VERSION "v0.2"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
-#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver"
+#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver"
 
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -81,6 +85,7 @@
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
+	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -urN linux-2.4.19-pre8/drivers/usb/serial/ipaq.h linux-2.4.19-pre9/drivers/usb/serial/ipaq.h
--- linux-2.4.19-pre8/drivers/usb/serial/ipaq.h	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/serial/ipaq.h	Tue May 28 16:02:30 2002
@@ -23,6 +23,9 @@
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
 
+#define CASIO_VENDOR_ID		0x07cf
+#define CASIO_EM500_ID		0x2002
+
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
  * doesn't work), we can send down only one write urb at a time. The simplistic
diff -urN linux-2.4.19-pre8/drivers/usb/serial/pl2303.c linux-2.4.19-pre9/drivers/usb/serial/pl2303.c
--- linux-2.4.19-pre8/drivers/usb/serial/pl2303.c	Wed Oct 10 23:42:47 2001
+++ linux-2.4.19-pre9/drivers/usb/serial/pl2303.c	Tue May 28 16:02:30 2002
@@ -140,6 +140,7 @@
 
 struct pl2303_private { 
 	u8 line_control;
+	u8 termios_initialized;
 };
 
 
@@ -217,13 +218,19 @@
 	int baud;
 	int i;
 
-	dbg (__FUNCTION__ " -  port %d", port->number);
+	dbg (__FUNCTION__ " -  port %d, initialized = %d", port->number, 
+	     ((struct pl2303_private *) port->private)->termios_initialized);
 
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg(__FUNCTION__" - no tty structures");
 		return;
 	}
 
+	if (!(((struct pl2303_private *)port->private)->termios_initialized)) {
+		*(port->tty->termios) = tty_std_termios;
+		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+		((struct pl2303_private *) port->private)->termios_initialized = 1;
+	}
 	cflag = port->tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
@@ -400,9 +407,6 @@
 		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
 		/* Setup termios */
-		*(port->tty->termios) = tty_std_termios;
-		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
 		pl2303_set_termios (port, &tmp_termios);
 
 		//FIXME: need to assert RTS and DTR if CRTSCTS off
diff -urN linux-2.4.19-pre8/drivers/usb/usb-ohci.c linux-2.4.19-pre9/drivers/usb/usb-ohci.c
--- linux-2.4.19-pre8/drivers/usb/usb-ohci.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/usb-ohci.c	Tue May 28 16:02:30 2002
@@ -1336,6 +1336,7 @@
 	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
 
 	/* append to queue */
+	wmb();
 	td->ed->hwTailP = td->hwNextTD;
 }
 
@@ -1399,8 +1400,10 @@
 				cnt++;
 			}
 
-			if (!ohci->sleeping)
+			if (!ohci->sleeping) {
+				wmb();
 				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+			}
 			break;
 
 		case PIPE_INTERRUPT:
@@ -1425,8 +1428,10 @@
 			info = usb_pipeout (urb->pipe)? 
  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
 			td_fill (ohci, info, data, 0, urb, cnt++);
-			if (!ohci->sleeping)
+			if (!ohci->sleeping) {
+				wmb();
 				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+			}
 			break;
 
 		case PIPE_ISOCHRONOUS:
diff -urN linux-2.4.19-pre8/drivers/usb/usb-ohci.h linux-2.4.19-pre9/drivers/usb/usb-ohci.h
--- linux-2.4.19-pre8/drivers/usb/usb-ohci.h	Wed Oct 24 08:26:12 2001
+++ linux-2.4.19-pre9/drivers/usb/usb-ohci.h	Tue May 28 16:02:30 2002
@@ -439,7 +439,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
+#define ALLOC_FLAGS (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
 
 #ifdef DEBUG
 #	define OHCI_MEM_FLAGS	SLAB_POISON
diff -urN linux-2.4.19-pre8/drivers/usb/usb-uhci.c linux-2.4.19-pre9/drivers/usb/usb-uhci.c
--- linux-2.4.19-pre8/drivers/usb/usb-uhci.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/usb/usb-uhci.c	Tue May 28 16:02:30 2002
@@ -86,8 +86,8 @@
 	static kmem_cache_t *urb_priv_kmem;
 #endif
 
-#define SLAB_FLAG     (in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt ()? GFP_ATOMIC : GFP_KERNEL)
+#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
 
 /* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
  * Reclamation: feature that puts loop on descriptor loop when
@@ -95,7 +95,7 @@
  * is optimal, but PCI can be slowed down up-to 5 times, slowing down
  * system performance (eg. framebuffer devices).
  */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
+#define CONFIG_USB_UHCI_HIGH_BANDWIDTH
 
 /* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
  * somehow similar effect to FSBR (higher speed), but does not
@@ -143,7 +143,7 @@
 	q=s->free_desc.prev;
 
 	while (q != &s->free_desc && (force || n<100)) {
-		qh = list_entry (q, uhci_desc_t, horizontal);		
+		qh = list_entry (q, uhci_desc_t, horizontal);
 		q=qh->horizontal.prev;
 
 		if ((qh->last_used!=now) || force)
diff -urN linux-2.4.19-pre8/drivers/video/Config.in linux-2.4.19-pre9/drivers/video/Config.in
--- linux-2.4.19-pre8/drivers/video/Config.in	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/video/Config.in	Tue May 28 16:02:30 2002
@@ -347,7 +347,7 @@
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
-	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB24 m
 	 fi
       fi
diff -urN linux-2.4.19-pre8/drivers/video/Makefile linux-2.4.19-pre9/drivers/video/Makefile
--- linux-2.4.19-pre8/drivers/video/Makefile	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/video/Makefile	Tue May 28 16:02:30 2002
@@ -15,7 +15,7 @@
 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
 		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
-		  cyber2000fb.o sa1100fb.o fbcon-hga.o
+		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
 
 # Each configuration option enables a list of files.
 
diff -urN linux-2.4.19-pre8/drivers/video/aty/mach64_gx.c linux-2.4.19-pre9/drivers/video/aty/mach64_gx.c
--- linux-2.4.19-pre8/drivers/video/aty/mach64_gx.c	Tue Jul 31 14:43:29 2001
+++ linux-2.4.19-pre9/drivers/video/aty/mach64_gx.c	Tue May 28 16:02:30 2002
@@ -5,6 +5,7 @@
 
 #include <linux/delay.h>
 #include <linux/fb.h>
+#include <linux/sched.h>
 
 #include <asm/io.h>
 
diff -urN linux-2.4.19-pre8/drivers/video/fbgen.c linux-2.4.19-pre9/drivers/video/fbgen.c
--- linux-2.4.19-pre8/drivers/video/fbgen.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/video/fbgen.c	Tue May 28 16:02:30 2002
@@ -448,3 +448,21 @@
 	fbgen_install_cmap(currcon, info2);
 }
 MODULE_LICENSE("GPL");
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fbgen_get_var);
+EXPORT_SYMBOL(fbgen_get_cmap);
+EXPORT_SYMBOL(fbgen_get_fix);
+EXPORT_SYMBOL(fbgen_set_var);
+EXPORT_SYMBOL(fbgen_set_cmap);
+EXPORT_SYMBOL(fbgen_set_disp);
+EXPORT_SYMBOL(fbgen_install_cmap);
+EXPORT_SYMBOL(fbgen_pan_display);
+EXPORT_SYMBOL(fbgen_update_var);
+EXPORT_SYMBOL(fbgen_do_set_var);
+EXPORT_SYMBOL(fbgen_switch);
+EXPORT_SYMBOL(fbgen_blank);
diff -urN linux-2.4.19-pre8/drivers/video/tridentfb.c linux-2.4.19-pre9/drivers/video/tridentfb.c
--- linux-2.4.19-pre8/drivers/video/tridentfb.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/drivers/video/tridentfb.c	Tue May 28 16:02:30 2002
@@ -1,9 +1,9 @@
 /*
  * Frame buffer driver for Trident Blade and Image series
  *
- * Copyright 2001,2002 - Jani Monoses   <jani@astechnix.ro>
+ * Copyright 2001,2002 - Jani Monoses   <jani@iv.ro>
  *
- * $Id: tridentfb.c,v 1.3 2002/02/25 20:09:41 marcelo Exp $
+ * $Id: trident.c,v 1.72 2002/05/04 14:49:28 jani Exp $
  *
  * CREDITS:(in order of appearance)
  * 	skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
@@ -35,7 +35,7 @@
 
 #include "tridentfb.h"
 
-#define VERSION		"0.6.9"
+#define VERSION		"0.7.2"
 
 struct tridentfb_par {
 	struct fb_var_screeninfo var;
@@ -69,6 +69,7 @@
 	unsigned int io_virt;		//iospace virtual memory address
 	unsigned int nativex;		//flat panel xres
 	struct tridentfb_par currentmode;
+	unsigned char eng_oper;		//engine operation...
 };
 
 static struct fb_ops tridentfb_ops;
@@ -82,7 +83,6 @@
 
 static char * tridentfb_name = "Trident";
 
-static int family;
 static int pci_id;
 
 static int defaultaccel;
@@ -90,7 +90,6 @@
 
 static int pseudo_pal[16];
 
-
 /* defaults which are normally overriden by user values */
 
 /* video mode */
@@ -150,9 +149,10 @@
 #define writemmr(r,v)	writel(v, fb_info.io_virt + r)
 #define readmmr(r)	readl(fb_info.io_virt + r)
 
+
+
 /*
- * Blade specific acceleration.Not XP's though those are
- * unaccelerated.
+ * Blade specific acceleration.
  */
 
 #define point(x,y) ((y)<<16|(x))
@@ -215,7 +215,7 @@
 	d1 = point(x2,y2);
 	d2 = point(x2+w-1,y2+h-1);
 
-	if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
+	if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
 			direction = 0;
 
 
@@ -235,6 +235,130 @@
 	blade_copy_rect,
 };
 
+
+/*
+ * BladeXP specific acceleration functions
+ */
+
+#define ROP_P 0xF0
+#define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff))
+
+static void xp_init_accel(int pitch,int bpp)
+{
+	int tmp = 0,v1;
+	unsigned char x = 0;
+
+	switch (bpp) {
+		case 8:  x = 0; break;
+		case 16: x = 1; break;
+		case 24: x = 3; break;
+		case 32: x = 2; break;
+	}
+
+	switch (pitch << (bpp >> 3)) {
+		case 8192:
+		case 512:  x |= 0x00; break;
+		case 1024: x |= 0x04; break;
+		case 2048: x |= 0x08; break;
+		case 4096: x |= 0x0C; break;
+	}
+
+	t_outb(x,0x2125);
+
+	fb_info.eng_oper = x | 0x40;
+
+	switch (bpp) {
+		case 8:  tmp = 18; break;
+		case 15:
+		case 16: tmp = 19; break;
+		case 24:
+		case 32: tmp = 20; break;
+	}
+
+	v1 = pitch << tmp;
+
+	writemmr(0x2154,v1);
+	writemmr(0x2150,v1);
+	t_outb(3,0x2126);
+}
+
+static void xp_wait_engine(void)
+{
+	int busy;
+	int count, timeout;
+
+	count = 0;
+	timeout = 0;
+	for (;;) {
+		busy = t_inb(STA) & 0x80;
+		if (busy != 0x80)
+			return;
+		count++;
+		if (count == 10000000) {
+			/* Timeout */
+			count = 9990000;
+			timeout++;
+			if (timeout == 8) {
+				/* Reset engine */
+				t_outb(0x00, 0x2120);
+				return;
+			}
+		}
+	}
+}
+
+static void xp_fill_rect(int x,int y,int w,int h,int c)
+{
+	writemmr(0x2127,ROP_P);
+	writemmr(0x2158,c);
+	writemmr(0x2128,0x4000);
+	writemmr(0x2140,masked_point(h,w));
+	writemmr(0x2138,masked_point(y,x));
+	t_outb(0x01,0x2124);
+        t_outb(fb_info.eng_oper,0x2125);
+}
+
+static void xp_copy_rect(int x1,int y1,int x2,int y2,int w,int h)
+{
+	int direction;
+	int x1_tmp, x2_tmp, y1_tmp, y2_tmp;
+
+	direction = 0x0004;
+
+	if ((x1 < x2) && (y1 == y2)) {
+		direction |= 0x0200;
+		x1_tmp = x1 + w - 1;
+		x2_tmp = x2 + w - 1;
+	} else {
+		x1_tmp = x1;
+		x2_tmp = x2;
+	}
+
+	if (y1 < y2) {
+		direction |= 0x0100;
+		y1_tmp = y1 + h - 1;
+		y2_tmp = y2 + h - 1;
+  	} else {
+		y1_tmp = y1;
+		y2_tmp = y2;
+	}
+
+	writemmr(0x2128,direction);
+	t_outb(ROP_S,0x2127);
+	writemmr(0x213C,masked_point(y1_tmp,x1_tmp));
+	writemmr(0x2138,masked_point(y2_tmp,x2_tmp));
+	writemmr(0x2140,masked_point(h,w));
+	t_outb(0x01,0x2124);
+}
+
+static struct accel_switch accel_xp = {
+  	xp_init_accel,
+	xp_wait_engine,
+	xp_fill_rect,
+	xp_copy_rect,
+};
+
+
 /*
  * Image specific acceleration functions
  */
@@ -255,7 +379,7 @@
 	writemmr(0x2148, 0x00000000);
 	writemmr(0x2150, 0x00000000);
 	writemmr(0x2154, 0x00000000);
-	writemmr(0x2120, 0x60000000 |(pitch<<16) |pitch);
+	writemmr(0x2120, 0x60000000|(pitch<<16) |pitch);
 	writemmr(0x216C, 0x00000000);
 	writemmr(0x2170, 0x00000000);
 	writemmr(0x217C, 0x00000000);
@@ -521,7 +645,7 @@
 }
 
 /* Use 20.12 fixed-point for NTSC value and frequency calculation */
-#define calc_freq(n,m,k)  ( (unsigned long)0xE517 * (n+8) / (m+2)*(1<<k) )
+#define calc_freq(n,m,k)  ( (unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k)) )
 
 /* Set dotclock frequency */
 static void set_vclk(int freq)
@@ -1035,8 +1159,8 @@
     	}
 
 	write3CE(PowerStatus,DPMSCont);
-    	t_outb(4,0x83C8);
-    	t_outb(PMCont,0x83C6);
+	t_outb(4,0x83C8);
+	t_outb(PMCont,0x83C6);
 
 	debug("exit\n");
 	return 0;
@@ -1097,73 +1221,40 @@
 	trident_set_disp
 };
 
-/* List of boards that we are trying to support */
-static struct almost_supported_board {
-	int pci_id;
-	int family;
-	struct accel_switch * acc;
-	char* board_name;
-	int accel;
-} asb[] __initdata = {
-	{ BLADE3D,		BLADE,	&accel_blade, "Blade3D",	ACCEL	},
-	{ CYBERBLADEi7,	BLADE,	&accel_blade, "CyberBladei7",	ACCEL	},
-	{ CYBERBLADEi7D,	BLADE,	&accel_blade, "CyberBladei7D",	ACCEL	},
-	{ CYBERBLADEi1,	BLADE,	&accel_blade, "CyberBladei1",	ACCEL	},
-	{ CYBERBLADEi1D,	BLADE,	&accel_blade, "CyberBladei1D",	ACCEL	},
-	{ CYBERBLADEAi1,	BLADE,	&accel_blade, "CyberBladeAi1",	ACCEL	},
-	{ CYBERBLADEAi1D,	BLADE,	&accel_blade, "CyberBladeAi1D",	ACCEL	},
-	{ CYBERBLADEE4,	BLADE,	&accel_blade, "CyberBladeE4",	ACCEL	},
-
-	{ IMAGE975,	IMAGE,	&accel_image,	"IMAGE975",	NOACCEL	},
-	{ IMAGE985,	IMAGE,	&accel_image,	"IMAGE985",	NOACCEL	},
-	{ CYBER9320,	IMAGE,	&accel_image,	"Cyber9320",	NOACCEL	},
-	{ CYBER9388,	IMAGE,	&accel_image,	"Cyber9388",	NOACCEL	},
-	{ CYBER9520,	IMAGE,	&accel_image,	"Cyber9520",	NOACCEL	},
-	{ CYBER9525DVD,	IMAGE,	&accel_image,	"Cyber9525DVD",	NOACCEL	},
-	{ CYBER9397,	IMAGE,	&accel_image,	"Cyber9397",	NOACCEL	},
-	{ CYBER9397DVD,	IMAGE,	&accel_image,	"Cyber9397DVD",	NOACCEL	},
-
-	{ CYBERBLADEXPAi1,	XP,	&accel_blade,	"CyberBladeXPAi1",	NOACCEL },
-	{ CYBERBLADEXPm8,	XP,	&accel_blade,	"CyberBladeXPm8",	NOACCEL },
-	{ CYBERBLADEXPm16,	XP,	&accel_blade,	"CyberBladeXPm16",	NOACCEL },
-};
-
-static __init int trident_find_board(void)
+static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
 {
-	int i;
-	struct pci_dev * board;
+	int err;
 
-	for (i = 0;i < ARRAY_SIZE(asb);i++) {
-      		if ((board = pci_find_device(PCI_VENDOR_ID_TRIDENT,
-				   asb[i].pci_id,
-				   NULL))) {
-	 		family = asb[i].family;
-	 		acc = asb[i].acc;
-	 		pci_id = asb[i].pci_id;
-	 		defaultaccel = asb[i].accel;
-
-			fb_info.io = pci_resource_start(board,1);
-			fb_info.fbmem = pci_resource_start(board,0);
-	 		output("%s board found\n", asb[i].board_name);
-	 		return 1;
-      		}
-   	}
-	output("No Trident board found\n");
-	return 0;
-}
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
 
-int __init tridentfb_init(void)
-{
+	pci_id = id->device;
 
-	output("Trident framebuffer  %s initializing\n", VERSION);
+	/* At this point this seems useless, we
+	 * could leave the default_accel variable
+	 * in the case that other boards (without
+	 * accel or buggy accel) will be added...
+	 */
+	if (is_xp(pci_id)) {
+		defaultaccel = ACCEL;
+		acc = &accel_xp;
+	} else
+	if (is_blade(pci_id)) {
+		defaultaccel = ACCEL;
+		acc = &accel_blade;
+	} else {
+		defaultaccel = ACCEL;
+		acc = &accel_image;
+	}
 
-	if (!trident_find_board())
-     		return -1;
+	fb_info.io = pci_resource_start(dev,1);
+	fb_info.fbmem = pci_resource_start(dev,0);
 
 	if (!request_mem_region(fb_info.io, TRIDENT_IOSIZE, "tridentfb")) {
 		debug("request_region failed!\n");
 		return -1;
-	};
+	}
 
 	fb_info.io_virt = (unsigned int)ioremap_nocache(fb_info.io, TRIDENT_IOSIZE);
 
@@ -1187,6 +1278,7 @@
 		return -1;
 	}
 
+	output("%s board found\n", dev->name);
 	debug("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
 		fb_info.fbmem, fb_info.io, fb_info.fbmem_virt, fb_info.io_virt);
 
@@ -1195,8 +1287,10 @@
 
 	strcpy(fb_info.gen.info.modename, tridentfb_name);
 	displaytype = get_displaytype();
+
 	if(flatpanel)
 		fb_info.nativex = get_nativex();
+
 	fb_info.gen.info.changevar = NULL;
 	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.fbops = &tridentfb_ops;
@@ -1212,6 +1306,7 @@
 
 	/* This should give a reasonable default video mode */
 	fb_find_mode(&default_var,&fb_info.gen.info,mode,NULL,0,NULL,bpp);
+
 	/*
 	 * Unless user explicitly requires accel/noaccel use
 	 * per chip defaults.Accel has priority over noaccel.
@@ -1221,7 +1316,7 @@
 	else if (noaccel)
 		defaultaccel = NOACCEL;
 
-	if (defaultaccel == ACCEL)
+	if (defaultaccel == ACCEL && acc)
 		default_var.accel_flags |= FB_ACCELF_TEXT;
 	else
 		default_var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -1242,13 +1337,60 @@
 	return 0;
 }
 
-void __exit tridentfb_exit(void)
+static void __devexit trident_pci_remove(struct pci_dev * dev)
 {
 	unregister_framebuffer(&fb_info.gen.info);
 	iounmap((void *)fb_info.io_virt);
 	iounmap((void *)fb_info.fbmem_virt);
+	release_mem_region(fb_info.fbmem, fb_info.memsize);
+	release_region(fb_info.io, TRIDENT_IOSIZE);
+}
+
+/* List of boards that we are trying to support */
+static struct pci_device_id trident_devices[] __devinitdata = {
+	{PCI_VENDOR_ID_TRIDENT,	BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci,trident_devices);
+
+static struct pci_driver tridentfb_pci_driver = {
+	name:"tridentfb",
+	id_table:trident_devices,
+	probe:trident_pci_probe,
+	remove:__devexit_p(trident_pci_remove),
+};
+
+int __init tridentfb_init(void)
+{
+	output("Trident framebuffer  %s initializing\n", VERSION);
+	return pci_module_init(&tridentfb_pci_driver);
+}
+
+void __exit tridentfb_exit(void)
+{
+	pci_unregister_driver(&tridentfb_pci_driver);
 }
 
+
 /*
  * Parse user specified options (`video=trident:')
  * example:
@@ -1301,6 +1443,7 @@
 #endif
 module_exit(tridentfb_exit);
 
-MODULE_AUTHOR("Jani Monoses <jani@astechnix.ro>");
+MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
 MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
 MODULE_LICENSE("GPL");
+
diff -urN linux-2.4.19-pre8/drivers/video/tridentfb.h linux-2.4.19-pre9/drivers/video/tridentfb.h
--- linux-2.4.19-pre8/drivers/video/tridentfb.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre9/drivers/video/tridentfb.h	Tue May 28 16:02:30 2002
@@ -41,9 +41,19 @@
 #define BLADE	1
 #define XP	2
 
-#define is_image()	(family == IMAGE)
-#define is_blade()	(family == BLADE)
-#define is_xp()		(family == XP)
+#define is_image(id)
+#define is_xp(id)	((id == CYBERBLADEXPAi1) ||\
+			 (id == CYBERBLADEXPm8) ||\
+			 (id == CYBERBLADEXPm16))
+
+#define is_blade(id)	((id == BLADE3D) ||\
+			 (id == CYBERBLADEE4) ||\
+			 (id == CYBERBLADEi7) ||\
+			 (id == CYBERBLADEi7D) ||\
+			 (id == CYBERBLADEi1) ||\
+			 (id == CYBERBLADEi1D) ||\
+			 (id ==	CYBERBLADEAi1) ||\
+			 (id ==	CYBERBLADEAi1D))
 
 /* these defines are for 'lcd' variable */
 #define LCD_STRETCH	0
@@ -60,8 +70,6 @@
 #define NOACCEL	0
 
 #define TRIDENT_IOSIZE	0x20000
-#define NTSC 14.31818
-#define PAL  17.73448
 
 /* General Registers */
 #define SPR	0x1F		/* Software Programming Register (videoram) */
diff -urN linux-2.4.19-pre8/fs/bfs/bfs_defs.h linux-2.4.19-pre9/fs/bfs/bfs_defs.h
--- linux-2.4.19-pre8/fs/bfs/bfs_defs.h	Sun Feb  6 18:43:21 2000
+++ linux-2.4.19-pre9/fs/bfs/bfs_defs.h	Tue May 28 16:02:30 2002
@@ -14,4 +14,7 @@
 #define iu_eblock	u.bfs_i.i_eblock
 
 #define printf(format, args...) \
-	printk(KERN_ERR "BFS-fs: " __FUNCTION__ "(): " format, ## args)
+do { \
+	printk(KERN_ERR "BFS-fs: %s(): ", __FUNCTION__); \
+	printk(format, args); \
+} while (0)
diff -urN linux-2.4.19-pre8/fs/binfmt_elf.c linux-2.4.19-pre9/fs/binfmt_elf.c
--- linux-2.4.19-pre8/fs/binfmt_elf.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/binfmt_elf.c	Tue May 28 16:02:30 2002
@@ -1281,3 +1281,4 @@
 
 module_init(init_elf_binfmt)
 module_exit(exit_elf_binfmt)
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre8/fs/binfmt_em86.c linux-2.4.19-pre9/fs/binfmt_em86.c
--- linux-2.4.19-pre8/fs/binfmt_em86.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.19-pre9/fs/binfmt_em86.c	Tue May 28 16:02:30 2002
@@ -110,3 +110,4 @@
 
 module_init(init_em86_binfmt)
 module_exit(exit_em86_binfmt)
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre8/fs/binfmt_script.c linux-2.4.19-pre9/fs/binfmt_script.c
--- linux-2.4.19-pre8/fs/binfmt_script.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.19-pre9/fs/binfmt_script.c	Tue May 28 16:02:30 2002
@@ -108,3 +108,4 @@
 
 module_init(init_script_binfmt)
 module_exit(exit_script_binfmt)
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre8/fs/block_dev.c linux-2.4.19-pre9/fs/block_dev.c
--- linux-2.4.19-pre8/fs/block_dev.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/block_dev.c	Tue May 28 16:02:30 2002
@@ -22,8 +22,6 @@
 
 #include <asm/uaccess.h>
 
-#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
-
 static unsigned long max_block(kdev_t dev)
 {
 	unsigned int retval = ~0U;
@@ -535,9 +533,6 @@
 	if (!bdops->check_media_change(dev))
 		return 0;
 
-	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
-		bdevname(dev));
-
 	if (invalidate_device(dev, 0))
 		printk("VFS: busy inodes on changed media.\n");
 
diff -urN linux-2.4.19-pre8/fs/buffer.c linux-2.4.19-pre9/fs/buffer.c
--- linux-2.4.19-pre8/fs/buffer.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/buffer.c	Tue May 28 16:02:30 2002
@@ -54,7 +54,6 @@
 #include <asm/bitops.h>
 #include <asm/mmu_context.h>
 
-#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
 #define NR_RESERVED (10*MAX_BUF_PER_PAGE)
 #define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 
 					     number of unused buffer heads */
diff -urN linux-2.4.19-pre8/fs/coda/cnode.c linux-2.4.19-pre9/fs/coda/cnode.c
--- linux-2.4.19-pre8/fs/coda/cnode.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/coda/cnode.c	Tue May 28 16:02:30 2002
@@ -81,9 +81,6 @@
 		/* new, empty inode found... initializing */
 		cii->c_fid = *fid;
 
-	/* we shouldnt see inode collisions anymore */
-	if (!coda_fideq(fid, &cii->c_fid)) BUG();
-
 	/* always replace the attributes, type might have changed */
 	coda_fill_inode(inode, attr);
 	return inode;
@@ -172,9 +169,6 @@
 		return NULL;
 	}
 
-	/* we shouldn't see inode collisions anymore */
-	if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
-
         CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
 	return inode;
 }
diff -urN linux-2.4.19-pre8/fs/coda/dir.c linux-2.4.19-pre9/fs/coda/dir.c
--- linux-2.4.19-pre8/fs/coda/dir.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/coda/dir.c	Tue May 28 16:02:30 2002
@@ -491,6 +491,7 @@
 	struct dentry *coda_dentry = coda_file->f_dentry;
 	struct coda_file_info *cfi;
 	struct file *host_file;
+	int ret;
 
 	cfi = CODA_FTOC(coda_file);
 	if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG();
@@ -498,12 +499,21 @@
 
 	coda_vfs_stat.readdir++;
 
-	if ( host_file->f_op->readdir )
+	down(&host_file->f_dentry->d_inode->i_sem);
+	host_file->f_pos = coda_file->f_pos;
+
+	if ( !host_file->f_op->readdir ) {
+		/* Venus: we must read Venus dirents from the file */
+		ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
+	} else {
 		/* potemkin case: we were handed a directory inode */
-		return vfs_readdir(host_file, filldir, dirent);
+		ret = vfs_readdir(host_file, filldir, dirent);
+	}
+
+	coda_file->f_pos = host_file->f_pos;
+	up(&host_file->f_dentry->d_inode->i_sem);
 
-	/* Venus: we must read Venus dirents from the file */
-	return coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
+	return ret;
 }
 
 static inline unsigned int CDT2DT(unsigned char cdt)
@@ -736,7 +746,6 @@
 	return 0;
 
 return_bad_inode:
-	make_bad_inode(inode);
 	unlock_kernel();
 	return -EIO;
 }
diff -urN linux-2.4.19-pre8/fs/coda/file.c linux-2.4.19-pre9/fs/coda/file.c
--- linux-2.4.19-pre8/fs/coda/file.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/coda/file.c	Tue May 28 16:02:30 2002
@@ -48,7 +48,7 @@
 static ssize_t
 coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos)
 {
-	struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
+	struct inode *coda_inode = coda_file->f_dentry->d_inode;
 	struct coda_file_info *cfi;
 	struct file *host_file;
 	ssize_t ret;
@@ -60,12 +60,11 @@
 	if (!host_file->f_op || !host_file->f_op->write)
 		return -EINVAL;
 
-	host_inode = host_file->f_dentry->d_inode;
 	down(&coda_inode->i_sem);
 
 	ret = host_file->f_op->write(host_file, buf, count, ppos);
 
-	coda_inode->i_size = host_inode->i_size;
+	coda_inode->i_size = host_file->f_dentry->d_inode->i_size;
 	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
 	coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME;
 	up(&coda_inode->i_sem);
@@ -96,8 +95,8 @@
 	unsigned short flags = coda_file->f_flags & (~O_EXCL);
 	unsigned short coda_flags = coda_flags_to_cflags(flags);
 	struct coda_file_info *cfi;
+	struct inode *host_inode;
 
-	lock_kernel();
 	coda_vfs_stat.open++;
 
 	cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
@@ -106,6 +105,8 @@
 		return -ENOMEM;
 	}
 
+	lock_kernel();
+
 	error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
 			   &host_file); 
 	if (error || !host_file) {
@@ -120,6 +121,18 @@
 	cfi->cfi_container = host_file;
 	coda_load_creds(&cfi->cfi_cred);
 
+	host_inode = host_file->f_dentry->d_inode;
+	if (coda_inode->i_mapping == &coda_inode->i_data)
+		coda_inode->i_mapping = host_inode->i_mapping;
+
+	else if (coda_inode->i_mapping != host_inode->i_mapping) {
+		/* This is not a good thing, it doesn't happen with 'venus'
+		 * Coda's own userspace daemon, but others might not provide
+		 * the same guarantees. Still looking for the real fix. */
+		printk("coda_open: changed mapping\n");
+		coda_inode->i_mapping = host_inode->i_mapping;
+	}
+
 	if (coda_file->private_data != NULL) BUG();
 	coda_file->private_data = cfi;
 
@@ -190,7 +203,9 @@
 		err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
 				  coda_flags, &cfi->cfi_cred);
 
+	coda_inode->i_mapping = &coda_inode->i_data;
 	fput(cfi->cfi_container);
+
 	kfree(coda_file->private_data);
 	coda_file->private_data = NULL;
 
diff -urN linux-2.4.19-pre8/fs/devfs/base.c linux-2.4.19-pre9/fs/devfs/base.c
--- linux-2.4.19-pre8/fs/devfs/base.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/devfs/base.c	Tue May 28 16:02:30 2002
@@ -615,6 +615,11 @@
     20020219   Richard Gooch <rgooch@atnf.csiro.au>
 	       Changed <devfs_rmdir> to allow later additions if not yet empty.
   v1.12
+    20020514   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added BKL to <devfs_open> because drivers still need it.
+	       Protected <scan_dir_for_removable> and <get_removable_partition>
+	       from changing directory contents.
+  v1.12a
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -647,7 +652,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.12 (20020219)"
+#define DEVFS_VERSION            "1.12a (20020514)"
 
 #define DEVFS_NAME "devfs"
 
@@ -2422,6 +2427,9 @@
  *	@de: The device.
  *
  *	Returns 1 if the media was changed, else 0.
+ *
+ *	This function may block, and may indirectly cause the parent directory
+ *	contents to be changed due to partition re-reading.
  */
 
 static int check_disc_changed (struct devfs_entry *de)
@@ -2456,19 +2464,29 @@
 /**
  *	scan_dir_for_removable - Scan a directory for removable media devices and check media.
  *	@dir: The directory.
+ *
+ *	This function may block, and may indirectly cause the directory
+ *	contents to be changed due to partition re-reading. The directory will
+ *	be locked for reading.
  */
 
 static void scan_dir_for_removable (struct devfs_entry *dir)
 {
     struct devfs_entry *de;
 
-    if (dir->u.dir.num_removable < 1) return;
-    for (de = dir->u.dir.first; de != NULL; de = de->next)
+    read_lock (&dir->u.dir.lock);
+    if (dir->u.dir.num_removable < 1) de = NULL;
+    else
     {
-	if ( !S_ISBLK (de->mode) ) continue;
-	if (!de->u.fcb.removable) continue;
-	check_disc_changed (de);
+	for (de = dir->u.dir.first; de != NULL; de = de->next)
+	{
+	    if (S_ISBLK (de->mode) && de->u.fcb.removable) break;
+	}
+	devfs_get (de);
     }
+    read_unlock (&dir->u.dir.lock);
+    if (de) check_disc_changed (de);
+    devfs_put (de);
 }   /*  End Function scan_dir_for_removable  */
 
 /**
@@ -2478,25 +2496,37 @@
  *	@namelen: The number of characters in <<name>>.
  *
  *	Returns 1 if the media was changed, else 0.
+ *
+ *	This function may block, and may indirectly cause the directory
+ *	contents to be changed due to partition re-reading. The directory must
+ *	be locked for reading upon entry, and will be unlocked upon exit.
  */
 
 static int get_removable_partition (struct devfs_entry *dir, const char *name,
 				    unsigned int namelen)
 {
+    int retval;
     struct devfs_entry *de;
 
+    if (dir->u.dir.num_removable < 1)
+    {
+	read_unlock (&dir->u.dir.lock);
+	return 0;
+    }
     for (de = dir->u.dir.first; de != NULL; de = de->next)
     {
-	if ( !S_ISBLK (de->mode) ) continue;
-	if (!de->u.fcb.removable) continue;
-	if (strcmp (de->name, "disc") == 0) return check_disc_changed (de);
+	if (!S_ISBLK (de->mode) || !de->u.fcb.removable) continue;
+	if (strcmp (de->name, "disc") == 0) break;
 	/*  Support for names where the partition is appended to the disc name
 	 */
 	if (de->namelen >= namelen) continue;
-	if (strncmp (de->name, name, de->namelen) != 0) continue;
-	return check_disc_changed (de);
+	if (strncmp (de->name, name, de->namelen) == 0) break;
     }
-    return 0;
+    devfs_get (de);
+    read_unlock (&dir->u.dir.lock);
+    retval = de ? check_disc_changed (de) : 0;
+    devfs_put (de);
+    return retval;
 }   /*  End Function get_removable_partition  */
 
 
@@ -2745,15 +2775,22 @@
     {
 	file->f_op = &def_blk_fops;
 	if (df->ops) inode->i_bdev->bd_op = df->ops;
+	err = def_blk_fops.open (inode, file);
     }
-    else file->f_op = fops_get ( (struct file_operations *) df->ops );
-    if (file->f_op)
-	err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
     else
     {
-	/*  Fallback to legacy scheme  */
-	if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
-	else err = -ENODEV;
+	file->f_op = fops_get ( (struct file_operations *) df->ops );
+	if (file->f_op)
+	{
+	    lock_kernel ();
+	    err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
+	    unlock_kernel ();
+	}
+	else
+	{   /*  Fallback to legacy scheme  */
+	    if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
+	    else err = -ENODEV;
+	}
     }
     if (err < 0) return err;
     /*  Open was successful  */
@@ -2953,15 +2990,17 @@
     if (parent == NULL) return ERR_PTR (-ENOENT);
     read_lock (&parent->u.dir.lock);
     de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
-    read_unlock (&parent->u.dir.lock);
-    if ( (de == NULL) && (parent->u.dir.num_removable > 0) &&
-	 get_removable_partition (parent, dentry->d_name.name,
-				  dentry->d_name.len) )
-    {
-	read_lock (&parent->u.dir.lock);
-	de = _devfs_search_dir (parent, dentry->d_name.name,
-				dentry->d_name.len);
-	read_unlock (&parent->u.dir.lock);
+    if (de) read_unlock (&parent->u.dir.lock);
+    else
+    {   /*  Try re-reading the partition (media may have changed)  */
+	if ( get_removable_partition (parent, dentry->d_name.name,
+				      dentry->d_name.len) )  /*  Unlocks  */
+	{   /*  Media did change  */
+	    read_lock (&parent->u.dir.lock);
+	    de = _devfs_search_dir (parent, dentry->d_name.name,
+				    dentry->d_name.len);
+	    read_unlock (&parent->u.dir.lock);
+	}
     }
     lookup_info.de = de;
     init_waitqueue_head (&lookup_info.wait_queue);
diff -urN linux-2.4.19-pre8/fs/devfs/util.c linux-2.4.19-pre9/fs/devfs/util.c
--- linux-2.4.19-pre8/fs/devfs/util.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/devfs/util.c	Tue May 28 16:02:30 2002
@@ -56,6 +56,8 @@
                Made major bitfield type and initialiser 64 bit safe.
     20020413   Richard Gooch <rgooch@atnf.csiro.au>
                Fixed shift warning on 64 bit machines.
+    20020428   Richard Gooch <rgooch@atnf.csiro.au>
+               Copied and used macro for error messages from fs/devfs/base.c 
 */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -65,6 +67,9 @@
 
 #include <asm/bitops.h>
 
+#define PRINTK(format, args...) \
+   {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
+
 
 /*  Private functions follow  */
 
@@ -209,9 +214,7 @@
     spin_lock (&list->lock);
     was_set = __test_and_clear_bit (major, list->bits);
     spin_unlock (&list->lock);
-    if (!was_set)
-	printk (KERN_ERR __FUNCTION__ "(): major %d was already free\n",
-		major);
+    if (!was_set) PRINTK ("(): major %d was already free\n", major);
 }   /*  End Function devfs_dealloc_major  */
 EXPORT_SYMBOL(devfs_dealloc_major);
 
@@ -339,12 +342,11 @@
 	if (was_set) list->none_free = 0;
 	up (semaphore);
 	if (!was_set)
-	    printk ( KERN_ERR __FUNCTION__ "(): device %s was already free\n",
-		     kdevname (devnum) );
+	    PRINTK ( "(): device %s was already free\n", kdevname (devnum) );
 	return;
     }
     up (semaphore);
-    printk ( KERN_ERR __FUNCTION__ "(): major for %s not previously allocated\n",
+    PRINTK ( "(): major for %s not previously allocated\n",
 	     kdevname (devnum) );
 }   /*  End Function devfs_dealloc_devnum  */
 EXPORT_SYMBOL(devfs_dealloc_devnum);
@@ -419,8 +421,6 @@
     was_set = __test_and_clear_bit (number, space->bits);
     if (was_set) ++space->num_free;
     up (&space->semaphore);
-    if (!was_set)
-	printk (KERN_ERR __FUNCTION__ "(): number %d was already free\n",
-		number);
+    if (!was_set) PRINTK ("(): number %d was already free\n", number);
 }   /*  End Function devfs_dealloc_unique_number  */
 EXPORT_SYMBOL(devfs_dealloc_unique_number);
diff -urN linux-2.4.19-pre8/fs/dnotify.c linux-2.4.19-pre9/fs/dnotify.c
--- linux-2.4.19-pre8/fs/dnotify.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/dnotify.c	Tue May 28 16:02:30 2002
@@ -38,60 +38,74 @@
 	inode->i_dnotify_mask = new_mask;
 }
 
+void dnotify_flush(struct file *filp, fl_owner_t id)
+{
+	struct dnotify_struct *dn;
+	struct dnotify_struct **prev;
+	struct inode *inode;
+
+	inode = filp->f_dentry->d_inode;
+	if (!S_ISDIR(inode->i_mode))
+		return;
+	write_lock(&dn_lock);
+	prev = &inode->i_dnotify;
+	while ((dn = *prev) != NULL) {
+		if ((dn->dn_owner == id) && (dn->dn_filp == filp)) {
+			*prev = dn->dn_next;
+			redo_inode_mask(inode);
+			kmem_cache_free(dn_cache, dn);
+			break;
+		}
+		prev = &dn->dn_next;
+	}
+	write_unlock(&dn_lock);
+}
+
 int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
 {
-	struct dnotify_struct *dn = NULL;
+	struct dnotify_struct *dn;
 	struct dnotify_struct *odn;
 	struct dnotify_struct **prev;
 	struct inode *inode;
-	int turning_off = (arg & ~DN_MULTISHOT) == 0;
+	fl_owner_t id = current->files;
 
-	if (!turning_off && !dir_notify_enable)
+	if ((arg & ~DN_MULTISHOT) == 0) {
+		dnotify_flush(filp, id);
+		return 0;
+	}
+	if (!dir_notify_enable)
 		return -EINVAL;
 	inode = filp->f_dentry->d_inode;
 	if (!S_ISDIR(inode->i_mode))
 		return -ENOTDIR;
-	if (!turning_off) {
-		dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
-		if (dn == NULL)
-			return -ENOMEM;
-	}
+	dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
+	if (dn == NULL)
+		return -ENOMEM;
 	write_lock(&dn_lock);
 	prev = &inode->i_dnotify;
-	for (odn = *prev; odn != NULL; prev = &odn->dn_next, odn = *prev)
-		if ((odn->dn_owner == current->files) && (odn->dn_filp == filp))
-			break;
-	if (odn != NULL) {
-		if (turning_off) {
-			*prev = odn->dn_next;
-			redo_inode_mask(inode);
-			dn = odn;
-			goto out_free;
+	while ((odn = *prev) != NULL) {
+		if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
+			odn->dn_fd = fd;
+			odn->dn_mask |= arg;
+			inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
+			kmem_cache_free(dn_cache, dn);
+			goto out;
 		}
-		odn->dn_fd = fd;
-		odn->dn_mask |= arg;
-		inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
-		goto out_free;
+		prev = &odn->dn_next;
 	}
-	if (turning_off)
-		goto out;
 	filp->f_owner.pid = current->pid;
 	filp->f_owner.uid = current->uid;
 	filp->f_owner.euid = current->euid;
-	dn->dn_magic = DNOTIFY_MAGIC;
 	dn->dn_mask = arg;
 	dn->dn_fd = fd;
 	dn->dn_filp = filp;
-	dn->dn_owner = current->files;
+	dn->dn_owner = id;
 	inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
 	dn->dn_next = inode->i_dnotify;
 	inode->i_dnotify = dn;
 out:
 	write_unlock(&dn_lock);
 	return 0;
-out_free:
-	kmem_cache_free(dn_cache, dn);
-	goto out;
 }
 
 void __inode_dir_notify(struct inode *inode, unsigned long event)
@@ -104,11 +118,6 @@
 	write_lock(&dn_lock);
 	prev = &inode->i_dnotify;
 	while ((dn = *prev) != NULL) {
-		if (dn->dn_magic != DNOTIFY_MAGIC) {
-		        printk(KERN_ERR "__inode_dir_notify: bad magic "
-				"number in dnotify_struct!\n");
-		        goto out;
-		}
 		if ((dn->dn_mask & event) == 0) {
 			prev = &dn->dn_next;
 			continue;
diff -urN linux-2.4.19-pre8/fs/file.c linux-2.4.19-pre9/fs/file.c
--- linux-2.4.19-pre8/fs/file.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/file.c	Tue May 28 16:02:30 2002
@@ -36,7 +36,8 @@
 	int size = num * sizeof(struct file *);
 
 	if (!array) {
-		printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+		printk(KERN_ERR "%s array = 0 (num = %d)\n",
+				__FUNCTION__, num);
 		return;
 	}
 
@@ -145,7 +146,8 @@
 	int size = num / 8;
 
 	if (!array) {
-		printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+		printk(KERN_ERR "%s array = 0 (num = %d)\n",
+				__FUNCTION__, num);
 		return;
 	}
 	
diff -urN linux-2.4.19-pre8/fs/hpfs/super.c linux-2.4.19-pre9/fs/hpfs/super.c
--- linux-2.4.19-pre8/fs/hpfs/super.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/hpfs/super.c	Tue May 28 16:02:30 2002
@@ -584,3 +584,4 @@
 
 module_init(init_hpfs_fs)
 module_exit(exit_hpfs_fs)
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre8/fs/intermezzo/psdev.c linux-2.4.19-pre9/fs/intermezzo/psdev.c
--- linux-2.4.19-pre8/fs/intermezzo/psdev.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre9/fs/intermezzo/psdev.c	Tue May 28 16:02:30 2002
@@ -46,6 +46,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <asm/io.h>
+#include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
diff -urN linux-2.4.19-pre8/fs/jffs2/gc.c linux-2.4.19-pre9/fs/jffs2/gc.c
--- linux-2.4.19-pre8/fs/jffs2/gc.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/jffs2/gc.c	Tue May 28 16:02:30 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: gc.c,v 1.52.2.2 2002/02/23 14:25:36 dwmw2 Exp $
+ * $Id: gc.c,v 1.52.2.3 2002/05/12 17:27:08 dwmw2 Exp $
  *
  */
 
@@ -497,9 +497,21 @@
 			jffs2_mark_node_obsolete(c, f->metadata->raw);
 			jffs2_free_full_dnode(f->metadata);
 			f->metadata = NULL;
-			return 0;
 		}
+		return 0;
 	}
+
+	/* 
+	 * We should only get here in the case where the node we are
+	 * replacing had more than one frag, so we kept the same version
+	 * number as before. (Except in case of error -- see 'goto fill;' 
+	 * above.)
+	 */
+	D1(if(unlikely(fn->frags <= 1)) {
+		printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
+		       fn->frags, ri.version, f->highest_version, ri.ino);
+	});
+
 	for (frag = f->fraglist; frag; frag = frag->next) {
 		if (frag->ofs > fn->size + fn->ofs)
 			break;
diff -urN linux-2.4.19-pre8/fs/jffs2/nodelist.c linux-2.4.19-pre9/fs/jffs2/nodelist.c
--- linux-2.4.19-pre8/fs/jffs2/nodelist.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/jffs2/nodelist.c	Tue May 28 16:02:30 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.c,v 1.30.2.3 2002/02/23 14:04:44 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.30.2.4 2002/05/10 18:30:33 dwmw2 Exp $
  *
  */
 
@@ -69,7 +69,7 @@
 	*prev = new;
 
  out:
-	D1(while(*list) {
+	D2(while(*list) {
 		printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino);
 		list = &(*list)->next;
 	});
diff -urN linux-2.4.19-pre8/fs/nfs/nfsroot.c linux-2.4.19-pre9/fs/nfs/nfsroot.c
--- linux-2.4.19-pre8/fs/nfs/nfsroot.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/nfs/nfsroot.c	Tue May 28 16:02:30 2002
@@ -343,8 +343,8 @@
 {
 	struct sockaddr_in sin;
 
-	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
-		program, version, in_ntoa(servaddr));
+	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
+		program, version, NIPQUAD(servaddr));
 	set_sockaddr(&sin, servaddr, 0);
 	return rpc_getport_external(&sin, program, version, proto);
 }
diff -urN linux-2.4.19-pre8/fs/nfsd/nfssvc.c linux-2.4.19-pre9/fs/nfsd/nfssvc.c
--- linux-2.4.19-pre8/fs/nfsd/nfssvc.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.19-pre9/fs/nfsd/nfssvc.c	Tue May 28 16:02:30 2002
@@ -66,7 +66,7 @@
 /*
  * Maximum number of nfsd processes
  */
-#define	NFSD_MAXSERVS		128
+#define	NFSD_MAXSERVS		8192
 
 int
 nfsd_svc(unsigned short port, int nrservs)
@@ -87,6 +87,7 @@
 	if (error<0)
 		goto out;
 	if (!nfsd_serv) {
+		error = -ENOMEM;
 		nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
 		if (nfsd_serv == NULL)
 			goto out;
diff -urN linux-2.4.19-pre8/fs/open.c linux-2.4.19-pre9/fs/open.c
--- linux-2.4.19-pre8/fs/open.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/open.c	Tue May 28 16:02:30 2002
@@ -857,7 +857,7 @@
 		retval = filp->f_op->flush(filp);
 		unlock_kernel();
 	}
-	fcntl_dirnotify(0, filp, 0);
+	dnotify_flush(filp, id);
 	locks_remove_posix(filp, id);
 	fput(filp);
 	return retval;
diff -urN linux-2.4.19-pre8/fs/partitions/acorn.c linux-2.4.19-pre9/fs/partitions/acorn.c
--- linux-2.4.19-pre8/fs/partitions/acorn.c	Mon Oct  1 20:03:26 2001
+++ linux-2.4.19-pre9/fs/partitions/acorn.c	Tue May 28 16:02:30 2002
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 
 #include "check.h"
 #include "acorn.h"
diff -urN linux-2.4.19-pre8/fs/partitions/mac.c linux-2.4.19-pre9/fs/partitions/mac.c
--- linux-2.4.19-pre8/fs/partitions/mac.c	Mon Oct  1 20:03:26 2001
+++ linux-2.4.19-pre9/fs/partitions/mac.c	Tue May 28 16:02:30 2002
@@ -20,22 +20,10 @@
 #include "check.h"
 #include "mac.h"
 
-#ifdef CONFIG_ALL_PPC
-extern void note_bootable_part(kdev_t dev, int part, int goodness);
-#endif
-
 /*
  * Code to understand MacOS partition tables.
  */
 
-static inline void mac_fix_string(char *stg, int len)
-{
-	int i;
-
-	for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
-		stg[i] = 0;
-}
-
 int mac_partition(struct gendisk *hd, struct block_device *bdev,
 		unsigned long fsec, int first_part_minor)
 {
@@ -43,10 +31,6 @@
 	unsigned char *data;
 	int blk, blocks_in_map;
 	unsigned secsize;
-#ifdef CONFIG_ALL_PPC
-	int found_root = 0;
-	int found_root_goodness = 0;
-#endif
 	struct mac_partition *part;
 	struct mac_driver_desc *md;
 
@@ -83,56 +67,8 @@
 			fsec + be32_to_cpu(part->start_block) * (secsize/512),
 			be32_to_cpu(part->block_count) * (secsize/512));
 
-#ifdef CONFIG_ALL_PPC
-		/*
-		 * If this is the first bootable partition, tell the
-		 * setup code, in case it wants to make this the root.
-		 */
-		if (_machine == _MACH_Pmac) {
-			int goodness = 0;
-
-			mac_fix_string(part->processor, 16);
-			mac_fix_string(part->name, 32);
-			mac_fix_string(part->type, 32);					
-		    
-			if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
-			    && strcasecmp(part->processor, "powerpc") == 0)
-				goodness++;
-
-			if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
-			    || (strnicmp(part->type, "Linux", 5) == 0
-			        && strcasecmp(part->type, "Linux_swap") != 0)) {
-				int i, l;
-
-				goodness++;
-				l = strlen(part->name);
-				if (strcmp(part->name, "/") == 0)
-					goodness++;
-				for (i = 0; i <= l - 4; ++i) {
-					if (strnicmp(part->name + i, "root",
-						     4) == 0) {
-						goodness += 2;
-						break;
-					}
-				}
-				if (strnicmp(part->name, "swap", 4) == 0)
-					goodness--;
-			}
-
-			if (goodness > found_root_goodness) {
-				found_root = blk;
-				found_root_goodness = goodness;
-			}
-		}
-#endif /* CONFIG_ALL_PPC */
-
 		++first_part_minor;
 	}
-#ifdef CONFIG_ALL_PPC
-	if (found_root_goodness)
-		note_bootable_part(to_kdev_t(bdev->bd_dev),
-					found_root, found_root_goodness);
-#endif
 
 	put_dev_sector(sect);
 	printk("\n");
diff -urN linux-2.4.19-pre8/fs/partitions/mac.h linux-2.4.19-pre9/fs/partitions/mac.h
--- linux-2.4.19-pre8/fs/partitions/mac.h	Mon Oct  1 20:03:26 2001
+++ linux-2.4.19-pre9/fs/partitions/mac.h	Tue May 28 16:02:30 2002
@@ -29,6 +29,14 @@
 	/* there is more stuff after this that we don't need */
 };
 
+static inline void macpart_fix_string(char *stg, int len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
+		stg[i] = 0;
+}
+
 #define MAC_STATUS_BOOTABLE	8	/* partition is bootable */
 
 #define MAC_DRIVER_MAGIC	0x4552
diff -urN linux-2.4.19-pre8/fs/proc/proc_misc.c linux-2.4.19-pre9/fs/proc/proc_misc.c
--- linux-2.4.19-pre8/fs/proc/proc_misc.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/proc/proc_misc.c	Tue May 28 16:02:30 2002
@@ -41,7 +41,6 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 
-
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 /*
@@ -67,6 +66,27 @@
 extern int get_ds1286_status(char *);
 #endif
 
+void proc_sprintf(char *page, off_t *off, int *lenp, const char *format, ...)
+{
+	int len = *lenp;
+	va_list args;
+
+	/* try to only print whole lines */
+	if (len > PAGE_SIZE-512)
+		return;
+
+	va_start(args, format);
+	len += vsnprintf(page + len, PAGE_SIZE-len, format, args);
+	va_end(args);
+
+	if (len <= *off) {
+		*off -= len;
+		len = 0;
+	}
+
+	*lenp = len;
+}
+
 static int proc_calc_metrics(char *page, char **start, off_t off,
 				 int count, int *eof, int len)
 {
@@ -258,7 +278,7 @@
 static int kstat_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
-	int i, len;
+	int i, len = 0;
 	extern unsigned long total_forks;
 	unsigned long jif = jiffies;
 	unsigned int sum = 0, user = 0, nice = 0, system = 0;
@@ -276,10 +296,12 @@
 #endif
 	}
 
-	len = sprintf(page, "cpu  %u %u %u %lu\n", user, nice, system,
+	proc_sprintf(page, &off, &len,
+		      "cpu  %u %u %u %lu\n", user, nice, system,
 		      jif * smp_num_cpus - (user + nice + system));
 	for (i = 0 ; i < smp_num_cpus; i++)
-		len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
+		proc_sprintf(page, &off, &len,
+			"cpu%d %u %u %u %lu\n",
 			i,
 			kstat.per_cpu_user[cpu_logical_map(i)],
 			kstat.per_cpu_nice[cpu_logical_map(i)],
@@ -287,7 +309,7 @@
 			jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
 				   + kstat.per_cpu_nice[cpu_logical_map(i)] \
 				   + kstat.per_cpu_system[cpu_logical_map(i)]));
-	len += sprintf(page + len,
+	proc_sprintf(page, &off, &len,
 		"page %u %u\n"
 		"swap %u %u\n"
 		"intr %u",
@@ -299,10 +321,11 @@
 	);
 #if !defined(CONFIG_ARCH_S390)
 	for (i = 0 ; i < NR_IRQS ; i++)
-		len += sprintf(page + len, " %u", kstat_irqs(i));
+		proc_sprintf(page, &off, &len,
+			     " %u", kstat_irqs(i) + 1000000000);
 #endif
 
-	len += sprintf(page + len, "\ndisk_io: ");
+	proc_sprintf(page, &off, &len, "\ndisk_io: ");
 
 	for (major = 0; major < DK_MAX_MAJOR; major++) {
 		for (disk = 0; disk < DK_MAX_DISK; disk++) {
@@ -310,7 +333,7 @@
 				kstat.dk_drive_rblk[major][disk] +
 				kstat.dk_drive_wblk[major][disk];
 			if (active)
-				len += sprintf(page + len,
+				proc_sprintf(page, &off, &len,
 					"(%u,%u):(%u,%u,%u,%u,%u) ",
 					major, disk,
 					kstat.dk_drive[major][disk],
@@ -322,7 +345,7 @@
 		}
 	}
 
-	len += sprintf(page + len,
+	proc_sprintf(page, &off, &len,
 		"\nctxt %u\n"
 		"btime %lu\n"
 		"processes %lu\n",
@@ -384,8 +407,7 @@
 	extern char saved_command_line[];
 	int len;
 
-	len = sprintf(page, "%s\n", saved_command_line);
-	len = strlen(page);
+	len = snprintf(page, count, "%s\n", saved_command_line);
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
diff -urN linux-2.4.19-pre8/fs/ufs/super.c linux-2.4.19-pre9/fs/ufs/super.c
--- linux-2.4.19-pre8/fs/ufs/super.c	Tue May 28 16:02:22 2002
+++ linux-2.4.19-pre9/fs/ufs/super.c	Tue May 28 16:02:30 2002
@@ -662,13 +662,13 @@
 			uspi->s_fsize);
 		goto failed;
 	}
-	if (uspi->s_bsize < 512) {
-		printk("ufs_read_super: fragment size %u is too small\n"
+	if (uspi->s_fsize < 512) {
+		printk("ufs_read_super: fragment size %u is too small\n",
 			uspi->s_fsize);
 		goto failed;
 	}
-	if (uspi->s_bsize > 4096) {
-		printk("ufs_read_super: fragment size %u is too large\n"
+	if (uspi->s_fsize > 4096) {
+		printk("ufs_read_super: fragment size %u is too large\n",
 			uspi->s_fsize);
 		goto failed;
 	}
@@ -678,12 +678,12 @@
 		goto failed;
 	}
 	if (uspi->s_bsize < 4096) {
-		printk("ufs_read_super: block size %u is too small\n"
+		printk("ufs_read_super: block size %u is too small\n",
 			uspi->s_fsize);
 		goto failed;
 	}
 	if (uspi->s_bsize / uspi->s_fsize > 8) {
-		printk("ufs_read_super: too many fragments per block (%u)\n"
+		printk("ufs_read_super: too many fragments per block (%u)\n",
 			uspi->s_bsize / uspi->s_fsize);
 		goto failed;
 	}
diff -urN linux-2.4.19-pre8/include/asm-i386/floppy.h linux-2.4.19-pre9/include/asm-i386/floppy.h
--- linux-2.4.19-pre8/include/asm-i386/floppy.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre9/include/asm-i386/floppy.h	Tue May 28 16:02:30 2002
@@ -75,28 +75,28 @@
 
 #ifndef NO_FLOPPY_ASSEMBLER
 	__asm__ (
-       "testl %1,%1
-	je 3f
-1:	inb %w4,%b0
-	andb $160,%b0
-	cmpb $160,%b0
-	jne 2f
-	incw %w4
-	testl %3,%3
-	jne 4f
-	inb %w4,%b0
-	movb %0,(%2)
-	jmp 5f
-4:     	movb (%2),%0
-	outb %b0,%w4
-5:	decw %w4
-	outb %0,$0x80
-	decl %1
-	incl %2
-	testl %1,%1
-	jne 1b
-3:	inb %w4,%b0
-2:	"
+       "testl %1,%1"
+	"je 3f"
+"1:	inb %w4,%b0"
+	"andb $160,%b0"
+	"cmpb $160,%b0"
+	"jne 2f"
+	"incw %w4"
+	"testl %3,%3"
+	"jne 4f"
+	"inb %w4,%b0"
+	"movb %0,(%2)"
+	"jmp 5f"
+"4:    	movb (%2),%0"
+	"outb %b0,%w4"
+"5:	decw %w4"
+	"outb %0,$0x80"
+	"decl %1"
+	"incl %2"
+	"testl %1,%1"
+	"jne 1b"
+"3:	inb %w4,%b0"
+"2:	"
        : "=a" ((char) st), 
        "=c" ((long) virtual_dma_count), 
        "=S" ((long) virtual_dma_addr)
diff -urN linux-2.4.19-pre8/include/asm-ppc/machdep.h linux-2.4.19-pre9/include/asm-ppc/machdep.h
--- linux-2.4.19-pre8/include/asm-ppc/machdep.h	Tue May 28 16:02:24 2002
+++ linux-2.4.19-pre9/include/asm-ppc/machdep.h	Tue May 28 16:02:31 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.machdep.h 1.29 02/14/02 17:27:01 trini
+ * BK Id: SCCS/s.machdep.h 1.31 03/19/02 14:19:28 benh
  */
 #ifdef __KERNEL__
 #ifndef _PPC_MACHDEP_H
@@ -56,6 +56,9 @@
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
+	/* Called from prepare_namespace() */
+	void		(*discover_root)(void);
+
 	/* Tons of keyboard stuff. */
 	int		(*kbd_setkeycode)(unsigned int scancode,
 				unsigned int keycode);
diff -urN linux-2.4.19-pre8/include/asm-ppc/processor.h linux-2.4.19-pre9/include/asm-ppc/processor.h
--- linux-2.4.19-pre8/include/asm-ppc/processor.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/asm-ppc/processor.h	Tue May 28 16:02:31 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.processor.h 1.35 03/19/02 15:04:39 benh
+ * BK Id: SCCS/s.processor.h 1.37 05/06/02 01:37:30 benh
  */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
@@ -191,8 +191,11 @@
 #define	  HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
 #define	  HID0_SBCLK	(1<<27)
 #define	  HID0_EICE	(1<<26)
+#define	  HID0_TBEN	(1<<26)		/* Timebase enable - 745x */
 #define	  HID0_ECLK	(1<<25)
 #define	  HID0_PAR	(1<<24)
+#define	  HID0_STEN	(1<<24)		/* Software table search enable - 745x */
+#define	  HID0_HIGH_BAT	(1<<23)		/* Enable high BATs - 7455 */
 #define	  HID0_DOZE	(1<<23)
 #define	  HID0_NAP	(1<<22)
 #define	  HID0_SLEEP	(1<<21)
@@ -208,8 +211,9 @@
 #define	  HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
 #define	  HID0_DFCA	(1<<6)		/* Data Cache Flush Assist */
 #define   HID0_BTIC	(1<<5)		/* Branch Target Instruction Cache Enable */
+#define   HID0_LRSTK	(1<<4)		/* Link register stack - 745x */
 #define   HID0_ABE	(1<<3)		/* Address Broadcast Enable */
-#define   HID0_FOLD	(1<<3)		/* Branch Folding enable - 7450 */
+#define   HID0_FOLD	(1<<3)		/* Branch Folding enable - 745x */
 #define	  HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 #define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
 #define	  HID0_NOPDST	(1<<1)		/* No-op dst, dstt, etc. instr. */
diff -urN linux-2.4.19-pre8/include/asm-ppc/uaccess.h linux-2.4.19-pre9/include/asm-ppc/uaccess.h
--- linux-2.4.19-pre8/include/asm-ppc/uaccess.h	Tue Sep 11 17:03:33 2001
+++ linux-2.4.19-pre9/include/asm-ppc/uaccess.h	Tue May 28 16:02:31 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.uaccess.h 1.8 09/11/01 18:10:06 paulus
+ * BK Id: SCCS/s.uaccess.h 1.10 05/21/02 21:44:32 paulus
  */
 #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 -urN linux-2.4.19-pre8/include/asm-sparc/pgalloc.h linux-2.4.19-pre9/include/asm-sparc/pgalloc.h
--- linux-2.4.19-pre8/include/asm-sparc/pgalloc.h	Sun Oct 21 10:36:54 2001
+++ linux-2.4.19-pre9/include/asm-sparc/pgalloc.h	Tue May 28 16:02:31 2002
@@ -117,7 +117,6 @@
 
 static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	BUG();
 	return 0;
 }
 
diff -urN linux-2.4.19-pre8/include/asm-sparc/sbus.h linux-2.4.19-pre9/include/asm-sparc/sbus.h
--- linux-2.4.19-pre8/include/asm-sparc/sbus.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/asm-sparc/sbus.h	Tue May 28 16:02:31 2002
@@ -112,13 +112,13 @@
 #define	SBUS_DMA_NONE		3
 
 /* All the rest use streaming mode mappings. */
-extern u32 sbus_map_single(struct sbus_dev *, void *, long, int);
-extern void sbus_unmap_single(struct sbus_dev *, u32, long, int);
+extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
+extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
 extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
 extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 /* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single(struct sbus_dev *, u32, long, int);
+extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int);
 extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
 #endif /* !(_SPARC_SBUS_H) */
diff -urN linux-2.4.19-pre8/include/asm-sparc/unistd.h linux-2.4.19-pre9/include/asm-sparc/unistd.h
--- linux-2.4.19-pre8/include/asm-sparc/unistd.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/asm-sparc/unistd.h	Tue May 28 16:02:31 2002
@@ -202,7 +202,7 @@
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
 /* #define __NR_pathconf        186    SunOS Specific                              */
-/* #define __NR_fpathconf       187    SunOS Specific                              */
+#define __NR_tkill              187 /* SunOS: fpathconf                            */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
@@ -271,7 +271,6 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
-#define __NR_tkill              257
 
 #define _syscall0(type,name) \
 type name(void) \
diff -urN linux-2.4.19-pre8/include/asm-sparc64/unistd.h linux-2.4.19-pre9/include/asm-sparc64/unistd.h
--- linux-2.4.19-pre8/include/asm-sparc64/unistd.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/asm-sparc64/unistd.h	Tue May 28 16:02:31 2002
@@ -202,7 +202,7 @@
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
 /* #define __NR_pathconf        186    SunOS Specific                              */
-/* #define __NR_fpathconf       187    SunOS Specific                              */
+#define __NR_tkill              187 /* SunOS: fpathconf                            */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
@@ -273,7 +273,6 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
-#define __NR_tkill              256
 
 #define _syscall0(type,name) \
 type name(void) \
diff -urN linux-2.4.19-pre8/include/linux/agp_backend.h linux-2.4.19-pre9/include/linux/agp_backend.h
--- linux-2.4.19-pre8/include/linux/agp_backend.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/agp_backend.h	Tue May 28 16:02:31 2002
@@ -48,6 +48,7 @@
 	INTEL_I815,
 	INTEL_I820,
 	INTEL_I830_M,
+	INTEL_I845_G,
 	INTEL_I840,
 	INTEL_I845,
 	INTEL_I850,
diff -urN linux-2.4.19-pre8/include/linux/brlvger.h linux-2.4.19-pre9/include/linux/brlvger.h
--- linux-2.4.19-pre8/include/linux/brlvger.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre9/include/linux/brlvger.h	Tue May 28 16:02:31 2002
@@ -0,0 +1,57 @@
+/*
+ *      Tieman Voyager braille display USB driver.
+ *
+ *      Copyright 2001-2002 Stephane Dalton <sdalton@videotron.ca>
+ *                      and Stéphane Doyon  <s.doyon@videotron.ca>
+ *            Maintained by Stéphane Doyon  <s.doyon@videotron.ca>.
+ */
+/*
+ *  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
+ */
+
+#ifndef _LINUX_BRLVGER_H
+#define _LINUX_BRLVGER_H
+
+/* Ioctl request codes */
+#define BRLVGER_GET_INFO	0
+#define BRLVGER_DISPLAY_ON	2
+#define BRLVGER_DISPLAY_OFF	3
+#define BRLVGER_BUZZ		4
+
+/* Number of supported devices, and range of covered minors */
+#define MAX_NR_BRLVGER_DEVS	4
+
+/* Base minor for the char devices */
+#define BRLVGER_MINOR		128
+
+/* Size of some fields */
+#define BRLVGER_HWVER_SIZE	2
+#define BRLVGER_FWVER_SIZE	200 /* arbitrary, a long string */
+#define BRLVGER_SERIAL_BIN_SIZE	8
+#define BRLVGER_SERIAL_SIZE	((2*BRLVGER_SERIAL_BIN_SIZE)+1)
+
+struct brlvger_info {
+	__u8 driver_version[12];
+	__u8 driver_banner[200];
+
+	__u32 display_length;
+	/* All other char[] fields are strings except this one.
+	   Hardware version: first byte is major, second byte is minor. */
+	__u8 hwver[BRLVGER_HWVER_SIZE];
+	__u8 fwver[BRLVGER_FWVER_SIZE];
+	__u8 serialnum[BRLVGER_SERIAL_SIZE];
+};
+
+#endif
diff -urN linux-2.4.19-pre8/include/linux/byteorder/generic.h linux-2.4.19-pre9/include/linux/byteorder/generic.h
--- linux-2.4.19-pre8/include/linux/byteorder/generic.h	Thu Jan 20 10:48:36 2000
+++ linux-2.4.19-pre9/include/linux/byteorder/generic.h	Tue May 28 16:02:31 2002
@@ -157,7 +157,7 @@
 extern unsigned short int	htons(unsigned short int);
 
 
-#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__)
+#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) && !defined(__STRICT_ANSI__)
 
 #define ___htonl(x) __cpu_to_be32(x)
 #define ___htons(x) __cpu_to_be16(x)
diff -urN linux-2.4.19-pre8/include/linux/dnotify.h linux-2.4.19-pre9/include/linux/dnotify.h
--- linux-2.4.19-pre8/include/linux/dnotify.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/dnotify.h	Tue May 28 16:02:31 2002
@@ -1,12 +1,11 @@
 /*
  * Directory notification for Linux
  *
- * Copyright 2000 (C) Stephen Rothwell
+ * Copyright (C) 2000,2002 Stephen Rothwell
  */
 
 struct dnotify_struct {
 	struct dnotify_struct *	dn_next;
-	int			dn_magic;
 	unsigned long		dn_mask;	/* Events to be notified
 						   see linux/fcntl.h */
 	int			dn_fd;
@@ -14,9 +13,8 @@
 	fl_owner_t		dn_owner;
 };
 
-#define DNOTIFY_MAGIC	0x444E4F54
-
 extern void __inode_dir_notify(struct inode *, unsigned long);
+extern void dnotify_flush(struct file *filp, fl_owner_t id);
 extern int fcntl_dirnotify(int, struct file *, unsigned long);
 
 static inline void inode_dir_notify(struct inode *inode, unsigned long event)
diff -urN linux-2.4.19-pre8/include/linux/fs.h linux-2.4.19-pre9/include/linux/fs.h
--- linux-2.4.19-pre8/include/linux/fs.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/fs.h	Tue May 28 16:02:31 2002
@@ -225,6 +225,8 @@
 			 */
 };
 
+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
+
 /*
  * Try to keep the most commonly used fields in single cache lines (16
  * bytes) to improve performance.  This ordering should be
diff -urN linux-2.4.19-pre8/include/linux/genhd.h linux-2.4.19-pre9/include/linux/genhd.h
--- linux-2.4.19-pre8/include/linux/genhd.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/genhd.h	Tue May 28 16:02:31 2002
@@ -108,6 +108,7 @@
 extern void add_gendisk(struct gendisk *gp);
 extern void del_gendisk(struct gendisk *gp);
 extern struct gendisk *get_gendisk(kdev_t dev);
+extern int walk_gendisk(int (*walk)(struct gendisk *, void *), void *);
 
 #endif  /*  __KERNEL__  */
 
diff -urN linux-2.4.19-pre8/include/linux/i2o.h linux-2.4.19-pre9/include/linux/i2o.h
--- linux-2.4.19-pre8/include/linux/i2o.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre9/include/linux/i2o.h	Tue May 28 16:02:31 2002
@@ -81,9 +81,9 @@
 struct i2o_pci
 {
 	int		irq;
-	int		queue_buggy:3;	/* Don't send a lot of messages */
 	int		short_req:1;	/* Use small block sizes        */
 	int		dpt:1;		/* Don't quiesce                */
+	int		promise:1;	/* Promise controller		*/
 #ifdef CONFIG_MTRR
 	int		mtrr_reg0;
 	int		mtrr_reg1;
@@ -112,9 +112,9 @@
 	atomic_t users;
 	struct i2o_device *devices;		/* I2O device chain */
 	struct i2o_controller *next;		/* Controller chain */
-	volatile u32 *post_port;		/* Inbout port */
-	volatile u32 *reply_port;		/* Outbound port */
-	volatile u32 *irq_mask;			/* Interrupt register */
+	unsigned long post_port;		/* Inbout port address */
+	unsigned long reply_port;		/* Outbound port address */
+	unsigned long irq_mask;			/* Interrupt register address */
 
 	/* Dynamic LCT related data */
 	struct semaphore lct_sem;
@@ -126,8 +126,8 @@
 	i2o_lct *dlct;				/* Temp LCT */
 	i2o_hrt *hrt;				/* HW Resource Table */
 
-	u32 mem_offset;				/* MFA offset */
-	u32 mem_phys;				/* MFA physical */
+	unsigned long mem_offset;		/* MFA offset */
+	unsigned long mem_phys;			/* MFA physical */
 
 	int battery:1;				/* Has a battery backup */
 	int io_alloc:1;				/* An I/O resource was allocated */
@@ -295,6 +295,13 @@
 	I2O_REPLY_WRITE32(c, m);
 }
 
+/*
+ *	Endian handling wrapped into the macro - keeps the core code
+ *	cleaner.
+ */
+ 
+#define i2o_raw_writel(val, mem)	__raw_writel(cpu_to_le32(val), mem)
+
 extern struct i2o_controller *i2o_find_controller(int);
 extern void i2o_unlock_controller(struct i2o_controller *);
 extern struct i2o_controller *i2o_controller_chain;
@@ -339,13 +346,66 @@
 extern void i2o_run_queue(struct i2o_controller *);
 extern int i2o_delete_controller(struct i2o_controller *);
 
+/*
+ *	Cache strategies
+ */
+ 
+ 
+/*	The NULL strategy leaves everything up to the controller. This tends to be a
+ *	pessimal but functional choice.
+ */
+#define CACHE_NULL		0
+/*	Prefetch data when reading. We continually attempt to load the next 32 sectors
+ *	into the controller cache. 
+ */
+#define CACHE_PREFETCH		1
+/*	Prefetch data when reading. We sometimes attempt to load the next 32 sectors
+ *	into the controller cache. When an I/O is less <= 8K we assume its probably
+ *	not sequential and don't prefetch (default)
+ */
+#define CACHE_SMARTFETCH	2
+/*	Data is written to the cache and then out on to the disk. The I/O must be
+ *	physically on the medium before the write is acknowledged (default without
+ *	NVRAM)
+ */
+#define CACHE_WRITETHROUGH	17
+/*	Data is written to the cache and then out on to the disk. The controller
+ *	is permitted to write back the cache any way it wants. (default if battery
+ *	backed NVRAM is present). It can be useful to set this for swap regardless of
+ *	battery state.
+ */
+#define CACHE_WRITEBACK		18
+/*	Optimise for under powered controllers, especially on RAID1 and RAID0. We
+ *	write large I/O's directly to disk bypassing the cache to avoid the extra
+ *	memory copy hits. Small writes are writeback cached
+ */
+#define CACHE_SMARTBACK		19
+/*	Optimise for under powered controllers, especially on RAID1 and RAID0. We
+ *	write large I/O's directly to disk bypassing the cache to avoid the extra
+ *	memory copy hits. Small writes are writethrough cached. Suitable for devices
+ *	lacking battery backup
+ */
+#define CACHE_SMARTTHROUGH	20
+
+/*
+ *	Ioctl structures
+ */
+ 
+
+#define 	BLKI2OGRSTRAT	_IOR('2', 1, int) 
+#define 	BLKI2OGWSTRAT	_IOR('2', 2, int) 
+#define 	BLKI2OSRSTRAT	_IOW('2', 3, int) 
+#define 	BLKI2OSWSTRAT	_IOW('2', 4, int) 
+
+
+
 
 /*
- * I2O Function codes
+ *	I2O Function codes
  */
 
 /*
- * Executive Class
+ *	Executive Class
  */
 #define	I2O_CMD_ADAPTER_ASSIGN		0xB3
 #define	I2O_CMD_ADAPTER_READ		0xB2
@@ -416,6 +476,7 @@
 #define I2O_CMD_BLOCK_MUNLOCK		0x4B
 #define I2O_CMD_BLOCK_MMOUNT		0x41
 #define I2O_CMD_BLOCK_MEJECT		0x43
+#define I2O_CMD_BLOCK_POWER		0x70
 
 #define I2O_PRIVATE_MSG			0xFF
 
@@ -574,6 +635,7 @@
 #define EIGHT_WORD_MSG_SIZE	0x00080000
 #define NINE_WORD_MSG_SIZE	0x00090000
 #define TEN_WORD_MSG_SIZE	0x000A0000
+#define ELEVEN_WORD_MSG_SIZE	0x000B0000
 #define I2O_MESSAGE_SIZE(x)	((x)<<16)
 
 
@@ -582,10 +644,10 @@
 #define ADAPTER_TID		0
 #define HOST_TID		1
 
-#define MSG_FRAME_SIZE		128
+#define MSG_FRAME_SIZE		64	/* i2o_scsi assumes >= 32 */
 #define NMBR_MSG_FRAMES		128
 
-#define MSG_POOL_SIZE		16384
+#define MSG_POOL_SIZE		(MSG_FRAME_SIZE*NMBR_MSG_FRAMES*sizeof(u32))
 
 #define I2O_POST_WAIT_OK	0
 #define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
diff -urN linux-2.4.19-pre8/include/linux/mm.h linux-2.4.19-pre9/include/linux/mm.h
--- linux-2.4.19-pre8/include/linux/mm.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/mm.h	Tue May 28 16:02:31 2002
@@ -313,6 +313,7 @@
 #define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
 #define PageLaunder(page)	test_bit(PG_launder, &(page)->flags)
 #define SetPageLaunder(page)	set_bit(PG_launder, &(page)->flags)
+#define ClearPageLaunder(page)	clear_bit(PG_launder, &(page)->flags)
 
 /*
  * The zone field is never updated after free_area_init_core()
diff -urN linux-2.4.19-pre8/include/linux/pci_ids.h linux-2.4.19-pre9/include/linux/pci_ids.h
--- linux-2.4.19-pre8/include/linux/pci_ids.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/pci_ids.h	Tue May 28 16:02:31 2002
@@ -346,6 +346,8 @@
 #define PCI_DEVICE_ID_IBM_MPIC		0x0046
 #define PCI_DEVICE_ID_IBM_3780IDSP	0x007d
 #define PCI_DEVICE_ID_IBM_CHUKAR	0x0096
+#define PCI_DEVICE_ID_IBM_CPC710_PCI64	0x00fc
+#define PCI_DEVICE_ID_IBM_CPC710_PCI32	0x0105
 #define	PCI_DEVICE_ID_IBM_405GP		0x0156
 #define PCI_DEVICE_ID_IBM_SERVERAIDI960	0x01bd
 #define PCI_DEVICE_ID_IBM_MPIC_2	0xffff
diff -urN linux-2.4.19-pre8/include/linux/sched.h linux-2.4.19-pre9/include/linux/sched.h
--- linux-2.4.19-pre8/include/linux/sched.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/linux/sched.h	Tue May 28 16:02:31 2002
@@ -80,7 +80,9 @@
 #include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
+#ifdef __KERNEL__
 #include <linux/timer.h>
+#endif
 
 #include <asm/processor.h>
 
diff -urN linux-2.4.19-pre8/include/linux/sysrq.h linux-2.4.19-pre9/include/linux/sysrq.h
--- linux-2.4.19-pre8/include/linux/sysrq.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre9/include/linux/sysrq.h	Tue May 28 16:02:31 2002
@@ -105,7 +105,7 @@
 
 /* Deferred actions */
 
-extern int emergency_sync_scheduled;
+extern volatile int emergency_sync_scheduled;
 
 #define EMERG_SYNC 1
 #define EMERG_REMOUNT 2
diff -urN linux-2.4.19-pre8/include/linux/types.h linux-2.4.19-pre9/include/linux/types.h
--- linux-2.4.19-pre8/include/linux/types.h	Thu Nov 22 11:46:18 2001
+++ linux-2.4.19-pre9/include/linux/types.h	Tue May 28 16:02:31 2002
@@ -41,7 +41,7 @@
 typedef __kernel_gid_t		gid_t;
 #endif /* __KERNEL__ */
 
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#if defined(__GNUC__)
 typedef __kernel_loff_t		loff_t;
 #endif
 
diff -urN linux-2.4.19-pre8/include/math-emu/op-1.h linux-2.4.19-pre9/include/math-emu/op-1.h
--- linux-2.4.19-pre8/include/math-emu/op-1.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/math-emu/op-1.h	Tue May 28 16:02:31 2002
@@ -58,6 +58,7 @@
 #define _FP_FRAC_NEGP_1(X)	((_FP_WS_TYPE)X##_f < 0)
 #define _FP_FRAC_ZEROP_1(X)	(X##_f == 0)
 #define _FP_FRAC_OVERP_1(fs,X)	(X##_f & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_CLEAR_OVERP_1(fs,X)	(X##_f &= ~_FP_OVERFLOW_##fs)
 #define _FP_FRAC_EQ_1(X, Y)	(X##_f == Y##_f)
 #define _FP_FRAC_GE_1(X, Y)	(X##_f >= Y##_f)
 #define _FP_FRAC_GT_1(X, Y)	(X##_f > Y##_f)
diff -urN linux-2.4.19-pre8/include/math-emu/op-2.h linux-2.4.19-pre9/include/math-emu/op-2.h
--- linux-2.4.19-pre8/include/math-emu/op-2.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre9/include/math-emu/op-2.h	Tue May 28 16:02:31 2002
@@ -114,6 +114,7 @@
 #define _FP_FRAC_NEGP_2(X)	((_FP_WS_TYPE)X##_f1 < 0)
 #define _FP_FRAC_ZEROP_2(X)	((X##_f1 | X##_f0) == 0)
 #define _FP_FRAC_OVERP_2(fs,X)	(_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_CLEAR_OVERP_2(fs,X)	(_FP_FRAC_HIGH_##fs(X) &= ~_FP_OVERFLOW_##fs)
 #define _FP_FRAC_EQ_2(X, Y)	(X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
 #define _FP_FRAC_GT_2(X, Y)	\
   (X##_f1 > Y##_f1 || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
diff -urN linux-2.4.19-pre8/include/math-emu/op-4.h linux-2.4.19-pre9/include/math-emu/op-4.h
--- linux-2.4.19-pre8/include/math-emu/op-4.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/math-emu/op-4.h	Tue May 28 16:02:31 2002
@@ -132,6 +132,7 @@
 #define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
 #define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
 #define _FP_FRAC_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_CLEAR_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) &= ~_FP_OVERFLOW_##fs)
 
 #define _FP_FRAC_EQ_4(X,Y)				\
  (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]		\
diff -urN linux-2.4.19-pre8/include/math-emu/op-common.h linux-2.4.19-pre9/include/math-emu/op-common.h
--- linux-2.4.19-pre8/include/math-emu/op-common.h	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/include/math-emu/op-common.h	Tue May 28 16:02:31 2002
@@ -97,11 +97,10 @@
 	_FP_ROUND(wc, X);					\
 	if (_FP_FRAC_OVERP_##wc(fs, X))				\
 	  {							\
-	    _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));		\
+	    _FP_FRAC_CLEAR_OVERP_##wc(fs, X);			\
 	    X##_e++;						\
 	  }							\
-	else							\
-	  _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);			\
+	_FP_FRAC_SRL_##wc(X, _FP_WORKBITS);			\
 	if (X##_e >= _FP_EXPMAX_##fs)				\
 	  {							\
 	    /* overflow */					\
@@ -766,24 +765,25 @@
   do {									\
     if (r)								\
       {									\
+        unsigned rtype ur_;						\
 	X##_c = FP_CLS_NORMAL;						\
 									\
 	if ((X##_s = (r < 0)))						\
 	  r = -r;							\
 									\
+	ur_ = (unsigned rtype) r;					\
 	if (rsize <= _FP_W_TYPE_SIZE)					\
-	  __FP_CLZ(X##_e, r);						\
+	  __FP_CLZ(X##_e, ur_);						\
 	else								\
-	  __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), 	\
-		     (_FP_W_TYPE)r);					\
+	  __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE), 	\
+		     (_FP_W_TYPE)ur_);					\
 	if (rsize < _FP_W_TYPE_SIZE)					\
 		X##_e -= (_FP_W_TYPE_SIZE - rsize);			\
 	X##_e = rsize - X##_e - 1;					\
 									\
-	r &= ~((rtype)1 << X##_e);					\
 	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
-	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);	\
-	_FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);	\
+	  __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
+	_FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize);			\
 	if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)			\
 	  _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));	\
       }									\
diff -urN linux-2.4.19-pre8/init/do_mounts.c linux-2.4.19-pre9/init/do_mounts.c
--- linux-2.4.19-pre8/init/do_mounts.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/init/do_mounts.c	Tue May 28 16:02:31 2002
@@ -347,16 +347,16 @@
 		(current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
 }
  
+#ifdef CONFIG_ROOT_NFS
 static int __init mount_nfs_root(void)
 {
-#ifdef CONFIG_ROOT_NFS
 	void *data = nfs_root_data();
 
 	if (data && sys_mount("/dev/root","/root","nfs",root_mountflags,data) == 0)
 		return 1;
-#endif
 	return 0;
 }
+#endif
 
 static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
 {
@@ -388,7 +388,7 @@
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
 	va_end(args);
-	fd = open("/dev/root", O_RDWR, 0);
+	fd = open("/dev/root", O_RDWR | O_NDELAY, 0);
 	if (fd >= 0) {
 		sys_ioctl(fd, FDEJECT, 0);
 		close(fd);
@@ -807,7 +807,7 @@
 			error = sys_ioctl(fd, BLKFLSBUF, 0);
 			close(fd);
 		}
-		printk(error ? "okay\n" : "failed\n");
+		printk(!error ? "okay\n" : "failed\n");
 	}
 #endif
 }
@@ -827,6 +827,10 @@
 void prepare_namespace(void)
 {
 	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+#ifdef CONFIG_ALL_PPC
+	extern void arch_discover_root(void);
+	arch_discover_root();
+#endif /* CONFIG_ALL_PPC */
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (!initrd_start)
 		mount_initrd = 0;
diff -urN linux-2.4.19-pre8/init/main.c linux-2.4.19-pre9/init/main.c
--- linux-2.4.19-pre8/init/main.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/init/main.c	Tue May 28 16:02:31 2002
@@ -293,11 +293,9 @@
 #ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_LOCAL_APIC
-extern int skip_ioapic_setup;
 static void __init smp_init(void)
 {
-	if (!skip_ioapic_setup)
-		APIC_init_uniprocessor();
+	APIC_init_uniprocessor();
 }
 #else
 #define smp_init()	do { } while (0)
diff -urN linux-2.4.19-pre8/kernel/fork.c linux-2.4.19-pre9/kernel/fork.c
--- linux-2.4.19-pre8/kernel/fork.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/kernel/fork.c	Tue May 28 16:02:31 2002
@@ -21,6 +21,7 @@
 #include <linux/completion.h>
 #include <linux/namespace.h>
 #include <linux/personality.h>
+#include <linux/compiler.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -86,12 +87,13 @@
 {
 	static int next_safe = PID_MAX;
 	struct task_struct *p;
-	int pid;
+	int pid, beginpid;
 
 	if (flags & CLONE_PID)
 		return current->pid;
 
 	spin_lock(&lastpid_lock);
+	beginpid = last_pid;
 	if((++last_pid) & 0xffff8000) {
 		last_pid = 300;		/* Skip daemons etc. */
 		goto inside;
@@ -111,12 +113,16 @@
 						last_pid = 300;
 					next_safe = PID_MAX;
 				}
+				if(unlikely(last_pid == beginpid))
+					goto nomorepids;
 				goto repeat;
 			}
 			if(p->pid > last_pid && next_safe > p->pid)
 				next_safe = p->pid;
 			if(p->pgrp > last_pid && next_safe > p->pgrp)
 				next_safe = p->pgrp;
+			if(p->tgid > last_pid && next_safe > p->tgid)
+				next_safe = p->tgid;
 			if(p->session > last_pid && next_safe > p->session)
 				next_safe = p->session;
 		}
@@ -126,6 +132,11 @@
 	spin_unlock(&lastpid_lock);
 
 	return pid;
+
+nomorepids:
+	read_unlock(&tasklist_lock);
+	spin_unlock(&lastpid_lock);
+	return 0;
 }
 
 static inline int dup_mmap(struct mm_struct * mm)
@@ -337,6 +348,9 @@
 	if (!mm_init(mm))
 		goto fail_nomem;
 
+	if (init_new_context(tsk,mm))
+		goto free_pt;
+
 	down_write(&oldmm->mmap_sem);
 	retval = dup_mmap(mm);
 	up_write(&oldmm->mmap_sem);
@@ -349,9 +363,6 @@
 	 */
 	copy_segments(tsk, mm);
 
-	if (init_new_context(tsk,mm))
-		goto free_pt;
-
 good_mm:
 	tsk->mm = mm;
 	tsk->active_mm = mm;
@@ -624,6 +635,8 @@
 
 	copy_flags(clone_flags, p);
 	p->pid = get_pid(clone_flags);
+	if (p->pid == 0 && current->pid != 0)
+		goto bad_fork_cleanup;
 
 	p->run_list.next = NULL;
 	p->run_list.prev = NULL;
diff -urN linux-2.4.19-pre8/kernel/panic.c linux-2.4.19-pre9/kernel/panic.c
--- linux-2.4.19-pre8/kernel/panic.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/kernel/panic.c	Tue May 28 16:02:31 2002
@@ -101,6 +101,7 @@
 		panic_blink(); 
 #endif
 		CHECK_EMERGENCY_SYNC
+		barrier();
 	}
 }
 
diff -urN linux-2.4.19-pre8/kernel/softirq.c linux-2.4.19-pre9/kernel/softirq.c
--- linux-2.4.19-pre8/kernel/softirq.c	Wed Oct 31 10:26:02 2001
+++ linux-2.4.19-pre9/kernel/softirq.c	Tue May 28 16:02:31 2002
@@ -62,7 +62,7 @@
 {
 	int cpu = smp_processor_id();
 	__u32 pending;
-	long flags;
+	unsigned long flags;
 	__u32 mask;
 
 	if (in_interrupt())
@@ -130,7 +130,7 @@
 
 void raise_softirq(unsigned int nr)
 {
-	long flags;
+	unsigned long flags;
 
 	local_irq_save(flags);
 	cpu_raise_softirq(smp_processor_id(), nr);
diff -urN linux-2.4.19-pre8/kernel/sys.c linux-2.4.19-pre9/kernel/sys.c
--- linux-2.4.19-pre8/kernel/sys.c	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre9/kernel/sys.c	Tue May 28 16:02:31 2002
@@ -655,8 +655,8 @@
 			wmb();
 		}
 		current->euid = euid;
-		current->fsuid = euid;
 	}
+	current->fsuid = current->euid;
 	if (suid != (uid_t) -1)
 		current->suid = suid;
 
@@ -701,8 +701,8 @@
 			wmb();
 		}
 		current->egid = egid;
-		current->fsgid = egid;
 	}
+	current->fsgid = current->egid;
 	if (rgid != (gid_t) -1)
 		current->gid = rgid;
 	if (sgid != (gid_t) -1)
diff -urN linux-2.4.19-pre8/mm/filemap.c linux-2.4.19-pre9/mm/filemap.c
--- linux-2.4.19-pre8/mm/filemap.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/mm/filemap.c	Tue May 28 16:02:31 2002
@@ -836,7 +836,7 @@
 void unlock_page(struct page *page)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
-	clear_bit(PG_launder, &(page)->flags);
+	ClearPageLaunder(page);
 	smp_mb__before_clear_bit();
 	if (!test_and_clear_bit(PG_locked, &(page)->flags))
 		BUG();
diff -urN linux-2.4.19-pre8/mm/page_alloc.c linux-2.4.19-pre9/mm/page_alloc.c
--- linux-2.4.19-pre8/mm/page_alloc.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/mm/page_alloc.c	Tue May 28 16:02:31 2002
@@ -25,8 +25,8 @@
 int nr_swap_pages;
 int nr_active_pages;
 int nr_inactive_pages;
-struct list_head inactive_list;
-struct list_head active_list;
+LIST_HEAD(inactive_list);
+LIST_HEAD(active_list);
 pg_data_t *pgdat_list;
 
 /* Used to look up the address of the struct zone encoded in page->zone */
@@ -39,26 +39,6 @@
 static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, };
 
 /*
- * Free_page() adds the page to the free lists. This is optimized for
- * fast normal cases (no error jumps taken normally).
- *
- * The way to optimize jumps for gcc-2.2.2 is to:
- *  - select the "normal" case and put it inside the if () { XXX }
- *  - no else-statements if you can avoid them
- *
- * With the above two rules, you get a straight-line execution path
- * for the normal case, giving better asm-code.
- */
-
-#define memlist_init(x) INIT_LIST_HEAD(x)
-#define memlist_add_head list_add
-#define memlist_add_tail list_add_tail
-#define memlist_del list_del
-#define memlist_entry list_entry
-#define memlist_next(x) ((x)->next)
-#define memlist_prev(x) ((x)->prev)
-
-/*
  * Temporary debugging check.
  */
 #define BAD_RANGE(zone, page)						\
@@ -159,13 +139,13 @@
 		if (BAD_RANGE(zone,buddy2))
 			BUG();
 
-		memlist_del(&buddy1->list);
+		list_del(&buddy1->list);
 		mask <<= 1;
 		area++;
 		index >>= 1;
 		page_idx &= mask;
 	}
-	memlist_add_head(&(base + page_idx)->list, &area->free_list);
+	list_add(&(base + page_idx)->list, &area->free_list);
 
 	spin_unlock_irqrestore(&zone->lock, flags);
 	return;
@@ -195,7 +175,7 @@
 		area--;
 		high--;
 		size >>= 1;
-		memlist_add_head(&(page)->list, &(area)->free_list);
+		list_add(&(page)->list, &(area)->free_list);
 		MARK_USED(index, high, area);
 		index += size;
 		page += size;
@@ -217,15 +197,15 @@
 	spin_lock_irqsave(&zone->lock, flags);
 	do {
 		head = &area->free_list;
-		curr = memlist_next(head);
+		curr = head->next;
 
 		if (curr != head) {
 			unsigned int index;
 
-			page = memlist_entry(curr, struct page, list);
+			page = list_entry(curr, struct page, list);
 			if (BAD_RANGE(zone,page))
 				BUG();
-			memlist_del(curr);
+			list_del(curr);
 			index = page - zone->zone_mem_map;
 			if (curr_order != MAX_ORDER-1)
 				MARK_USED(index, curr_order, area);
@@ -582,8 +562,7 @@
 				curr = head;
 				nr = 0;
 				for (;;) {
-					curr = memlist_next(curr);
-					if (curr == head)
+					if ((curr = curr->next) == head)
 						break;
 					nr++;
 				}
@@ -727,9 +706,6 @@
 			
 	printk("On node %d totalpages: %lu\n", nid, realtotalpages);
 
-	INIT_LIST_HEAD(&active_list);
-	INIT_LIST_HEAD(&inactive_list);
-
 	/*
 	 * Some architectures (with lots of mem and discontinous memory
 	 * maps) have to search for a good mem_map area:
@@ -812,7 +788,7 @@
 			set_page_zone(page, nid * MAX_NR_ZONES + j);
 			set_page_count(page, 0);
 			SetPageReserved(page);
-			memlist_init(&page->list);
+			INIT_LIST_HEAD(&page->list);
 			if (j != ZONE_HIGHMEM)
 				set_page_address(page, __va(zone_start_paddr));
 			zone_start_paddr += PAGE_SIZE;
@@ -822,7 +798,7 @@
 		for (i = 0; ; i++) {
 			unsigned long bitmap_size;
 
-			memlist_init(&zone->free_area[i].free_list);
+			INIT_LIST_HEAD(&zone->free_area[i].free_list);
 			if (i == MAX_ORDER-1) {
 				zone->free_area[i].map = NULL;
 				break;
diff -urN linux-2.4.19-pre8/net/atm/pppoatm.c linux-2.4.19-pre9/net/atm/pppoatm.c
--- linux-2.4.19-pre8/net/atm/pppoatm.c	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/net/atm/pppoatm.c	Tue May 28 16:02:31 2002
@@ -125,7 +125,7 @@
 	pvcc = atmvcc_to_pvcc(atmvcc);
 	atmvcc->push = pvcc->old_push;
 	atmvcc->pop = pvcc->old_pop;
-	tasklet_disable(&pvcc->wakeup_tasklet);
+	tasklet_kill(&pvcc->wakeup_tasklet);
 	ppp_unregister_channel(&pvcc->chan);
 	atmvcc->user_back = NULL;
 	kfree(pvcc);
diff -urN linux-2.4.19-pre8/scripts/Menuconfig linux-2.4.19-pre9/scripts/Menuconfig
--- linux-2.4.19-pre8/scripts/Menuconfig	Tue May 28 16:02:25 2002
+++ linux-2.4.19-pre9/scripts/Menuconfig	Tue May 28 16:02:31 2002
@@ -54,7 +54,7 @@
 # Change a lot of places to call set_x_info uniformly.
 # Take out message about preparing version (old sound driver cruft).
 #
-# 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
+# 13 Dec 1998, Riley H Williams <Riley@Williams.Name>
 # When an error occurs, actually display the error message as well as
 # our comments thereon.
 #
@@ -73,6 +73,10 @@
 # - Support for multiple conditions in dep_tristate().
 # - Implemented new functions: define_tristate(), define_int(), define_hex(),
 #   define_string(), dep_bool().
+#
+# 12 November 2001, Keith Owens <kaos@ocs.com.au>
+# Escape double quotes on eval so the quotes are still there on the second
+# evaluation, required to handle strings with special characters.
 # 
 
 
@@ -105,11 +109,11 @@
     eval x=\$$1
     if [ -z "$x" ]; then
 	eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig`
-	eval x=\${$1:-"$2"}
+	eval x=\${$1:-\"$2\"}
 	eval $1=$x
 	eval INFO_$1="' (NEW)'"
     fi
-    eval info="\$INFO_$1"
+    eval info=\"\$INFO_$1\"
 }
 
 #
@@ -151,7 +155,7 @@
 }
 
 function define_string () {
-	eval $1="$2"
+	eval $1=\"$2\"
 }
 
 #
@@ -333,7 +337,7 @@
 
 	while [ -n "$2" ]
 	do
-		if eval [ "_\$$2" = "_y" ]
+		if eval [ \"_\$$2\" = \"_y\" ]
 		then
 			current=$1
 			break
@@ -548,9 +552,9 @@
 			# we avoid them:
 			if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
 			then
-				eval $2="$answer"
+				eval $2=\"$answer\"
 			else
-				eval $2="$3"
+				eval $2=\"$3\"
 				echo -en "\007"
 				${DIALOG} --backtitle "$backtitle" \
 					--infobox "You have made an invalid entry." 3 43
@@ -581,9 +585,9 @@
 
 			if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
 			then
-				eval $2="$answer"
+				eval $2=\"$answer\"
 			else
-				eval $2="$3"
+				eval $2=\"$3\"
 				echo -en "\007"
 				${DIALOG} --backtitle "$backtitle" \
 					--infobox "You have made an invalid entry." 3 43
@@ -681,9 +685,9 @@
 	do
 		if [ "$2" = "$choice" ]
 		then
-			eval $2="y"
+			eval $2=\"y\"
 		else
-			eval $2="n"
+			eval $2=\"n\"
 		fi
 		
 		shift ; shift
@@ -946,9 +950,9 @@
 
 			[ "_" = "_$ALT_CONFIG" ] && break
 
-			if eval [ -r "$ALT_CONFIG" ]
+			if eval [ -r \"$ALT_CONFIG\" ]
 			then
-				eval load_config_file "$ALT_CONFIG"
+				eval load_config_file \"$ALT_CONFIG\"
 				break
 			else
 				echo -ne "\007"
@@ -1072,12 +1076,12 @@
 	#
 	function bool () {
 		set_x_info "$2" "n"
-		eval define_bool "$2" "$x"
+		eval define_bool \"$2\" \"$x\"
 	}
 
 	function tristate () {
 		set_x_info "$2" "n"
-		eval define_tristate "$2" "$x"
+		eval define_tristate \"$2\" \"$x\"
 	}
 
 	function dep_tristate () {
@@ -1143,19 +1147,19 @@
 	}
 
 	function define_hex () {
-		eval $1="$2"
+		eval $1=\"$2\"
                	echo "$1=$2"			>>$CONFIG
 		echo "#define $1 0x${2##*[x,X]}"	>>$CONFIG_H
 	}
 
 	function define_int () {
-		eval $1="$2"
+		eval $1=\"$2\"
 		echo "$1=$2" 			>>$CONFIG
 		echo "#define $1 ($2)"		>>$CONFIG_H
 	}
 
 	function define_string () {
-		eval $1="$2"
+		eval $1=\"$2\"
 		echo "$1=\"$2\""		>>$CONFIG
 		echo "#define $1 \"$2\""	>>$CONFIG_H
 	}
@@ -1165,7 +1169,7 @@
 	}
 
 	function define_tristate () {
-		eval $1="$2"
+		eval $1=\"$2\"
 
    		case "$2" in
          	y)
@@ -1204,7 +1208,7 @@
 		set -- $choices
 		while [ -n "$2" ]
 		do
-			if eval [ "_\$$2" = "_y" ]
+			if eval [ \"_\$$2\" = \"_y\" ]
 			then
 				current=$1
 				break
diff -urN linux-2.4.19-pre8/scripts/mkdep.c linux-2.4.19-pre9/scripts/mkdep.c
--- linux-2.4.19-pre8/scripts/mkdep.c	Fri Sep 14 14:40:00 2001
+++ linux-2.4.19-pre9/scripts/mkdep.c	Tue May 28 16:02:31 2002
@@ -268,7 +268,7 @@
 
 	for (i = 0; i < len; i++) {
 	    char c = name[i];
-	    if (isupper(c)) c = tolower(c);
+	    if (isupper((int)c)) c = tolower((int)c);
 	    if (c == '_')   c = '/';
 	    pc[i] = c;
 	}
@@ -496,7 +496,7 @@
 
 /* \<CONFIG_(\w*) */
 cee:
-	if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
+	if (next >= map+2 && (isalnum((int)next[-2]) || next[-2] == '_'))
 		goto start;
 	GETNEXT NOTCASE('O', __start);
 	GETNEXT NOTCASE('N', __start);
diff -urN linux-2.4.19-pre8/scripts/split-include.c linux-2.4.19-pre9/scripts/split-include.c
--- linux-2.4.19-pre8/scripts/split-include.c	Mon Oct  8 11:46:09 2001
+++ linux-2.4.19-pre9/scripts/split-include.c	Tue May 28 16:02:31 2002
@@ -115,10 +115,10 @@
 
 	/* Make the output file name. */
 	str_config += sizeof("CONFIG_") - 1;
-	for (itarget = 0; !isspace(str_config[itarget]); itarget++)
+	for (itarget = 0; !isspace((int)str_config[itarget]); itarget++)
 	{
 	    char c = str_config[itarget];
-	    if (isupper(c)) c = tolower(c);
+	    if (isupper((int)c)) c = tolower((int)c);
 	    if (c == '_')   c = '/';
 	    ptarget[itarget] = c;
 	}
diff -urN linux-2.4.19-pre8/scripts/tkparse.c linux-2.4.19-pre9/scripts/tkparse.c
--- linux-2.4.19-pre8/scripts/tkparse.c	Sun Oct  8 09:30:40 2000
+++ linux-2.4.19-pre9/scripts/tkparse.c	Tue May 28 16:02:31 2002
@@ -74,12 +74,12 @@
 
 
 /*
- * Find index of a specyfic variable in the symbol table.
+ * Find index of a specific variable in the symbol table.
  * Create a new entry if it does not exist yet.
  */
-#define VARTABLE_SIZE 2048
-struct variable vartable[VARTABLE_SIZE];
+struct variable *vartable;
 int max_varnum = 0;
+static int vartable_size = 0;
 
 int get_varnum( char * name )
 {
@@ -88,8 +88,13 @@
     for ( i = 1; i <= max_varnum; i++ )
 	if ( strcmp( vartable[i].name, name ) == 0 )
 	    return i;
-    if (max_varnum > VARTABLE_SIZE-1)
-	syntax_error( "Too many variables defined." );
+    while (max_varnum+1 >= vartable_size) {
+	vartable = realloc(vartable, (vartable_size += 1000)*sizeof(*vartable));
+	if (!vartable) {
+	    fprintf(stderr, "tkparse realloc vartable failed\n");
+	    exit(1);
+	}
+    }
     vartable[++max_varnum].name = malloc( strlen( name )+1 );
     strcpy( vartable[max_varnum].name, name );
     return max_varnum;
@@ -818,5 +823,6 @@
     do_source        ( "-"         );
     fix_conditionals ( config_list );
     dump_tk_script   ( config_list );
+    free(vartable);
     return 0;
 }
diff -urN linux-2.4.19-pre8/scripts/tkparse.h linux-2.4.19-pre9/scripts/tkparse.h
--- linux-2.4.19-pre8/scripts/tkparse.h	Sun Feb 20 20:13:10 2000
+++ linux-2.4.19-pre9/scripts/tkparse.h	Tue May 28 16:02:31 2002
@@ -115,7 +115,7 @@
     char	global_written;
 };
 
-extern struct variable vartable[];
+extern struct variable *vartable;
 extern int max_varnum;
 
 /*
