diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Thu May  9 15:21:03 2002
+++ b/CREDITS	Thu May  9 15:21:03 2002
@@ -595,7 +595,7 @@
 S: USA
 
 N: Kees Cook
-E: cook@cpoint.net
+E: kees@outflux.net
 W: http://outflux.net/
 P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30  1975 1FFF 4BA9 1706 3E6D
 D: Minor updates to SCSI code for the Communications type
diff -Nru a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
--- a/Documentation/kbuild/makefiles.txt	Thu May  9 15:21:09 2002
+++ b/Documentation/kbuild/makefiles.txt	Thu May  9 15:21:09 2002
@@ -99,15 +99,15 @@
 
 === 3 Makefile language
 
-The kernel Makefiles are designed to run with Gnu Make.  The Makefiles
-use only the documented features of Gnu Make, but they do use many
-Gnu extensions.
+The kernel Makefiles are designed to run with GNU Make.  The Makefiles
+use only the documented features of GNU Make, but they do use many
+GNU extensions.
 
-Gnu Make supports elementary list-processing functions.  The kernel
+GNU Make supports elementary list-processing functions.  The kernel
 Makefiles use a novel style of list building and manipulation with few
 "if" statements.
 
-Gnu Make has two assignment operators, ":=" and "=".  ":=" performs
+GNU Make has two assignment operators, ":=" and "=".  ":=" performs
 immediate evaluation of the right-hand side and stores an actual string
 into the left-hand side.  "=" is like a formula definition; it stores the
 right-hand side in an unevaluated form and then evaluates this form each
@@ -191,7 +191,7 @@
 	$(DRIVERS), and $(LIBS).  The arch Makefile defines $(HEAD)
 	and $(LINKFLAGS), and extends $(CORE_FILES) and $(LIBS).
 
-	Note: there are more names here than necessary.  $(NETWORKS),
+	Note: there are more variables here than necessary.  $(NETWORKS),
 	$(DRIVERS), and even $(LIBS) could be subsumed into $(CORE_FILES).
 
     CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP
@@ -289,12 +289,12 @@
 
     MAKE, MAKEFILES
 
-	Some variables internal to Gnu Make.
+	Some variables internal to GNU Make.
 
 	$(MAKEFILES) in particular is used to force the arch Makefiles
 	and subdirectory Makefiles to read $(TOPDIR)/.config without
-	including it explicitly.  (This was an implementation hack and
-	could be fixed).
+	including it explicitly.  (This was an implementational hack
+	and could be fixed).
 
 
 
@@ -338,7 +338,7 @@
 	extends them.
 
 	Many arch Makefiles dynamically run the target C compiler to
-	probe what options it supports:
+	probe supported options:
 
 		# arch/i386/Makefile
 
@@ -375,7 +375,7 @@
 
 --- 5.2 Vmlinux build variables
 
-An arch Makefile co-operates with the top Makefile to define variables
+An arch Makefile cooperates with the top Makefile to define variables
 which specify how to build the vmlinux file.  Note that there is no
 corresponding arch-specific section for modules; the module-building
 machinery is all architecture-independent.
@@ -471,11 +471,9 @@
 
 --- 6.1 Comments
 
-The first section is a comment header.  Just write what you would
-write if you were editing a C source file, but use "# ..." instead of
-"/* ... */".  Historically, many anonymous people have edited kernel
-Makefiles without leaving any change histories in the header; comments
-from them would have been valuable.
+The first section is a comment header. Historically, many anonymous
+people have edited kernel Makefiles without leaving any change
+histories in the header; comments from them would have been valuable.
 
 
 
@@ -657,8 +655,8 @@
     export-objs
 
 	When using loadable modules, not every global symbol in the
-	kernel / other modules is automatically available for your
-	module, only those explicitly exported are.
+	kernel / other modules is automatically available, only those
+	explicitly exported are available for your module.
 
 	To make a symbol available for use in modules, to "export" it,
 	use the EXPORT_SYMBOL(<symbol>) directive in your source. In
@@ -827,7 +825,7 @@
 		obj-$(CONFIG_ATARI_FLOPPY)      += ataflop.o
 
 	Notice the use of $(CONFIG_...) substitutions on the left hand
-	side of an assignment operator.  This gives Gnu Make the power
+	side of an assignment operator.  This gives GNU Make the power
 	of associative indexing!  Each of these assignments replaces
 	eight lines of code in an old-style Makefile.
 
@@ -840,9 +838,8 @@
 	$(obj-n) and $(obj-) are ignored.
 
 	Each list may contain duplicates items; duplicates are
-	automatically removed later.  Also, if a file appears in both
-	$(obj-y) and $(obj-m), it will automatically be removed from
-	the $(obj-m) list.
+	automatically removed later.  Duplicates in both $(obj-y) and
+	$(obj-m) will automatically be removed from the $(obj-m) list.
 
 	Example:
 
@@ -926,9 +923,9 @@
 	of sr_mod.o will be linked together with "$(LD) -r" to make the
 	kernel module sr_mod.o.
 
-	And suppose CONFIG_SCSI_INITIO=n.  Then initio.o goes onto the
-	$(obj-n) list and that's the end of it.  Its component files
-	are not compiled, and the composite file is not created.
+	Also suppose CONFIG_SCSI_INITIO=n.  Then initio.o goes onto
+	the $(obj-n) list and that's the end of it.  Its component
+	files are not compiled, and the composite file is not created.
 
 
     subdir-y subdir-m subdir-n subdir-
@@ -947,9 +944,9 @@
 	These variables work similar to obj-*, but are used for
 	subdirectories instead of object files.
 
-	After executing all of the assignments, the subdirectory
-	Makefile has built up four lists: $(subdir-y), $(subdir-m),
-	$(subdir-n), and $(subdir-).
+	After executing all assignments, the subdirectory Makefile has
+	built up four lists: $(subdir-y), $(subdir-m), $(subdir-n),
+	and $(subdir-).
 
 	$(subdir-y) is a list of directories that should be entered
 		for making vmlinux.
diff -Nru a/Documentation/nbd.txt b/Documentation/nbd.txt
--- a/Documentation/nbd.txt	Thu May  9 15:21:09 2002
+++ b/Documentation/nbd.txt	Thu May  9 15:21:09 2002
@@ -54,4 +54,4 @@
   ...                 in case of read operation with no error,
                       this is immediately followed len bytes of data
 
-   For more information, look at http://atrey.karlin.mff.cuni.cz/~pavel.
+   For more information, look at http://nbd.sf.net/.
diff -Nru a/Documentation/sonypi.txt b/Documentation/sonypi.txt
--- a/Documentation/sonypi.txt	Thu May  9 15:21:01 2002
+++ b/Documentation/sonypi.txt	Thu May  9 15:21:01 2002
@@ -36,14 +36,14 @@
 driver and the ACPI BIOS, because Sony doesn't agree to release any programming
 specs for its laptops. If someone convinces them to do so, drop me a note.
 
-Module options:
+Driver options:
 ---------------
 
 Several options can be passed to the sonypi driver, either by adding them
 to /etc/modules.conf file, when the driver is compiled as a module or by
 adding the following to the kernel command line (in your bootloader):
 
-	sonypi=minor[[[[[,camera],fnkeyinit],verbose],compat],nojogdial]
+	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,nojogdial]]]]]
 
 where:
 
diff -Nru a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
--- a/Documentation/video4linux/meye.txt	Thu May  9 15:21:03 2002
+++ b/Documentation/video4linux/meye.txt	Thu May  9 15:21:03 2002
@@ -15,8 +15,16 @@
 
 MJPEG hardware grabbing is supported via a private API (see below).
 
-Module options:
+Driver options:
 ---------------
+
+Several options can be passed to the meye driver, either by adding them
+to /etc/modules.conf file, when the driver is compiled as a module, or
+by adding the following to the kernel command line (in your bootloader):
+
+	meye=gbuffers[,gbufsize[,video_nr]]
+
+where:
 
 	gbuffers:	number of capture buffers, default is 2 (32 max)
 
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Thu May  9 15:21:02 2002
+++ b/Makefile	Thu May  9 15:21:02 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 14
+SUBLEVEL = 15
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -130,6 +130,7 @@
 DRIVERS-  :=
 
 DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
+DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
 DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
 DRIVERS-y += drivers/base/base.o \
 	drivers/char/char.o \
@@ -137,19 +138,12 @@
 	drivers/misc/misc.o \
 	drivers/net/net.o \
 	drivers/media/media.o
-DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
-DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
 DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
-DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
-DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o
-DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o
-DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o
-DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o
 DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
 DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
 DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
-DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o
+DRIVERS-$(CONFIG_FUSION) += drivers/message/message.o
 DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
 
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
@@ -157,13 +151,8 @@
 endif
 
 DRIVERS-$(CONFIG_SOUND) += sound/sound.o
-DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
 DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
 DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
-DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
-DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
-DRIVERS-$(CONFIG_NET_TULIP) += drivers/net/tulip/tulip_net.o
-DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
 DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
 DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
@@ -173,14 +162,12 @@
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
 DRIVERS-$(CONFIG_VT) += drivers/video/video.o
 DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
-DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
 DRIVERS-$(CONFIG_GAMEPORT) += drivers/input/gameport/gamedrv.o
 DRIVERS-$(CONFIG_SERIO) += drivers/input/serio/seriodrv.o
-DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
-DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
+DRIVERS-$(CONFIG_I2O) += drivers/message/message.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
@@ -391,17 +378,8 @@
 depmod_opts	:= -b $(INSTALL_MOD_PATH) -r
 endif
 .PHONY: _modinst_post
-_modinst_post: _modinst_post_pcmcia
+_modinst_post:
 	if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
-
-# Backwards compatibilty symlinks for people still using old versions
-# of pcmcia-cs with hard coded pathnames on insmod.  Remove
-# _modinst_post_pcmcia for kernel 2.4.1.
-.PHONY: _modinst_post_pcmcia
-_modinst_post_pcmcia:
-	cd $(MODLIB); \
-	mkdir -p pcmcia; \
-	find kernel -path '*/pcmcia/*' -name '*.o' | xargs -i -r ln -sf ../{} pcmcia
 
 .PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
 $(patsubst %, _modinst_%, $(SUBDIRS)) :
diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig
--- a/arch/alpha/defconfig	Thu May  9 15:21:07 2002
+++ b/arch/alpha/defconfig	Thu May  9 15:21:07 2002
@@ -245,7 +245,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Thu May  9 15:21:02 2002
+++ b/arch/alpha/kernel/pci.c	Thu May  9 15:21:02 2002
@@ -128,7 +128,8 @@
 #define GB			(1024*MB)
 
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 	struct pci_controller *hose = dev->sysdata;
@@ -168,7 +169,7 @@
 		 */
 
 		/* Align to multiple of size of minimum base.  */
-		alignto = MAX(0x1000, size);
+		alignto = MAX(0x1000, align);
 		start = ALIGN(start, alignto);
 		if (hose->sparse_mem_base && size <= 7 * 16*MB) {
 			if (((start / (16*MB)) & 0x7) == 0) {
@@ -192,7 +193,7 @@
 #undef MB
 #undef GB
 
-void __init
+static void __init
 pcibios_init(void)
 {
 	if (!alpha_mv.init_pci)
@@ -200,6 +201,8 @@
 	alpha_mv.init_pci();
 }
 
+subsys_initcall(pcibios_init);
+
 char * __init
 pcibios_setup(char *str)
 {
@@ -245,25 +248,6 @@
 		/* Root bus */
 		bus->resource[0] = hose->io_space;
 		bus->resource[1] = hose->mem_space;
-	} else {
-		/* This is a bridge. Do not care how it's initialized,
-		   just link its resources to the bus ones */
-		int i;
-
-		for(i=0; i<3; i++) {
-			bus->resource[i] =
-				&dev->resource[PCI_BRIDGE_RESOURCES+i];
-			bus->resource[i]->name = bus->name;
-		}
-		bus->resource[0]->flags |= pci_bridge_check_io(dev);
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-		/* For now, propogate hose limits to the bus;
-		   we'll adjust them later. */
-		bus->resource[0]->end = hose->io_space->end;
-		bus->resource[1]->end = hose->mem_space->end;
-		/* Turn off downstream PF memory address range by default */
-		bus->resource[2]->start = 1024*1024;
-		bus->resource[2]->end = bus->resource[2]->start - 1;
 	}
 
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
@@ -348,6 +332,10 @@
 	ranges->io_end -= hose->io_space->start;
 	ranges->mem_start -= hose->mem_space->start;
 	ranges->mem_end -= hose->mem_space->start;
+/* FIXME: On older alphas we could use dense memory space
+	  to access prefetchable resources. */
+	ranges->prefetch_start -= hose->mem_space->start;
+	ranges->prefetch_end -= hose->mem_space->start;
 }
 
 int
diff -Nru a/arch/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge
--- a/arch/arm/def-configs/footbridge	Thu May  9 15:21:05 2002
+++ b/arch/arm/def-configs/footbridge	Thu May  9 15:21:05 2002
@@ -403,7 +403,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 CONFIG_BLK_DEV_OFFBOARD=y
diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310
--- a/arch/arm/def-configs/iq80310	Thu May  9 15:21:03 2002
+++ b/arch/arm/def-configs/iq80310	Thu May  9 15:21:03 2002
@@ -454,7 +454,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/arm/def-configs/shark b/arch/arm/def-configs/shark
--- a/arch/arm/def-configs/shark	Thu May  9 15:21:02 2002
+++ b/arch/arm/def-configs/shark	Thu May  9 15:21:02 2002
@@ -432,7 +432,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
--- a/arch/arm/kernel/bios32.c	Thu May  9 15:21:06 2002
+++ b/arch/arm/kernel/bios32.c	Thu May  9 15:21:06 2002
@@ -346,20 +346,7 @@
 	struct pci_dev *dev = bus->self;
 	int i;
 
-	if (dev) {
-		for (i = 0; i < 3; i++) {
-			if (root->resource[i]) {
-				bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-				bus->resource[i]->end  = root->resource[i]->end;
-				bus->resource[i]->name = bus->name;
-			}
-		}
-		bus->resource[0]->flags |= pci_bridge_check_io(dev);
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-
-		if (bus->resource[2] && root->resource[2])
-			bus->resource[2]->flags = root->resource[2]->flags;
-	} else {
+	if (!dev) {
 		/*
 		 * Assign root bus resources.
 		 */
@@ -662,7 +649,8 @@
  * but we want to try to avoid allocating at 0x2900-0x2bff
  * which might be mirrored at 0x0100-0x03ff..
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Thu May  9 15:21:05 2002
+++ b/arch/i386/Makefile	Thu May  9 15:21:05 2002
@@ -98,6 +98,11 @@
 DRIVERS += arch/i386/math-emu/math.o
 endif
 
+ifdef CONFIG_PCI
+SUBDIRS	+= arch/i386/pci
+DRIVERS	+= arch/i386/pci/pci.o
+endif
+
 arch/i386/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
 
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Thu May  9 15:21:02 2002
+++ b/arch/i386/defconfig	Thu May  9 15:21:02 2002
@@ -254,7 +254,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 CONFIG_BLK_DEV_RZ1000=y
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Thu May  9 15:21:03 2002
+++ b/arch/i386/kernel/Makefile	Thu May  9 15:21:03 2002
@@ -7,8 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.S.o:
-	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+EXTRA_AFLAGS	:= -traditional
+USE_STANDARD_AS_RULE	:= true
 
 all: kernel.o head.o init_task.o
 
@@ -20,16 +20,6 @@
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
 		bootflag.o
-
-
-ifdef CONFIG_PCI
-obj-y			+= pci-i386.o
-ifdef CONFIG_VISWS
-obj-y			+= pci-visws.o
-else
-obj-y			+= pci-pc.o pci-irq.o
-endif
-endif
 
 obj-$(CONFIG_MCA)		+= mca.o
 obj-$(CONFIG_MTRR)		+= mtrr.o
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Thu May  9 15:21:05 2002
+++ b/arch/i386/kernel/dmi_scan.c	Thu May  9 15:21:05 2002
@@ -643,6 +643,12 @@
 			MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
 			} },
 	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0209Z3"),
+			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
+			} },
+	
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204K2"),
diff -Nru a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
--- a/arch/i386/kernel/mtrr.c	Thu May  9 15:21:01 2002
+++ b/arch/i386/kernel/mtrr.c	Thu May  9 15:21:02 2002
@@ -1659,7 +1659,7 @@
     char *ptr;
     char line[LINE_SIZE];
 
-    if ( !suser () ) return -EPERM;
+    if ( !capable(CAP_SYS_ADMIN)) return -EPERM;
     /*  Can't seek (pwrite) on this device  */
     if (ppos != &file->f_pos) return -ESPIPE;
     memset (line, 0, LINE_SIZE);
@@ -1727,28 +1727,28 @@
       default:
 	return -ENOIOCTLCMD;
       case MTRRIOC_ADD_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( ! capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_SET_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_DEL_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_del (sentry.base, sentry.size, file, 0);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_KILL_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_del (-1, sentry.base, sentry.size);
@@ -1773,28 +1773,28 @@
 	     return -EFAULT;
 	break;
       case MTRRIOC_ADD_PAGE_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_SET_PAGE_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_DEL_PAGE_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_del (sentry.base, sentry.size, file, 1);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_KILL_PAGE_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_del_page (-1, sentry.base, sentry.size);
diff -Nru a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c
--- a/arch/i386/kernel/pci-i386.c	Thu May  9 15:21:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,384 +0,0 @@
-/*
- *	Low-Level PCI Access for i386 machines
- *
- * Copyright 1993, 1994 Drew Eckhardt
- *      Visionary Computing
- *      (Unix and Linux consulting and custom programming)
- *      Drew@Colorado.EDU
- *      +1 (303) 786-7975
- *
- * Drew's work was sponsored by:
- *	iX Multiuser Multitasking Magazine
- *	Hannover, Germany
- *	hm@ix.de
- *
- * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
- *
- * For more information, please consult the following manuals (look at
- * http://www.pcisig.com/ for how to get them):
- *
- * PCI BIOS Specification
- * PCI Local Bus Specification
- * PCI to PCI Bridge Specification
- * PCI System Design Guide
- *
- *
- * CHANGELOG :
- * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
- *	Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
- *
- * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
- *     Potter, potter@cao-vlsi.ibp.fr
- *
- * Jan 10, 1995 : Modified to store the information about configured pci
- *      devices into a list, which can be accessed via /proc/pci by
- *      Curtis Varner, cvarner@cs.ucr.edu
- *
- * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
- *	Alpha version. Intel & UMC chipset support only.
- *
- * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
- *	moved to drivers/pci/pci.c.
- *
- * Dec 7, 1996  : Added support for direct configuration access of boards
- *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
- *
- * Feb 3, 1997  : Set internal functions to static, save/restore flags
- *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
- *
- * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
- *	(mj@atrey.karlin.mff.cuni.cz)
- *
- * May 7,  1997 : Added some missing cli()'s. [mj]
- * 
- * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
- *      (paubert@iram.es)
- *
- * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
- *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
- *
- * May 1,  1998 : Support for peer host bridges. [mj]
- *
- * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
- *	can be accessed from interrupts even on SMP systems. [mj]
- *
- * August  1998 : Better support for peer host bridges and more paranoid
- *	checks for direct hardware access. Ugh, this file starts to look as
- *	a large gallery of common hardware bug workarounds (watch the comments)
- *	-- the PCI specs themselves are sane, but most implementors should be
- *	hit hard with \hammer scaled \magstep5. [mj]
- *
- * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
- *
- * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
- *
- * August  1999 : New resource management and configuration access stuff. [mj]
- *
- * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
- *		  Based on ideas by Chris Frantz and David Hinds. [mj]
- *
- * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
- *		  for a lot of patience during testing. [mj]
- *
- * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-
-#include "pci-i386.h"
-
-void
-pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-			struct resource *res, int resource)
-{
-	u32 new, check;
-	int reg;
-
-	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
-	if (resource < 6) {
-		reg = PCI_BASE_ADDRESS_0 + 4*resource;
-	} else if (resource == PCI_ROM_RESOURCE) {
-		res->flags |= PCI_ROM_ADDRESS_ENABLE;
-		new |= PCI_ROM_ADDRESS_ENABLE;
-		reg = dev->rom_base_reg;
-	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
-		return;
-	}
-	
-	pci_write_config_dword(dev, reg, new);
-	pci_read_config_dword(dev, reg, &check);
-	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
-		printk(KERN_ERR "PCI: Error while updating region "
-		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
-		       new, check);
-	}
-}
-
-/*
- * We need to avoid collisions with `mirrored' VGA ports
- * and other strange ISA hardware, so we always want the
- * addresses to be allocated in the 0x000-0x0ff region
- * modulo 0x400.
- *
- * Why? Because some silly external IO cards only decode
- * the low 10 bits of the IO address. The 0x00-0xff region
- * is reserved for motherboard devices that decode all 16
- * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
- * but we want to try to avoid allocating at 0x2900-0x2bff
- * which might have be mirrored at 0x0100-0x03ff..
- */
-void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
-{
-	if (res->flags & IORESOURCE_IO) {
-		unsigned long start = res->start;
-
-		if (start & 0x300) {
-			start = (start + 0x3ff) & ~0x3ff;
-			res->start = start;
-		}
-	}
-}
-
-
-/*
- *  Handle resources of PCI devices.  If the world were perfect, we could
- *  just allocate all the resource regions and do nothing more.  It isn't.
- *  On the other hand, we cannot just re-allocate all devices, as it would
- *  require us to know lots of host bridge internals.  So we attempt to
- *  keep as much of the original configuration as possible, but tweak it
- *  when it's found to be wrong.
- *
- *  Known BIOS problems we have to work around:
- *	- I/O or memory regions not configured
- *	- regions configured, but not enabled in the command register
- *	- bogus I/O addresses above 64K used
- *	- expansion ROMs left enabled (this may sound harmless, but given
- *	  the fact the PCI specs explicitly allow address decoders to be
- *	  shared between expansion ROMs and other resource regions, it's
- *	  at least dangerous)
- *
- *  Our solution:
- *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
- *	    This gives us fixed barriers on where we can allocate.
- *	(2) Allocate resources for all enabled devices.  If there is
- *	    a collision, just mark the resource as unallocated. Also
- *	    disable expansion ROMs during this step.
- *	(3) Try to allocate resources for disabled devices.  If the
- *	    resources were assigned correctly, everything goes well,
- *	    if they weren't, they won't disturb allocation of other
- *	    resources.
- *	(4) Assign new addresses to resources which were either
- *	    not configured at all or misconfigured.  If explicitly
- *	    requested by the user, configure expansion ROM address
- *	    as well.
- */
-
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
-{
-	struct list_head *ln;
-	struct pci_bus *bus;
-	struct pci_dev *dev;
-	int idx;
-	struct resource *r, *pr;
-
-	/* Depth-First Search on bus tree */
-	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
-		bus = pci_bus_b(ln);
-		if ((dev = bus->self)) {
-			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
-				r = &dev->resource[idx];
-				if (!r->start)
-					continue;
-				pr = pci_find_parent_resource(dev, r);
-				if (!pr || request_resource(pr, r) < 0)
-					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
-			}
-		}
-		pcibios_allocate_bus_resources(&bus->children);
-	}
-}
-
-static void __init pcibios_allocate_resources(int pass)
-{
-	struct pci_dev *dev;
-	int idx, disabled;
-	u16 command;
-	struct resource *r, *pr;
-
-	pci_for_each_dev(dev) {
-		pci_read_config_word(dev, PCI_COMMAND, &command);
-		for(idx = 0; idx < 6; idx++) {
-			r = &dev->resource[idx];
-			if (r->parent)		/* Already allocated */
-				continue;
-			if (!r->start)		/* Address not assigned at all */
-				continue;
-			if (r->flags & IORESOURCE_IO)
-				disabled = !(command & PCI_COMMAND_IO);
-			else
-				disabled = !(command & PCI_COMMAND_MEMORY);
-			if (pass == disabled) {
-				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
-				    r->start, r->end, r->flags, disabled, pass);
-				pr = pci_find_parent_resource(dev, r);
-				if (!pr || request_resource(pr, r) < 0) {
-					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
-					/* We'll assign a new address later */
-					r->end -= r->start;
-					r->start = 0;
-				}
-			}
-		}
-		if (!pass) {
-			r = &dev->resource[PCI_ROM_RESOURCE];
-			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
-				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
-				u32 reg;
-				DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
-				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
-				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
-			}
-		}
-	}
-}
-
-static void __init pcibios_assign_resources(void)
-{
-	struct pci_dev *dev;
-	int idx;
-	struct resource *r;
-
-	pci_for_each_dev(dev) {
-		int class = dev->class >> 8;
-
-		/* Don't touch classless devices and host bridges */
-		if (!class || class == PCI_CLASS_BRIDGE_HOST)
-			continue;
-
-		for(idx=0; idx<6; idx++) {
-			r = &dev->resource[idx];
-
-			/*
-			 *  Don't touch IDE controllers and I/O ports of video cards!
-			 */
-			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
-				continue;
-
-			/*
-			 *  We shall assign a new address to this resource, either because
-			 *  the BIOS forgot to do so or because we have decided the old
-			 *  address was unusable for some reason.
-			 */
-			if (!r->start && r->end)
-				pci_assign_resource(dev, idx);
-		}
-
-		if (pci_probe & PCI_ASSIGN_ROMS) {
-			r = &dev->resource[PCI_ROM_RESOURCE];
-			r->end -= r->start;
-			r->start = 0;
-			if (r->end)
-				pci_assign_resource(dev, PCI_ROM_RESOURCE);
-		}
-	}
-}
-
-void __init pcibios_resource_survey(void)
-{
-	DBG("PCI: Allocating resources\n");
-	pcibios_allocate_bus_resources(&pci_root_buses);
-	pcibios_allocate_resources(0);
-	pcibios_allocate_resources(1);
-	pcibios_assign_resources();
-}
-
-int pcibios_enable_resources(struct pci_dev *dev)
-{
-	u16 cmd, old_cmd;
-	int idx;
-	struct resource *r;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
-	for(idx=0; idx<6; idx++) {
-		r = &dev->resource[idx];
-		if (!r->start && r->end) {
-			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
-			return -EINVAL;
-		}
-		if (r->flags & IORESOURCE_IO)
-			cmd |= PCI_COMMAND_IO;
-		if (r->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-	}
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		cmd |= PCI_COMMAND_MEMORY;
-	if (cmd != old_cmd) {
-		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
-	return 0;
-}
-
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-	u8 lat;
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-	if (lat < 16)
-		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-	else if (lat > pcibios_max_latency)
-		lat = pcibios_max_latency;
-	else
-		return;
-	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-			enum pci_mmap_state mmap_state, int write_combine)
-{
-	unsigned long prot;
-
-	/* I/O space cannot be accessed via normal processor loads and
-	 * stores on this platform.
-	 */
-	if (mmap_state == pci_mmap_io)
-		return -EINVAL;
-
-	/* Leave vm_pgoff as-is, the PCI space address is the physical
-	 * address on this platform.
-	 */
-	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
-	prot = pgprot_val(vma->vm_page_prot);
-	if (boot_cpu_data.x86 > 3)
-		prot |= _PAGE_PCD | _PAGE_PWT;
-	vma->vm_page_prot = __pgprot(prot);
-
-	/* Write-combine setting is ignored, it is changed via the mtrr
-	 * interfaces on this platform.
-	 */
-	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
-			     vma->vm_end - vma->vm_start,
-			     vma->vm_page_prot))
-		return -EAGAIN;
-
-	return 0;
-}
diff -Nru a/arch/i386/kernel/pci-i386.h b/arch/i386/kernel/pci-i386.h
--- a/arch/i386/kernel/pci-i386.h	Thu May  9 15:21:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-/*
- *	Low-Level PCI Access for i386 machines.
- *
- *	(c) 1999 Martin Mares <mj@ucw.cz>
- */
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#define PCI_PROBE_BIOS		0x0001
-#define PCI_PROBE_CONF1		0x0002
-#define PCI_PROBE_CONF2		0x0004
-#define PCI_NO_SORT		0x0100
-#define PCI_BIOS_SORT		0x0200
-#define PCI_NO_CHECKS		0x0400
-#define PCI_USE_PIRQ_MASK	0x0800
-#define PCI_ASSIGN_ROMS		0x1000
-#define PCI_BIOS_IRQ_SCAN	0x2000
-#define PCI_ASSIGN_ALL_BUSSES	0x4000
-#define PCI_NO_ACPI_ROUTING	0x8000
-
-extern unsigned int pci_probe;
-
-/* pci-i386.c */
-
-extern unsigned int pcibios_max_latency;
-
-void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
-
-/* pci-pc.c */
-
-extern int pcibios_last_bus;
-extern struct pci_bus *pci_root_bus;
-extern struct pci_ops *pci_root_ops;
-
-/* pci-irq.c */
-
-struct irq_info {
-	u8 bus, devfn;			/* Bus, device and function */
-	struct {
-		u8 link;		/* IRQ line ID, chipset dependent, 0=not routed */
-		u16 bitmap;		/* Available IRQs */
-	} __attribute__((packed)) irq[4];
-	u8 slot;			/* Slot number, 0=onboard */
-	u8 rfu;
-} __attribute__((packed));
-
-struct irq_routing_table {
-	u32 signature;			/* PIRQ_SIGNATURE should be here */
-	u16 version;			/* PIRQ_VERSION */
-	u16 size;			/* Table size in bytes */
-	u8 rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
-	u16 exclusive_irqs;		/* IRQs devoted exclusively to PCI usage */
-	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
-	u32 miniport_data;		/* Crap */
-	u8 rfu[11];
-	u8 checksum;			/* Modulo 256 checksum must give zero */
-	struct irq_info slots[0];
-} __attribute__((packed));
-
-extern unsigned int pcibios_irq_mask;
-
-extern int pci_use_acpi_routing;
-
-void pcibios_irq_init(void);
-void pcibios_fixup_irqs(void);
-void pcibios_enable_irq(struct pci_dev *dev);
diff -Nru a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
--- a/arch/i386/kernel/pci-irq.c	Thu May  9 15:21:10 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,866 +0,0 @@
-/*
- *	Low-Level PCI Support for PC -- Routing of Interrupts
- *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/io_apic.h>
-
-#include "pci-i386.h"
-
-#define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
-#define PIRQ_VERSION 0x0100
-
-int pci_use_acpi_routing = 0;
-int broken_hp_bios_irq9;
-
-static struct irq_routing_table *pirq_table;
-
-/*
- * Never use: 0, 1, 2 (timer, keyboard, and cascade)
- * Avoid using: 13, 14 and 15 (FP error and IDE).
- * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
- */
-unsigned int pcibios_irq_mask = 0xfff8;
-
-static int pirq_penalty[16] = {
-	1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
-	0, 0, 0, 0, 1000, 100000, 100000, 100000
-};
-
-struct irq_router {
-	char *name;
-	u16 vendor, device;
-	int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
-	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
-};
-
-/*
- *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
- */
-
-static struct irq_routing_table * __init pirq_find_routing_table(void)
-{
-	u8 *addr;
-	struct irq_routing_table *rt;
-	int i;
-	u8 sum;
-
-	for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-		rt = (struct irq_routing_table *) addr;
-		if (rt->signature != PIRQ_SIGNATURE ||
-		    rt->version != PIRQ_VERSION ||
-		    rt->size % 16 ||
-		    rt->size < sizeof(struct irq_routing_table))
-			continue;
-		sum = 0;
-		for(i=0; i<rt->size; i++)
-			sum += addr[i];
-		if (!sum) {
-			DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
-			return rt;
-		}
-	}
-	return NULL;
-}
-
-/*
- *  If we have a IRQ routing table, use it to search for peer host
- *  bridges.  It's a gross hack, but since there are no other known
- *  ways how to get a list of buses, we have to go this way.
- */
-
-static void __init pirq_peer_trick(void)
-{
-	struct irq_routing_table *rt = pirq_table;
-	u8 busmap[256];
-	int i;
-	struct irq_info *e;
-
-	memset(busmap, 0, sizeof(busmap));
-	for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
-		e = &rt->slots[i];
-#ifdef DEBUG
-		{
-			int j;
-			DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
-			for(j=0; j<4; j++)
-				DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
-			DBG("\n");
-		}
-#endif
-		busmap[e->bus] = 1;
-	}
-	for(i=1; i<256; i++)
-		/*
-		 *  It might be a secondary bus, but in this case its parent is already
-		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
-		 */
-		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
-			printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
-	pcibios_last_bus = -1;
-}
-
-/*
- *  Code for querying and setting of IRQ routes on various interrupt routers.
- */
-
-static void eisa_set_level_irq(unsigned int irq)
-{
-	unsigned char mask = 1 << (irq & 7);
-	unsigned int port = 0x4d0 + (irq >> 3);
-	unsigned char val = inb(port);
-
-	if (!(val & mask)) {
-		DBG(" -> edge");
-		outb(val | mask, port);
-	}
-}
-
-/*
- * Common IRQ routing practice: nybbles in config space,
- * offset by some magic constant.
- */
-static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
-{
-	u8 x;
-	unsigned reg = offset + (nr >> 1);
-
-	pci_read_config_byte(router, reg, &x);
-	return (nr & 1) ? (x >> 4) : (x & 0xf);
-}
-
-static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
-{
-	u8 x;
-	unsigned reg = offset + (nr >> 1);
-
-	pci_read_config_byte(router, reg, &x);
-	x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
-	pci_write_config_byte(router, reg, x);
-}
-
-/*
- * ALI pirq entries are damn ugly, and completely undocumented.
- * This has been figured out from pirq tables, and it's not a pretty
- * picture.
- */
-static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
-
-	return irqmap[read_config_nybble(router, 0x48, pirq-1)];
-}
-
-static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
-	unsigned int val = irqmap[irq];
-		
-	if (val) {
-		write_config_nybble(router, 0x48, pirq-1, val);
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
- * just a pointer to the config space.
- */
-static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	u8 x;
-
-	pci_read_config_byte(router, pirq, &x);
-	return (x < 16) ? x : 0;
-}
-
-static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	pci_write_config_byte(router, pirq, irq);
-	return 1;
-}
-
-/*
- * The VIA pirq rules are nibble-based, like ALI,
- * but without the ugly irq number munging.
- */
-static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	return read_config_nybble(router, 0x55, pirq);
-}
-
-static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	write_config_nybble(router, 0x55, pirq, irq);
-	return 1;
-}
-
-/*
- * ITE 8330G pirq rules are nibble-based
- * FIXME: pirqmap may be { 1, 0, 3, 2 },
- * 	  2+3 are both mapped to irq 9 on my system
- */
-static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
-	return read_config_nybble(router,0x43, pirqmap[pirq-1]);
-}
-
-static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
-	write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
-	return 1;
-}
-
-/*
- * OPTI: high four bits are nibble pointer..
- * I wonder what the low bits do?
- */
-static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	return read_config_nybble(router, 0xb8, pirq >> 4);
-}
-
-static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	write_config_nybble(router, 0xb8, pirq >> 4, irq);
-	return 1;
-}
-
-/*
- * Cyrix: nibble offset 0x5C
- */
-static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	return read_config_nybble(router, 0x5C, (pirq-1)^1);
-}
-
-static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
-	return 1;
-}
-
-/*
- *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
- *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
- *	the related registers work as follows:
- *	
- *	general: one byte per re-routable IRQ,
- *		 bit 7      IRQ mapping enabled (0) or disabled (1)
- *		 bits [6:4] reserved
- *		 bits [3:0] IRQ to map to
- *		     allowed: 3-7, 9-12, 14-15
- *		     reserved: 0, 1, 2, 8, 13
- *
- *	individual registers in device config space:
- *
- *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
- *
- *	0x61:			IDEIRQ: bits as in general case - but:
- *				bits [6:5] must be written 01
- *				bit 4 channel-select primary (0), secondary (1)
- *
- *	0x62:			USBIRQ: bits as in general case - but:
- *				bit 4 OHCI function disabled (0), enabled (1)
- *	
- *	0x6a:			ACPI/SCI IRQ - bits as in general case
- *
- *	0x7e:			Data Acq. Module IRQ - bits as in general case
- *
- *	Apparently there are systems implementing PCI routing table using both
- *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
- *	like 0x62 as link values for USBIRQ e.g. So there is no simple
- *	"register = offset + pirq" relation.
- *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
- *	both link mappings.
- *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
- */
-
-static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	u8 x;
-	int reg = pirq;
-
-	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			pci_read_config_byte(router, reg, &x);
-			if (reg != 0x62)
-				break;
-			if (!(x & 0x40))
-				return 0;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
-	}
-	return (x & 0x80) ? 0 : (x & 0x0f);
-}
-
-static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	u8 x;
-	int reg = pirq;
-
-	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
-			if (reg != 0x62)
-				break;
-			/* always mark OHCI enabled, as nothing else knows about this */
-			x |= 0x40;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
-	}
-	pci_write_config_byte(router, reg, x);
-
-	return 1;
-}
-
-/*
- * VLSI: nibble offset 0x74 - educated guess due to routing table and
- *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
- *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
- *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
- *       for the busbridge to the docking station.
- */
-
-static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	if (pirq > 8) {
-		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
-		return 0;
-	}
-	return read_config_nybble(router, 0x74, pirq-1);
-}
-
-static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	if (pirq > 8) {
-		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
-		return 0;
-	}
-	write_config_nybble(router, 0x74, pirq-1, irq);
-	return 1;
-}
-
-/*
- * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
- * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
- * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
- * register is a straight binary coding of desired PIC IRQ (low nibble).
- *
- * The 'link' value in the PIRQ table is already in the correct format
- * for the Index register.  There are some special index values:
- * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
- * and 0x03 for SMBus.
- */
-static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	outb_p(pirq, 0xc00);
-	return inb(0xc01) & 0xf;
-}
-
-static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	outb_p(pirq, 0xc00);
-	outb_p(irq, 0xc01);
-	return 1;
-}
-
-/* Support for AMD756 PCI IRQ Routing
- * Jhon H. Caicedo <jhcaiced@osso.org.co>
- * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
- * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
- * The AMD756 pirq rules are nibble-based
- * offset 0x56 0-3 PIRQA  4-7  PIRQB
- * offset 0x57 0-3 PIRQC  4-7  PIRQD
- */
-static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-	u8 irq;
-	irq = 0;
-	if (pirq <= 4)
-	{
-		irq = read_config_nybble(router, 0x56, pirq - 1);
-	}
-	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
-		dev->vendor, dev->device, pirq, irq);
-	return irq;
-}
-
-static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
-		dev->vendor, dev->device, pirq, irq);
-	if (pirq <= 4)
-	{
-		write_config_nybble(router, 0x56, pirq - 1, irq);
-	}
-	return 1;
-}
-
-#ifdef CONFIG_PCI_BIOS
-
-static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-	struct pci_dev *bridge;
-	int pin = pci_get_interrupt_pin(dev, &bridge);
-	return pcibios_set_irq_routing(bridge, pin, irq);
-}
-
-static struct irq_router pirq_bios_router =
-	{ "BIOS", 0, 0, NULL, pirq_bios_set };
-
-#endif
-
-static struct irq_router pirq_routers[] = {
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
-
-	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
-
-	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
-
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
-
-	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
-
-	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
-	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
-		pirq_amd756_get, pirq_amd756_set },
-
-	{ "default", 0, 0, NULL, NULL }
-};
-
-static struct irq_router *pirq_router;
-static struct pci_dev *pirq_router_dev;
-
-static void __init pirq_find_router(void)
-{
-	struct irq_routing_table *rt = pirq_table;
-	struct irq_router *r;
-
-#ifdef CONFIG_PCI_BIOS
-	if (!rt->signature) {
-		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
-		pirq_router = &pirq_bios_router;
-		return;
-	}
-#endif
-
-	DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
-	    rt->rtr_vendor, rt->rtr_device);
-
-	/* fall back to default router if nothing else found */
-	pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
-
-	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
-	if (!pirq_router_dev) {
-		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
-		return;
-	}
-
-	for(r=pirq_routers; r->vendor; r++) {
-		/* Exact match against router table entry? Use it! */
-		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
-			pirq_router = r;
-			break;
-		}
-		/* Match against router device entry? Use it as a fallback */
-		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
-			pirq_router = r;
-		}
-	}
-	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
-		pirq_router->name,
-		pirq_router_dev->vendor,
-		pirq_router_dev->device,
-		pirq_router_dev->slot_name);
-}
-
-static struct irq_info *pirq_get_info(struct pci_dev *dev)
-{
-	struct irq_routing_table *rt = pirq_table;
-	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
-	struct irq_info *info;
-
-	for (info = rt->slots; entries--; info++)
-		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
-			return info;
-	return NULL;
-}
-
-static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-#ifdef CONFIG_ACPI_PCI
-
-static int acpi_lookup_irq (
-	struct pci_dev		*dev,
-	u8			pin,
-	int			assign)
-{
-	int			result = 0;
-	int			irq = 0;
-
-	/* TBD: Select IRQ from possible to improve routing performance. */
-
-	result = acpi_prt_get_irq(dev, pin, &irq);
-	if (!irq)
-		result = -ENODEV;
-	if (0 != result) {
-		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n",
-		       'A'+pin, dev->slot_name);
-		return result;
-	}
-
-	dev->irq = irq;
-
-	if (!assign) {
-		/* only check for the IRQ */
-		printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq, 
-		       dev->slot_name);
-		return 1;
-	}
-
-	/* also assign an IRQ */
-	if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
-		result = acpi_prt_set_irq(dev, pin, irq);
-		if (0 != result) {
-			printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name);
-			return result;
-		}
-
-		eisa_set_level_irq(irq);
-
-		printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name);
-	}
-
-	return 1;
-}
-
-#endif /* CONFIG_ACPI_PCI */
-
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
-{
-	u8 pin;
-	struct irq_info *info;
-	int i, pirq, newirq;
-	int irq = 0;
-	u32 mask;
-	struct irq_router *r = pirq_router;
-	struct pci_dev *dev2;
-	char *msg = NULL;
-
-	/* Find IRQ pin */
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-	if (!pin) {
-		DBG(" -> no interrupt pin\n");
-		return 0;
-	}
-	pin = pin - 1;
-
-#ifdef CONFIG_ACPI_PCI
-	/* Use ACPI to lookup IRQ */
-	if (pci_use_acpi_routing)
-		return acpi_lookup_irq(dev, pin, assign);
-#endif
-
-	/* Find IRQ routing entry */
-
-	if (!pirq_table)
-		return 0;
-	
-	DBG("IRQ for %s:%d", dev->slot_name, pin);
-	info = pirq_get_info(dev);
-	if (!info) {
-		DBG(" -> not found in routing table\n");
-		return 0;
-	}
-	pirq = info->irq[pin].link;
-	mask = info->irq[pin].bitmap;
-	if (!pirq) {
-		DBG(" -> not routed\n");
-		return 0;
-	}
-	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
-	mask &= pcibios_irq_mask;
-
-	/* Work around broken HP Pavilion Notebooks which assign USB to
-	   IRQ 9 even though it is actually wired to IRQ 11 */
-
-	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
-		dev->irq = 11;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
-		r->set(pirq_router_dev, dev, pirq, 11);
-	}
-
-	/*
-	 * Find the best IRQ to assign: use the one
-	 * reported by the device if possible.
-	 */
-	newirq = dev->irq;
-	if (!((1 << newirq) & mask)) {
-		if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
-		else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
-	}
-	if (!newirq && assign) {
-		for (i = 0; i < 16; i++) {
-			if (!(mask & (1 << i)))
-				continue;
-			if (pirq_penalty[i] < pirq_penalty[newirq] &&
-			    !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
-				free_irq(i, dev);
-				newirq = i;
-			}
-		}
-	}
-	DBG(" -> newirq=%d", newirq);
-
-	/* Check if it is hardcoded */
-	if ((pirq & 0xf0) == 0xf0) {
-		irq = pirq & 0xf;
-		DBG(" -> hardcoded IRQ %d\n", irq);
-		msg = "Hardcoded";
-	} else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
-	((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
-		DBG(" -> got IRQ %d\n", irq);
-		msg = "Found";
-	} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
-		DBG(" -> assigning IRQ %d", newirq);
-		if (r->set(pirq_router_dev, dev, pirq, newirq)) {
-			eisa_set_level_irq(newirq);
-			DBG(" ... OK\n");
-			msg = "Assigned";
-			irq = newirq;
-		}
-	}
-
-	if (!irq) {
-		DBG(" ... failed\n");
-		if (newirq && mask == (1 << newirq)) {
-			msg = "Guessed";
-			irq = newirq;
-		} else
-			return 0;
-	}
-	printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
-
-	/* Update IRQ for all devices with the same pirq value */
-	pci_for_each_dev(dev2) {
-		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
-		if (!pin)
-			continue;
-		pin--;
-		info = pirq_get_info(dev2);
-		if (!info)
-			continue;
-		if (info->irq[pin].link == pirq) {
-			/* We refuse to override the dev->irq information. Give a warning! */
-		    	if ( dev2->irq && dev2->irq != irq && \
-			(!(pci_probe & PCI_USE_PIRQ_MASK) || \
-			((1 << dev2->irq) & mask)) ) {
-		    		printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
-				       dev2->slot_name, dev2->irq, irq);
-		    		continue;
-		    	}
-			dev2->irq = irq;
-			pirq_penalty[irq]++;
-			if (dev != dev2)
-				printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
-		}
-	}
-	return 1;
-}
-
-void __init pcibios_irq_init(void)
-{
-	DBG("PCI: IRQ init\n");
-
-#ifdef CONFIG_ACPI_PCI
-	if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
-		if (acpi_prts.count) {
-			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-			pci_use_acpi_routing = 1;
-			return;
-		}
-		else
-			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
-	}
-#endif
-
-	pirq_table = pirq_find_routing_table();
-
-#ifdef CONFIG_PCI_BIOS
-	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
-		pirq_table = pcibios_get_irq_routing_table();
-#endif
-	if (pirq_table) {
-		pirq_peer_trick();
-		pirq_find_router();
-		if (pirq_table->exclusive_irqs) {
-			int i;
-			for (i=0; i<16; i++)
-				if (!(pirq_table->exclusive_irqs & (1 << i)))
-					pirq_penalty[i] += 100;
-		}
-		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
-		if (io_apic_assign_pci_irqs)
-			pirq_table = NULL;
-	}
-}
-
-void __init pcibios_fixup_irqs(void)
-{
-	struct pci_dev *dev;
-	u8 pin;
-
-	DBG("PCI: IRQ fixup\n");
-	pci_for_each_dev(dev) {
-		/*
-		 * If the BIOS has set an out of range IRQ number, just ignore it.
-		 * Also keep track of which IRQ's are already in use.
-		 */
-		if (dev->irq >= 16) {
-			DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
-			dev->irq = 0;
-		}
-		/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
-		if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
-			pirq_penalty[dev->irq] = 0;
-		pirq_penalty[dev->irq]++;
-	}
-
-	pci_for_each_dev(dev) {
-		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-#ifdef CONFIG_X86_IO_APIC
-		/*
-		 * Recalculate IRQ numbers if we use the I/O APIC.
-		 */
-		if (io_apic_assign_pci_irqs)
-		{
-			int irq;
-
-			if (pin) {
-				pin--;		/* interrupt pins are numbered starting from 1 */
-				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-	/*
-	 * Busses behind bridges are typically not listed in the MP-table.
-	 * In this case we have to look up the IRQ based on the parent bus,
-	 * parent slot, and pin number. The SMP code detects such bridged
-	 * busses itself so we should get into this branch reliably.
-	 */
-				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
-					struct pci_dev * bridge = dev->bus->self;
-
-					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
-							PCI_SLOT(bridge->devfn), pin);
-					if (irq >= 0)
-						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
-							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
-				}
-				if (irq >= 0) {
-					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
-						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
-					dev->irq = irq;
-				}
-			}
-		}
-#endif
-		/*
-		 * Still no IRQ? Try to lookup one...
-		 */
-		if (pin && !dev->irq)
-			pcibios_lookup_irq(dev, 0);
-	}
-}
-
-void pcibios_penalize_isa_irq(int irq)
-{
-	/*
-	 *  If any ISAPnP device reports an IRQ in its list of possible
-	 *  IRQ's, we try to avoid assigning it to PCI devices.
-	 */
-	pirq_penalty[irq] += 100;
-}
-
-void pcibios_enable_irq(struct pci_dev *dev)
-{
-	u8 pin;
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
-		char *msg;
-		if (io_apic_assign_pci_irqs)
-			msg = " Probably buggy MP table.";
-		else if (pci_probe & PCI_BIOS_IRQ_SCAN)
-			msg = "";
-		else
-			msg = " Please try using pci=biosirq.";
-		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
-		       'A' + pin - 1, dev->slot_name, msg);
-	}
-}
diff -Nru a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
--- a/arch/i386/kernel/pci-pc.c	Thu May  9 15:21:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1423 +0,0 @@
-/*
- *	Low-Level PCI Support for PC
- *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-
-#include "pci-i386.h"
-
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
-
-int pcibios_last_bus = -1;
-struct pci_bus *pci_root_bus = NULL;
-struct pci_ops *pci_root_ops = NULL;
-
-int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
-int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
-
-#ifdef CONFIG_MULTIQUAD
-#define BUS2QUAD(global) (mp_bus_id_to_node[global])
-#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
-#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
-#else
-#define BUS2QUAD(global) (0)
-#define BUS2LOCAL(global) (global)
-#define QUADLOCAL2BUS(quad,local) (local)
-#endif
-
-/*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
- */
-static spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*
- * Functions for accessing PCI configuration space with type 1 accesses
- */
-
-#ifdef CONFIG_PCI_DIRECT
-
-#ifdef CONFIG_MULTIQUAD
-#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
-	(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
-
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
-{
-	unsigned long flags;
-
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
-
-	switch (len) {
-	case 1:
-		*value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
-		break;
-	case 2:
-		*value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
-		break;
-	case 4:
-		*value = inl_quad(0xCFC, BUS2QUAD(bus));
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
-{
-	unsigned long flags;
-
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
-
-	switch (len) {
-	case 1:
-		outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
-		break;
-	case 2:
-		outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
-		break;
-	case 4:
-		outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-#else /* !CONFIG_MULTIQUAD */
-#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
-	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
-
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
-{
-	unsigned long flags;
-
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
-
-	switch (len) {
-	case 1:
-		*value = inb(0xCFC + (reg & 3));
-		break;
-	case 2:
-		*value = inw(0xCFC + (reg & 2));
-		break;
-	case 4:
-		*value = inl(0xCFC);
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */
-{
-	unsigned long flags;
-
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
-
-	switch (len) {
-	case 1:
-		outb((u8)value, 0xCFC + (reg & 3));
-		break;
-	case 2:
-		outw((u16)value, 0xCFC + (reg & 2));
-		break;
-	case 4:
-		outl((u32)value, 0xCFC);
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-#endif /* CONFIG_MULTIQUAD */
-
-#undef PCI_CONF1_ADDRESS
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	int result; 
-	u32 data;
-
-	if (!value) 
-		return -EINVAL;
-
-	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, &data);
-
-	*value = (u8)data;
-
-	return result;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	int result; 
-	u32 data;
-
-	if (!value) 
-		return -EINVAL;
-
-	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, &data);
-
-	*value = (u16)data;
-
-	return result;
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	if (!value) 
-		return -EINVAL;
-
-	return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static struct pci_ops pci_direct_conf1 = {
-	pci_conf1_read_config_byte,
-	pci_conf1_read_config_word,
-	pci_conf1_read_config_dword,
-	pci_conf1_write_config_byte,
-	pci_conf1_write_config_word,
-	pci_conf1_write_config_dword
-};
-
-
-/*
- * Functions for accessing PCI configuration space with type 2 accesses
- */
-
-#define PCI_CONF2_ADDRESS(dev, reg)	(u16)(0xC000 | (dev << 8) | reg)
-
-static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
-{
-	unsigned long flags;
-
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-		return -EINVAL;
-
-	if (dev & 0x10) 
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
-	outb((u8)bus, 0xCFA);
-
-	switch (len) {
-	case 1:
-		*value = inb(PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	case 2:
-		*value = inw(PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	case 4:
-		*value = inl(PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	}
-
-	outb (0, 0xCF8);
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-	unsigned long flags;
-
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-		return -EINVAL;
-
-	if (dev & 0x10) 
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
-	outb((u8)bus, 0xCFA);
-
-	switch (len) {
-	case 1:
-		outb ((u8)value, PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	case 2:
-		outw ((u16)value, PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	case 4:
-		outl ((u32)value, PCI_CONF2_ADDRESS(dev, reg));
-		break;
-	}
-
-	outb (0, 0xCF8);    
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return 0;
-}
-
-#undef PCI_CONF2_ADDRESS
-
-static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	int result; 
-	u32 data;
-	result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, &data);
-	*value = (u8)data;
-	return result;
-}
-
-static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	int result; 
-	u32 data;
-	result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, &data);
-	*value = (u16)data;
-	return result;
-}
-
-static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static struct pci_ops pci_direct_conf2 = {
-	pci_conf2_read_config_byte,
-	pci_conf2_read_config_word,
-	pci_conf2_read_config_dword,
-	pci_conf2_write_config_byte,
-	pci_conf2_write_config_word,
-	pci_conf2_write_config_dword
-};
-
-
-/*
- * Before we decide to use direct hardware access mechanisms, we try to do some
- * trivial checks to ensure it at least _seems_ to be working -- we just test
- * whether bus 00 contains a host bridge (this is similar to checking
- * techniques used in XFree86, but ours should be more reliable since we
- * attempt to make use of direct access hints provided by the PCI BIOS).
- *
- * This should be close to trivial, but it isn't, because there are buggy
- * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
- */
-static int __devinit pci_sanity_check(struct pci_ops *o)
-{
-	u16 x;
-	struct pci_bus bus;		/* Fake bus and device */
-	struct pci_dev dev;
-
-	if (pci_probe & PCI_NO_CHECKS)
-		return 1;
-	bus.number = 0;
-	dev.bus = &bus;
-	for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
-		if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
-		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
-		    (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
-		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
-			return 1;
-	DBG("PCI: Sanity check failed\n");
-	return 0;
-}
-
-static struct pci_ops * __devinit pci_check_direct(void)
-{
-	unsigned int tmp;
-	unsigned long flags;
-
-	__save_flags(flags); __cli();
-
-	/*
-	 * Check if configuration type 1 works.
-	 */
-	if (pci_probe & PCI_PROBE_CONF1) {
-		outb (0x01, 0xCFB);
-		tmp = inl (0xCF8);
-		outl (0x80000000, 0xCF8);
-		if (inl (0xCF8) == 0x80000000 &&
-		    pci_sanity_check(&pci_direct_conf1)) {
-			outl (tmp, 0xCF8);
-			__restore_flags(flags);
-			printk(KERN_INFO "PCI: Using configuration type 1\n");
-			if (!request_region(0xCF8, 8, "PCI conf1"))
-				return NULL;
-			return &pci_direct_conf1;
-		}
-		outl (tmp, 0xCF8);
-	}
-
-	/*
-	 * Check if configuration type 2 works.
-	 */
-	if (pci_probe & PCI_PROBE_CONF2) {
-		outb (0x00, 0xCFB);
-		outb (0x00, 0xCF8);
-		outb (0x00, 0xCFA);
-		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
-		    pci_sanity_check(&pci_direct_conf2)) {
-			__restore_flags(flags);
-			printk(KERN_INFO "PCI: Using configuration type 2\n");
-			if (!request_region(0xCF8, 4, "PCI conf2"))
-				return NULL;
-			return &pci_direct_conf2;
-		}
-	}
-
-	__restore_flags(flags);
-	return NULL;
-}
-
-#endif
-
-/*
- * BIOS32 and PCI BIOS handling.
- */
-
-#ifdef CONFIG_PCI_BIOS
-
-#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
-#define PCIBIOS_FIND_PCI_DEVICE		0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
-#define PCIBIOS_READ_CONFIG_BYTE	0xb108
-#define PCIBIOS_READ_CONFIG_WORD	0xb109
-#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
-#define PCIBIOS_GET_ROUTING_OPTIONS	0xb10e
-#define PCIBIOS_SET_PCI_HW_INT		0xb10f
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
-/* PCI BIOS hardware mechanism flags */
-#define PCIBIOS_HW_TYPE1		0x01
-#define PCIBIOS_HW_TYPE2		0x02
-#define PCIBIOS_HW_TYPE1_SPEC		0x10
-#define PCIBIOS_HW_TYPE2_SPEC		0x20
-
-/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * 	Standard BIOS 32-bit Service Directory Proposal
- * 	Revision 0.4 May 24, 1993
- * 	Phoenix Technologies Ltd.
- *	Norwood, MA
- * and the PCI BIOS specification.
- */
-
-union bios32 {
-	struct {
-		unsigned long signature;	/* _32_ */
-		unsigned long entry;		/* 32 bit physical address */
-		unsigned char revision;		/* Revision level, 0 */
-		unsigned char length;		/* Length in paragraphs should be 01 */
-		unsigned char checksum;		/* All bytes must add up to zero */
-		unsigned char reserved[5]; 	/* Must be zero */
-	} fields;
-	char chars[16];
-};
-
-/*
- * Physical address of the service directory.  I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
- */
-
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} bios32_indirect = { 0, __KERNEL_CS };
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
-{
-	unsigned char return_code;	/* %al */
-	unsigned long address;		/* %ebx */
-	unsigned long length;		/* %ecx */
-	unsigned long entry;		/* %edx */
-	unsigned long flags;
-
-	__save_flags(flags); __cli();
-	__asm__("lcall *(%%edi); cld"
-		: "=a" (return_code),
-		  "=b" (address),
-		  "=c" (length),
-		  "=d" (entry)
-		: "0" (service),
-		  "1" (0),
-		  "D" (&bios32_indirect));
-	__restore_flags(flags);
-
-	switch (return_code) {
-		case 0:
-			return address + entry;
-		case 0x80:	/* Not present */
-			printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
-			return 0;
-		default: /* Shouldn't happen */
-			printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
-				service, return_code);
-			return 0;
-	}
-}
-
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} pci_indirect = { 0, __KERNEL_CS };
-
-static int pci_bios_present;
-
-static int __devinit check_pcibios(void)
-{
-	u32 signature, eax, ebx, ecx;
-	u8 status, major_ver, minor_ver, hw_mech;
-	unsigned long flags, pcibios_entry;
-
-	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
-
-		__save_flags(flags); __cli();
-		__asm__(
-			"lcall *(%%edi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=d" (signature),
-			  "=a" (eax),
-			  "=b" (ebx),
-			  "=c" (ecx)
-			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
-			  "D" (&pci_indirect)
-			: "memory");
-		__restore_flags(flags);
-
-		status = (eax >> 8) & 0xff;
-		hw_mech = eax & 0xff;
-		major_ver = (ebx >> 8) & 0xff;
-		minor_ver = ebx & 0xff;
-		if (pcibios_last_bus < 0)
-			pcibios_last_bus = ecx & 0xff;
-		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
-			status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
-		if (status || signature != PCI_SIGNATURE) {
-			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
-				status, signature);
-			return 0;
-		}
-		printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
-			major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
-#ifdef CONFIG_PCI_DIRECT
-		if (!(hw_mech & PCIBIOS_HW_TYPE1))
-			pci_probe &= ~PCI_PROBE_CONF1;
-		if (!(hw_mech & PCIBIOS_HW_TYPE2))
-			pci_probe &= ~PCI_PROBE_CONF2;
-#endif
-		return 1;
-	}
-	return 0;
-}
-
-static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
-					unsigned short index, unsigned char *bus, unsigned char *device_fn)
-{
-	unsigned short bx;
-	unsigned short ret;
-
-	__asm__("lcall *(%%edi); cld\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=b" (bx),
-		  "=a" (ret)
-		: "1" (PCIBIOS_FIND_PCI_DEVICE),
-		  "c" (device_id),
-		  "d" (vendor),
-		  "S" ((int) index),
-		  "D" (&pci_indirect));
-	*bus = (bx >> 8) & 0xff;
-	*device_fn = bx & 0xff;
-	return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
-{
-	unsigned long result = 0;
-	unsigned long flags;
-	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
-
-	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	switch (len) {
-	case 1:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=c" (*value),
-			  "=a" (result)
-			: "1" (PCIBIOS_READ_CONFIG_BYTE),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	case 2:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=c" (*value),
-			  "=a" (result)
-			: "1" (PCIBIOS_READ_CONFIG_WORD),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	case 4:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=c" (*value),
-			  "=a" (result)
-			: "1" (PCIBIOS_READ_CONFIG_DWORD),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return (int)((result & 0xff00) >> 8);
-}
-
-static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-	unsigned long result = 0;
-	unsigned long flags;
-	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
-
-	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-		return -EINVAL;
-
-	spin_lock_irqsave(&pci_config_lock, flags);
-
-	switch (len) {
-	case 1:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=a" (result)
-			: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
-			  "c" (value),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	case 2:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=a" (result)
-			: "0" (PCIBIOS_WRITE_CONFIG_WORD),
-			  "c" (value),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	case 4:
-		__asm__("lcall *(%%esi); cld\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:"
-			: "=a" (result)
-			: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
-			  "c" (value),
-			  "b" (bx),
-			  "D" ((long)reg),
-			  "S" (&pci_indirect));
-		break;
-	}
-
-	spin_unlock_irqrestore(&pci_config_lock, flags);
-
-	return (int)((result & 0xff00) >> 8);
-}
-
-static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	int result; 
-	u32 data;
-
-	if (!value) 
-		return -EINVAL;
-
-	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, &data);
-
-	*value = (u8)data;
-
-	return result;
-}
-
-static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	int result; 
-	u32 data;
-
-	if (!value) 
-		return -EINVAL;
-
-	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, &data);
-
-	*value = (u16)data;
-
-	return result;
-}
-
-static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	if (!value) 
-		return -EINVAL;
-	
-	return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-		PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-
-/*
- * Function table for BIOS32 access
- */
-
-static struct pci_ops pci_bios_access = {
-      pci_bios_read_config_byte,
-      pci_bios_read_config_word,
-      pci_bios_read_config_dword,
-      pci_bios_write_config_byte,
-      pci_bios_write_config_word,
-      pci_bios_write_config_dword
-};
-
-/*
- * Try to find PCI BIOS.
- */
-
-static struct pci_ops * __devinit pci_find_bios(void)
-{
-	union bios32 *check;
-	unsigned char sum;
-	int i, length;
-
-	/*
-	 * Follow the standard procedure for locating the BIOS32 Service
-	 * directory by scanning the permissible address range from
-	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
-	 */
-
-	for (check = (union bios32 *) __va(0xe0000);
-	     check <= (union bios32 *) __va(0xffff0);
-	     ++check) {
-		if (check->fields.signature != BIOS32_SIGNATURE)
-			continue;
-		length = check->fields.length * 16;
-		if (!length)
-			continue;
-		sum = 0;
-		for (i = 0; i < length ; ++i)
-			sum += check->chars[i];
-		if (sum != 0)
-			continue;
-		if (check->fields.revision != 0) {
-			printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
-				check->fields.revision, check);
-			continue;
-		}
-		DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
-		if (check->fields.entry >= 0x100000) {
-			printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
-			return NULL;
-		} else {
-			unsigned long bios32_entry = check->fields.entry;
-			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
-			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
-			if (check_pcibios())
-				return &pci_bios_access;
-		}
-		break;	/* Hopefully more than one BIOS32 cannot happen... */
-	}
-
-	return NULL;
-}
-
-/*
- * Sort the device list according to PCI BIOS. Nasty hack, but since some
- * fool forgot to define the `correct' device order in the PCI BIOS specs
- * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
- * which used BIOS ordering, we are bound to do this...
- */
-
-static void __devinit pcibios_sort(void)
-{
-	LIST_HEAD(sorted_devices);
-	struct list_head *ln;
-	struct pci_dev *dev, *d;
-	int idx, found;
-	unsigned char bus, devfn;
-
-	DBG("PCI: Sorting device list...\n");
-	while (!list_empty(&pci_devices)) {
-		ln = pci_devices.next;
-		dev = pci_dev_g(ln);
-		idx = found = 0;
-		while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
-			idx++;
-			for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
-				d = pci_dev_g(ln);
-				if (d->bus->number == bus && d->devfn == devfn) {
-					list_del(&d->global_list);
-					list_add_tail(&d->global_list, &sorted_devices);
-					if (d == dev)
-						found = 1;
-					break;
-				}
-			}
-			if (ln == &pci_devices) {
-				printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
-				/*
-				 * We must not continue scanning as several buggy BIOSes
-				 * return garbage after the last device. Grr.
-				 */
-				break;
-			}
-		}
-		if (!found) {
-			printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
-				dev->bus->number, dev->devfn);
-			list_del(&dev->global_list);
-			list_add_tail(&dev->global_list, &sorted_devices);
-		}
-	}
-	list_splice(&sorted_devices, &pci_devices);
-}
-
-/*
- *  BIOS Functions for IRQ Routing
- */
-
-struct irq_routing_options {
-	u16 size;
-	struct irq_info *table;
-	u16 segment;
-} __attribute__((packed));
-
-struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
-{
-	struct irq_routing_options opt;
-	struct irq_routing_table *rt = NULL;
-	int ret, map;
-	unsigned long page;
-
-	if (!pci_bios_present)
-		return NULL;
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return NULL;
-	opt.table = (struct irq_info *) page;
-	opt.size = PAGE_SIZE;
-	opt.segment = __KERNEL_DS;
-
-	DBG("PCI: Fetching IRQ routing table... ");
-	__asm__("push %%es\n\t"
-		"push %%ds\n\t"
-		"pop  %%es\n\t"
-		"lcall *(%%esi); cld\n\t"
-		"pop %%es\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret),
-		  "=b" (map)
-		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
-		  "1" (0),
-		  "D" ((long) &opt),
-		  "S" (&pci_indirect));
-	DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
-	if (ret & 0xff00)
-		printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
-	else if (opt.size) {
-		rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
-		if (rt) {
-			memset(rt, 0, sizeof(struct irq_routing_table));
-			rt->size = opt.size + sizeof(struct irq_routing_table);
-			rt->exclusive_irqs = map;
-			memcpy(rt->slots, (void *) page, opt.size);
-			printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
-		}
-	}
-	free_page(page);
-	return rt;
-}
-
-
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
-{
-	int ret;
-
-	__asm__("lcall *(%%esi); cld\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_SET_PCI_HW_INT),
-		  "b" ((dev->bus->number << 8) | dev->devfn),
-		  "c" ((irq << 8) | (pin + 10)),
-		  "S" (&pci_indirect));
-	return !(ret & 0xff00);
-}
-
-#endif
-
-/*
- * Several buggy motherboards address only 16 devices and mirror
- * them to next 16 IDs. We try to detect this `feature' on all
- * primary buses (those containing host bridges as they are
- * expected to be unique) and remove the ghost devices.
- */
-
-static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
-{
-	struct list_head *ln, *mn;
-	struct pci_dev *d, *e;
-	int mirror = PCI_DEVFN(16,0);
-	int seen_host_bridge = 0;
-	int i;
-
-	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
-	for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
-		d = pci_dev_b(ln);
-		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-			seen_host_bridge++;
-		for (mn=ln->next; mn != &b->devices; mn=mn->next) {
-			e = pci_dev_b(mn);
-			if (e->devfn != d->devfn + mirror ||
-			    e->vendor != d->vendor ||
-			    e->device != d->device ||
-			    e->class != d->class)
-				continue;
-			for(i=0; i<PCI_NUM_RESOURCES; i++)
-				if (e->resource[i].start != d->resource[i].start ||
-				    e->resource[i].end != d->resource[i].end ||
-				    e->resource[i].flags != d->resource[i].flags)
-					continue;
-			break;
-		}
-		if (mn == &b->devices)
-			return;
-	}
-	if (!seen_host_bridge)
-		return;
-	printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
-
-	ln = &b->devices;
-	while (ln->next != &b->devices) {
-		d = pci_dev_b(ln->next);
-		if (d->devfn >= mirror) {
-			list_del(&d->global_list);
-			list_del(&d->bus_list);
-			kfree(d);
-		} else
-			ln = ln->next;
-	}
-}
-
-/*
- * Discover remaining PCI buses in case there are peer host bridges.
- * We use the number of last PCI bus provided by the PCI BIOS.
- */
-static void __devinit pcibios_fixup_peer_bridges(void)
-{
-	int n;
-	struct pci_bus bus;
-	struct pci_dev dev;
-	u16 l;
-
-	if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
-		return;
-	DBG("PCI: Peer bridge fixup\n");
-	for (n=0; n <= pcibios_last_bus; n++) {
-		if (pci_bus_exists(&pci_root_buses, n))
-			continue;
-		bus.number = n;
-		bus.ops = pci_root_ops;
-		dev.bus = &bus;
-		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
-			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
-			    l != 0x0000 && l != 0xffff) {
-				DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
-				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
-				pci_scan_bus(n, pci_root_ops, NULL);
-				break;
-			}
-	}
-}
-
-/*
- * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
- */
-
-static void __devinit pci_fixup_i450nx(struct pci_dev *d)
-{
-	/*
-	 * i450NX -- Find and scan all secondary buses on all PXB's.
-	 */
-	int pxb, reg;
-	u8 busno, suba, subb;
-#ifdef CONFIG_MULTIQUAD
-	int quad = BUS2QUAD(d->bus->number);
-#endif
-	printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
-	reg = 0xd0;
-	for(pxb=0; pxb<2; pxb++) {
-		pci_read_config_byte(d, reg++, &busno);
-		pci_read_config_byte(d, reg++, &suba);
-		pci_read_config_byte(d, reg++, &subb);
-		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
-		if (busno)
-			pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL);	/* Bus A */
-		if (suba < subb)
-			pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL);	/* Bus B */
-	}
-	pcibios_last_bus = -1;
-}
-
-static void __devinit pci_fixup_i450gx(struct pci_dev *d)
-{
-	/*
-	 * i450GX and i450KX -- Find and scan all secondary buses.
-	 * (called separately for each PCI bridge found)
-	 */
-	u8 busno;
-	pci_read_config_byte(d, 0x4a, &busno);
-	printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
-	pci_scan_bus(busno, pci_root_ops, NULL);
-	pcibios_last_bus = -1;
-}
-
-static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
-{
-	/*
-	 * UM8886BF IDE controller sets region type bits incorrectly,
-	 * therefore they look like memory despite of them being I/O.
-	 */
-	int i;
-
-	printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
-	for(i=0; i<4; i++)
-		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-}
-
-static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
-{
-    /*
-     * NCR 53C810 returns class code 0 (at least on some systems).
-     * Fix class to be PCI_CLASS_STORAGE_SCSI
-     */
-    if (!d->class) {
-        printk("PCI: fixing NCR 53C810 class code for %s\n", d->slot_name);
-        d->class = PCI_CLASS_STORAGE_SCSI << 8;
-    }
-}
-
-static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
-{
-	int i;
-
-	/*
-	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
-	 */
-	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
-		return;
-	DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
-	for(i=0; i<4; i++) {
-		struct resource *r = &d->resource[i];
-		if ((r->start & ~0x80) == 0x374) {
-			r->start |= 2;
-			r->end = r->start;
-		}
-	}
-}
-
-static void __devinit  pci_fixup_ide_trash(struct pci_dev *d)
-{
-	int i;
-
-	/*
-	 * There exist PCI IDE controllers which have utter garbage
-	 * in first four base registers. Ignore that.
-	 */
-	DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name);
-	for(i=0; i<4; i++)
-		d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
-}
-
-static void __devinit  pci_fixup_latency(struct pci_dev *d)
-{
-	/*
-	 *  SiS 5597 and 5598 chipsets require latency timer set to
-	 *  at most 32 to avoid lockups.
-	 */
-	DBG("PCI: Setting max latency to 32\n");
-	pcibios_max_latency = 32;
-}
-
-static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
-{
-	/*
-	 * PIIX4 ACPI device: hardwired IRQ9
-	 */
-	d->irq = 9;
-}
-
-/*
- * Addresses issues with problems in the memory write queue timer in
- * certain VIA Northbridges.  This bugfix is per VIA's specifications.
- *
- * VIA 8363,8622,8361 Northbridges:
- *  - bits  5, 6, 7 at offset 0x55 need to be turned off
- * VIA 8367 (KT266x) Northbridges:
- *  - bits  5, 6, 7 at offset 0x95 need to be turned off
- */
-static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
-{
-	u8 v;
-	int where = 0x55;
-
-	if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
-  	        where = 0x95; /* the memory write queue timer register is 
-                                 different for the kt266x's: 0x95 not 0x55 */
-	}
-
-        pci_read_config_byte(d, where, &v);
-	if (v & 0xe0) {
-		printk("Disabling broken memory write queue: [%02x] %02x->%02x\n",
-			where, v, v & 0x1f);
-		v &= 0x1f; /* clear bits 5, 6, 7 */
-		pci_write_config_byte(d, where, v);
-	}
-}
-
-struct pci_fixup pcibios_fixups[] = {
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5513,		pci_fixup_ide_trash },
-	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
- 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_via_northbridge_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8622,	        pci_fixup_via_northbridge_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
-	{ 0 }
-};
-
-/*
- *  Called after each bus is probed, but before its children
- *  are examined.
- */
-
-void __devinit  pcibios_fixup_bus(struct pci_bus *b)
-{
-	pcibios_fixup_ghosts(b);
-	pci_read_bridge_bases(b);
-}
-
-
-struct pci_bus * __devinit pcibios_scan_root(int busnum)
-{
-	struct list_head *list;
-	struct pci_bus *bus;
-
-	list_for_each(list, &pci_root_buses) {
-		bus = pci_bus_b(list);
-		if (bus->number == busnum) {
-			/* Already scanned */
-			return bus;
-		}
-	}
-
-	printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
-
-	return pci_scan_bus(busnum, pci_root_ops, NULL);
-}
-
-void __devinit pcibios_config_init(void)
-{
-	struct pci_ops *tmp=NULL;
-
-	/*
-	 * Try all known PCI access methods. Note that we support using 
-	 * both PCI BIOS and direct access, with a preference for direct.
-	 */
-
-#ifdef CONFIG_PCI_BIOS
-	if ((pci_probe & PCI_PROBE_BIOS) 
-		&& ((pci_root_ops = pci_find_bios()))) {
-		pci_probe |= PCI_BIOS_SORT;
-		pci_bios_present = 1;
-		pci_config_read = pci_bios_read;
-		pci_config_write = pci_bios_write;
-	}
-#endif
-	tmp = pci_root_ops;
-
-#ifdef CONFIG_PCI_DIRECT
-	if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
-		&& (pci_root_ops = pci_check_direct())) {
-		if (pci_root_ops == &pci_direct_conf1) {
-			pci_config_read = pci_conf1_read;
-			pci_config_write = pci_conf1_write;
-		}
-		else {
-			pci_config_read = pci_conf2_read;
-			pci_config_write = pci_conf2_write;
-		}
-	}
-#endif
-
-	/* if direct access failed, fall back to BIOS access. */
-	if (pci_root_ops == NULL)
-		pci_root_ops = tmp;
-
-	return;
-}
-
-void __init pcibios_init(void)
-{
-	int quad;
-
-	if (!pci_root_ops)
-		pcibios_config_init();
-	if (!pci_root_ops) {
-		printk("PCI: System does not support PCI\n");
-		return;
-	}
-
-	printk("PCI: Probing PCI hardware\n");
-	pci_root_bus = pcibios_scan_root(0);
-	if (clustered_apic_mode && (numnodes > 1)) {
-		for (quad = 1; quad < numnodes; ++quad) {
-			printk("Scanning PCI bus %d for quad %d\n", 
-				QUADLOCAL2BUS(quad,0), quad);
-			pci_scan_bus(QUADLOCAL2BUS(quad,0), 
-				pci_root_ops, NULL);
-		}
-	}
-
-	pcibios_irq_init();
-
-	if (!pci_use_acpi_routing)
-		pcibios_fixup_peer_bridges();
-
-	pcibios_fixup_irqs();
-	pcibios_resource_survey();
-
-#ifdef CONFIG_PCI_BIOS
-	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
-		pcibios_sort();
-#endif
-}
-
-char * __devinit  pcibios_setup(char *str)
-{
-	if (!strcmp(str, "off")) {
-		pci_probe = 0;
-		return NULL;
-	}
-#ifdef CONFIG_PCI_BIOS
-	else if (!strcmp(str, "bios")) {
-		pci_probe = PCI_PROBE_BIOS;
-		return NULL;
-	} else if (!strcmp(str, "nobios")) {
-		pci_probe &= ~PCI_PROBE_BIOS;
-		return NULL;
-	} else if (!strcmp(str, "nosort")) {
-		pci_probe |= PCI_NO_SORT;
-		return NULL;
-	} else if (!strcmp(str, "biosirq")) {
-		pci_probe |= PCI_BIOS_IRQ_SCAN;
-		return NULL;
-	}
-#endif
-#ifdef CONFIG_PCI_DIRECT
-	else if (!strcmp(str, "conf1")) {
-		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
-		return NULL;
-	}
-	else if (!strcmp(str, "conf2")) {
-		pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
-		return NULL;
-	}
-#endif
-#ifdef CONFIG_ACPI_PCI
-	else if (!strcmp(str, "noacpi")) {
-		pci_probe |= PCI_NO_ACPI_ROUTING;
-		return NULL;
-	}
-#endif
-	else if (!strcmp(str, "rom")) {
-		pci_probe |= PCI_ASSIGN_ROMS;
-		return NULL;
-	} else if (!strcmp(str, "assign-busses")) {
-		pci_probe |= PCI_ASSIGN_ALL_BUSSES;
-		return NULL;
-	} else if (!strcmp(str, "usepirqmask")) {
-		pci_probe |= PCI_USE_PIRQ_MASK;
-		return NULL;
-	} else if (!strncmp(str, "irqmask=", 8)) {
-		pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
-		return NULL;
-	} else if (!strncmp(str, "lastbus=", 8)) {
-		pcibios_last_bus = simple_strtol(str+8, NULL, 0);
-		return NULL;
-	}
-	return str;
-}
-
-unsigned int pcibios_assign_all_busses(void)
-{
-	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
-}
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-	int err;
-
-	if ((err = pcibios_enable_resources(dev)) < 0)
-		return err;
-	pcibios_enable_irq(dev);
-	return 0;
-}
diff -Nru a/arch/i386/kernel/pci-visws.c b/arch/i386/kernel/pci-visws.c
--- a/arch/i386/kernel/pci-visws.c	Thu May  9 15:21:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-/*
- *	Low-Level PCI Support for SGI Visual Workstation
- *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/smp.h>
-#include <asm/lithium.h>
-#include <asm/io.h>
-
-#include "pci-i386.h"
-
-unsigned int pci_probe = 0;
-
-/*
- *  The VISWS uses configuration access type 1 only.
- */
-
-#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	*value = inb(0xCFC + (where&3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);    
-	*value = inw(0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	*value = inl(0xCFC);
-	return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);    
-	outb(value, 0xCFC + (where&3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	outw(value, 0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	outl(value, 0xCFC);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-#undef CONFIG_CMD
-
-static struct pci_ops visws_pci_ops = {
-	pci_conf1_read_config_byte,
-	pci_conf1_read_config_word,
-	pci_conf1_read_config_dword,
-	pci_conf1_write_config_byte,
-	pci_conf1_write_config_word,
-	pci_conf1_write_config_dword
-};
-
-static void __init pcibios_fixup_irqs(void)
-{
-	struct pci_dev *dev, *p;
-	u8 pin;
-	int irq;
-
-	pci_for_each_dev(dev) {
-		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-		dev->irq = 0;
-		if (!pin)
-			continue;
-		pin--;
-		if (dev->bus->parent) {
-			p = dev->bus->parent->self;
-			pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-		} else
-			p = dev;
-		irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
-		if (irq >= 0)
-			dev->irq = irq;
-		DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
-	}
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *b)
-{
-	pci_read_bridge_bases(b);
-}
-
-#if 0
-static struct resource visws_pci_bus_resources[2] = {
-	{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
-	{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
-};
-#endif
-
-void __init pcibios_init(void)
-{
-	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
-
-	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
-	pci_scan_bus(0, &visws_pci_ops, NULL);
-	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
-	pcibios_fixup_irqs();
-	pcibios_resource_survey();
-}
-
-char * __init pcibios_setup(char *str)
-{
-	return str;
-}
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-	return pcibios_enable_resources(dev);
-}
-
-void __init pcibios_penalize_isa_irq(irq)
-{
-}
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Thu May  9 15:21:06 2002
+++ b/arch/i386/kernel/signal.c	Thu May  9 15:21:06 2002
@@ -657,7 +657,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Nru a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
--- a/arch/i386/lib/Makefile	Thu May  9 15:21:02 2002
+++ b/arch/i386/lib/Makefile	Thu May  9 15:21:02 2002
@@ -2,8 +2,7 @@
 # Makefile for i386-specific library files..
 #
 
-.S.o:
-	$(CC) $(AFLAGS) -c $< -o $*.o
+USE_STANDARD_AS_RULE	:= true
 
 L_TARGET = lib.a
 
diff -Nru a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c
--- a/arch/i386/lib/mmx.c	Thu May  9 15:21:08 2002
+++ b/arch/i386/lib/mmx.c	Thu May  9 15:21:08 2002
@@ -89,6 +89,30 @@
 		from+=64;
 		to+=64;
 	}
+
+	for(; i>0; i--)
+	{
+		__asm__ __volatile__ (
+		"  movq (%0), %%mm0\n"
+		"  movq 8(%0), %%mm1\n"
+		"  movq 16(%0), %%mm2\n"
+		"  movq 24(%0), %%mm3\n"
+		"  movq %%mm0, (%1)\n"
+		"  movq %%mm1, 8(%1)\n"
+		"  movq %%mm2, 16(%1)\n"
+		"  movq %%mm3, 24(%1)\n"
+		"  movq 32(%0), %%mm0\n"
+		"  movq 40(%0), %%mm1\n"
+		"  movq 48(%0), %%mm2\n"
+		"  movq 56(%0), %%mm3\n"
+		"  movq %%mm0, 32(%1)\n"
+		"  movq %%mm1, 40(%1)\n"
+		"  movq %%mm2, 48(%1)\n"
+		"  movq %%mm3, 56(%1)\n"
+		: : "r" (from), "r" (to) : "memory");
+		from+=64;
+		to+=64;
+	}
 	/*
 	 *	Now do the tail of the block
 	 */
diff -Nru a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
--- a/arch/i386/math-emu/Makefile	Thu May  9 15:21:01 2002
+++ b/arch/i386/math-emu/Makefile	Thu May  9 15:21:01 2002
@@ -9,8 +9,8 @@
 PARANOID = -DPARANOID
 CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
 
-.S.o:
-	$(CC) $(AFLAGS) $(PARANOID) -c $<
+USE_STANDARD_AS_RULE	:= true
+EXTRA_AFLAGS	:= $(PARANOID)
 
 # From 'C' language sources:
 C_OBJS =fpu_entry.o errors.o \
diff -Nru a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/Makefile	Thu May  9 15:21:10 2002
@@ -0,0 +1,29 @@
+O_TARGET        := pci.o
+
+obj-y		:= i386.o
+
+ifdef	CONFIG_VISWS
+obj-y		+= visws.o
+else
+
+obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
+obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+
+ifdef	CONFIG_MULTIQUAD
+obj-y		+= numa.o
+else
+obj-y		+= fixup.o
+
+ifdef	CONFIG_ACPI_PCI
+obj-y		+= acpi.o
+endif
+obj-y		+= legacy.o
+
+
+endif		# CONFIG_MULTIQUAD
+obj-y		+= irq.o common.o
+endif		# CONFIG_VISWS
+
+export-objs     +=      $(obj-y)
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/acpi.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,74 @@
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include "pci.h"
+
+extern void eisa_set_level_irq(int irq);
+
+static int acpi_lookup_irq (
+	struct pci_dev		*dev,
+	int			assign)
+{
+	int			result = 0;
+	int			irq = 0;
+	u8			pin;
+
+	/* TBD: Select IRQ from possible to improve routing performance. */
+
+	/* Find IRQ pin */
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin) {
+		DBG(" -> no interrupt pin\n");
+		return 0;
+	}
+	pin = pin - 1;
+
+	result = acpi_prt_get_irq(dev, pin, &irq);
+	if (!irq)
+		result = -ENODEV;
+	if (0 != result) {
+		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n",
+		       'A'+pin, dev->slot_name);
+		return result;
+	}
+
+	/* only check for the IRQ */
+	if (!assign) {
+		printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", 
+		       irq, dev->slot_name);
+		return 1;
+	}
+
+	dev->irq = irq;
+
+	/* also assign an IRQ */
+	if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+		result = acpi_prt_set_irq(dev, pin, irq);
+		if (0 != result) {
+			printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name);
+			return result;
+		}
+
+		eisa_set_level_irq(irq);
+
+		printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name);
+	}
+
+	return 1;
+}
+
+static int __init pci_acpi_init(void)
+{
+	if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
+		if (acpi_prts.count) {
+			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+			printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
+			pci_use_acpi_routing = 1;
+			pci_lookup_irq = acpi_lookup_irq;
+		} else
+			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+
+	}
+	return 0;
+}
+
+arch_initcall(pci_acpi_init);
diff -Nru a/arch/i386/pci/changelog b/arch/i386/pci/changelog
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/changelog	Thu May  9 15:21:10 2002
@@ -0,0 +1,62 @@
+/*
+ * CHANGELOG :
+ * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
+ *	Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
+ *
+ * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
+ *     Potter, potter@cao-vlsi.ibp.fr
+ *
+ * Jan 10, 1995 : Modified to store the information about configured pci
+ *      devices into a list, which can be accessed via /proc/pci by
+ *      Curtis Varner, cvarner@cs.ucr.edu
+ *
+ * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
+ *	Alpha version. Intel & UMC chipset support only.
+ *
+ * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
+ *	moved to drivers/pci/pci.c.
+ *
+ * Dec 7, 1996  : Added support for direct configuration access of boards
+ *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
+ *
+ * Feb 3, 1997  : Set internal functions to static, save/restore flags
+ *	avoid dead locks reading broken PCI BIOS, werner@suse.de 
+ *
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ *	(mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7,  1997 : Added some missing cli()'s. [mj]
+ * 
+ * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
+ *      (paubert@iram.es)
+ *
+ * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
+ *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
+ *
+ * May 1,  1998 : Support for peer host bridges. [mj]
+ *
+ * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
+ *	can be accessed from interrupts even on SMP systems. [mj]
+ *
+ * August  1998 : Better support for peer host bridges and more paranoid
+ *	checks for direct hardware access. Ugh, this file starts to look as
+ *	a large gallery of common hardware bug workarounds (watch the comments)
+ *	-- the PCI specs themselves are sane, but most implementors should be
+ *	hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
+ *
+ * August  1999 : New resource management and configuration access stuff. [mj]
+ *
+ * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
+ *		  Based on ideas by Chris Frantz and David Hinds. [mj]
+ *
+ * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
+ *		  for a lot of patience during testing. [mj]
+ *
+ * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
+ */
\ No newline at end of file
diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/common.c	Thu May  9 15:21:06 2002
@@ -0,0 +1,206 @@
+/*
+ *	Low-Level PCI Support for PC
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "pci.h"
+
+#ifdef CONFIG_PCI_BIOS
+extern  void pcibios_sort(void);
+#endif
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus = NULL;
+struct pci_ops *pci_root_ops = NULL;
+
+int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
+int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Several buggy motherboards address only 16 devices and mirror
+ * them to next 16 IDs. We try to detect this `feature' on all
+ * primary buses (those containing host bridges as they are
+ * expected to be unique) and remove the ghost devices.
+ */
+
+static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
+{
+	struct list_head *ln, *mn;
+	struct pci_dev *d, *e;
+	int mirror = PCI_DEVFN(16,0);
+	int seen_host_bridge = 0;
+	int i;
+
+	DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
+	for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+		d = pci_dev_b(ln);
+		if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+			seen_host_bridge++;
+		for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+			e = pci_dev_b(mn);
+			if (e->devfn != d->devfn + mirror ||
+			    e->vendor != d->vendor ||
+			    e->device != d->device ||
+			    e->class != d->class)
+				continue;
+			for(i=0; i<PCI_NUM_RESOURCES; i++)
+				if (e->resource[i].start != d->resource[i].start ||
+				    e->resource[i].end != d->resource[i].end ||
+				    e->resource[i].flags != d->resource[i].flags)
+					continue;
+			break;
+		}
+		if (mn == &b->devices)
+			return;
+	}
+	if (!seen_host_bridge)
+		return;
+	printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
+
+	ln = &b->devices;
+	while (ln->next != &b->devices) {
+		d = pci_dev_b(ln->next);
+		if (d->devfn >= mirror) {
+			list_del(&d->global_list);
+			list_del(&d->bus_list);
+			kfree(d);
+		} else
+			ln = ln->next;
+	}
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __devinit  pcibios_fixup_bus(struct pci_bus *b)
+{
+	pcibios_fixup_ghosts(b);
+	pci_read_bridge_bases(b);
+}
+
+
+struct pci_bus * __devinit pcibios_scan_root(int busnum)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		if (bus->number == busnum) {
+			/* Already scanned */
+			return bus;
+		}
+	}
+
+	printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
+
+	return pci_scan_bus(busnum, pci_root_ops, NULL);
+}
+
+static int __init pcibios_init(void)
+{
+	if (!pci_root_ops) {
+		printk("PCI: System does not support PCI\n");
+		return 0;
+	}
+
+	pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+		pcibios_sort();
+#endif
+	return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+char * __devinit  pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+#ifdef CONFIG_PCI_BIOS
+	else if (!strcmp(str, "bios")) {
+		pci_probe = PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nobios")) {
+		pci_probe &= ~PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nosort")) {
+		pci_probe |= PCI_NO_SORT;
+		return NULL;
+	} else if (!strcmp(str, "biosirq")) {
+		pci_probe |= PCI_BIOS_IRQ_SCAN;
+		return NULL;
+	}
+#endif
+#ifdef CONFIG_PCI_DIRECT
+	else if (!strcmp(str, "conf1")) {
+		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+		return NULL;
+	}
+	else if (!strcmp(str, "conf2")) {
+		pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
+		return NULL;
+	}
+#endif
+#ifdef CONFIG_ACPI_PCI
+	else if (!strcmp(str, "noacpi")) {
+		pci_probe |= PCI_NO_ACPI_ROUTING;
+		return NULL;
+	}
+#endif
+	else if (!strcmp(str, "rom")) {
+		pci_probe |= PCI_ASSIGN_ROMS;
+		return NULL;
+	} else if (!strcmp(str, "assign-busses")) {
+		pci_probe |= PCI_ASSIGN_ALL_BUSSES;
+		return NULL;
+	} else if (!strcmp(str, "usepirqmask")) {
+		pci_probe |= PCI_USE_PIRQ_MASK;
+		return NULL;
+	} else if (!strncmp(str, "irqmask=", 8)) {
+		pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
+		return NULL;
+	} else if (!strncmp(str, "lastbus=", 8)) {
+		pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+		return NULL;
+	}
+	return str;
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	int err;
+
+	if ((err = pcibios_enable_resources(dev)) < 0)
+		return err;
+	pcibios_enable_irq(dev);
+	return 0;
+}
diff -Nru a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/direct.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,366 @@
+/*
+ * direct.c - Low-level direct PCI config space access
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
+
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
+
+	switch (len) {
+	case 1:
+		*value = inb(0xCFC + (reg & 3));
+		break;
+	case 2:
+		*value = inw(0xCFC + (reg & 2));
+		break;
+	case 4:
+		*value = inl(0xCFC);
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
+
+	switch (len) {
+	case 1:
+		outb((u8)value, 0xCFC + (reg & 3));
+		break;
+	case 2:
+		outw((u16)value, 0xCFC + (reg & 2));
+		break;
+	case 4:
+		outl((u32)value, 0xCFC);
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+
+#undef PCI_CONF1_ADDRESS
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	int result; 
+	u32 data;
+
+	if (!value) 
+		return -EINVAL;
+
+	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, &data);
+
+	*value = (u8)data;
+
+	return result;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	int result; 
+	u32 data;
+
+	if (!value) 
+		return -EINVAL;
+
+	result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, &data);
+
+	*value = (u16)data;
+
+	return result;
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	if (!value) 
+		return -EINVAL;
+
+	return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_conf1 = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define PCI_CONF2_ADDRESS(dev, reg)	(u16)(0xC000 | (dev << 8) | reg)
+
+static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
+
+	if (dev & 0x10) 
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
+	outb((u8)bus, 0xCFA);
+
+	switch (len) {
+	case 1:
+		*value = inb(PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	case 2:
+		*value = inw(PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	case 4:
+		*value = inl(PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	}
+
+	outb (0, 0xCF8);
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+		return -EINVAL;
+
+	if (dev & 0x10) 
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outb((u8)(0xF0 | (fn << 1)), 0xCF8);
+	outb((u8)bus, 0xCFA);
+
+	switch (len) {
+	case 1:
+		outb ((u8)value, PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	case 2:
+		outw ((u16)value, PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	case 4:
+		outl ((u32)value, PCI_CONF2_ADDRESS(dev, reg));
+		break;
+	}
+
+	outb (0, 0xCF8);    
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+#undef PCI_CONF2_ADDRESS
+
+static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	int result; 
+	u32 data;
+	result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, &data);
+	*value = (u8)data;
+	return result;
+}
+
+static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	int result; 
+	u32 data;
+	result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, &data);
+	*value = (u16)data;
+	return result;
+}
+
+static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_conf2 = {
+	pci_conf2_read_config_byte,
+	pci_conf2_read_config_word,
+	pci_conf2_read_config_dword,
+	pci_conf2_write_config_byte,
+	pci_conf2_write_config_word,
+	pci_conf2_write_config_dword
+};
+
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int __devinit pci_sanity_check(struct pci_ops *o)
+{
+	u16 x;
+	struct pci_bus bus;		/* Fake bus and device */
+	struct pci_dev dev;
+
+	if (pci_probe & PCI_NO_CHECKS)
+		return 1;
+	bus.number = 0;
+	dev.bus = &bus;
+	for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
+		if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
+		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+		    (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
+		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
+			return 1;
+	DBG("PCI: Sanity check failed\n");
+	return 0;
+}
+
+static struct pci_ops * __devinit pci_check_direct(void)
+{
+	unsigned int tmp;
+	unsigned long flags;
+
+	__save_flags(flags); __cli();
+
+	/*
+	 * Check if configuration type 1 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF1) {
+		outb (0x01, 0xCFB);
+		tmp = inl (0xCF8);
+		outl (0x80000000, 0xCF8);
+		if (inl (0xCF8) == 0x80000000 &&
+		    pci_sanity_check(&pci_direct_conf1)) {
+			outl (tmp, 0xCF8);
+			__restore_flags(flags);
+			printk(KERN_INFO "PCI: Using configuration type 1\n");
+			if (!request_region(0xCF8, 8, "PCI conf1"))
+				return NULL;
+			return &pci_direct_conf1;
+		}
+		outl (tmp, 0xCF8);
+	}
+
+	/*
+	 * Check if configuration type 2 works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF2) {
+		outb (0x00, 0xCFB);
+		outb (0x00, 0xCF8);
+		outb (0x00, 0xCFA);
+		if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
+		    pci_sanity_check(&pci_direct_conf2)) {
+			__restore_flags(flags);
+			printk(KERN_INFO "PCI: Using configuration type 2\n");
+			if (!request_region(0xCF8, 4, "PCI conf2"))
+				return NULL;
+			return &pci_direct_conf2;
+		}
+	}
+
+	__restore_flags(flags);
+	return NULL;
+}
+
+static int __init pci_direct_init(void)
+{
+	if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
+		&& (pci_root_ops = pci_check_direct())) {
+		if (pci_root_ops == &pci_direct_conf1) {
+			pci_config_read = pci_conf1_read;
+			pci_config_write = pci_conf1_write;
+		}
+		else {
+			pci_config_read = pci_conf2_read;
+			pci_config_write = pci_conf2_write;
+		}
+	}
+	return 0;
+}
+
+arch_initcall(pci_direct_init);
diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/fixup.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,183 @@
+/*
+ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+{
+	/*
+	 * i450NX -- Find and scan all secondary buses on all PXB's.
+	 */
+	int pxb, reg;
+	u8 busno, suba, subb;
+
+	printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
+	reg = 0xd0;
+	for(pxb=0; pxb<2; pxb++) {
+		pci_read_config_byte(d, reg++, &busno);
+		pci_read_config_byte(d, reg++, &suba);
+		pci_read_config_byte(d, reg++, &subb);
+		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+		if (busno)
+			pci_scan_bus(busno, pci_root_ops, NULL);	/* Bus A */
+		if (suba < subb)
+			pci_scan_bus(suba+1, pci_root_ops, NULL);	/* Bus B */
+	}
+	pcibios_last_bus = -1;
+}
+
+static void __devinit pci_fixup_i450gx(struct pci_dev *d)
+{
+	/*
+	 * i450GX and i450KX -- Find and scan all secondary buses.
+	 * (called separately for each PCI bridge found)
+	 */
+	u8 busno;
+	pci_read_config_byte(d, 0x4a, &busno);
+	printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+	pci_scan_bus(busno, pci_root_ops, NULL);
+	pcibios_last_bus = -1;
+}
+
+static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
+{
+	/*
+	 * UM8886BF IDE controller sets region type bits incorrectly,
+	 * therefore they look like memory despite of them being I/O.
+	 */
+	int i;
+
+	printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
+	for(i=0; i<4; i++)
+		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+}
+
+static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
+{
+	/*
+	 * NCR 53C810 returns class code 0 (at least on some systems).
+	 * Fix class to be PCI_CLASS_STORAGE_SCSI
+	 */
+	if (!d->class) {
+		printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", d->slot_name);
+		d->class = PCI_CLASS_STORAGE_SCSI << 8;
+	}
+}
+
+static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+static void __devinit  pci_fixup_ide_trash(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * There exist PCI IDE controllers which have utter garbage
+	 * in first four base registers. Ignore that.
+	 */
+	DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name);
+	for(i=0; i<4; i++)
+		d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
+}
+
+static void __devinit  pci_fixup_latency(struct pci_dev *d)
+{
+	/*
+	 *  SiS 5597 and 5598 chipsets require latency timer set to
+	 *  at most 32 to avoid lockups.
+	 */
+	DBG("PCI: Setting max latency to 32\n");
+	pcibios_max_latency = 32;
+}
+
+static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
+{
+	/*
+	 * PIIX4 ACPI device: hardwired IRQ9
+	 */
+	d->irq = 9;
+}
+
+/*
+ * Addresses issues with problems in the memory write queue timer in
+ * certain VIA Northbridges.  This bugfix is per VIA's specifications,
+ * except for the KL133/KM133: clearing bit 5 on those Northbridges seems
+ * to trigger a bug in its integrated ProSavage video card, which
+ * causes screen corruption.  We only clear bits 6 and 7 for that chipset,
+ * until VIA can provide us with definitive information on why screen
+ * corruption occurs, and what exactly those bits do.
+ *
+ * VIA 8363,8622,8361 Northbridges:
+ *  - bits  5, 6, 7 at offset 0x55 need to be turned off
+ * VIA 8367 (KT266x) Northbridges:
+ *  - bits  5, 6, 7 at offset 0x95 need to be turned off
+ * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges:
+ *  - bits     6, 7 at offset 0x55 need to be turned off
+ */
+
+#define VIA_8363_KL133_REVISION_ID 0x81
+#define VIA_8363_KM133_REVISION_ID 0x84
+
+static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
+{
+	u8 v;
+	u8 revision;
+	int where = 0x55;
+	int mask = 0x1f; /* clear bits 5, 6, 7 by default */
+
+	pci_read_config_byte(d, PCI_REVISION_ID, &revision);
+
+	if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
+  	        where = 0x95; /* the memory write queue timer register is 
+				different for the KT266x's: 0x95 not 0x55 */
+	} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
+			(revision == VIA_8363_KL133_REVISION_ID || 
+			revision == VIA_8363_KM133_REVISION_ID)) {
+			mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5
+					causes screen corruption on the KL133/KM133 */
+	}
+
+        pci_read_config_byte(d, where, &v);
+	if (v & ~mask) {
+		printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
+			d->device, revision, where, v, mask, v & mask);
+		v &= mask;
+		pci_write_config_byte(d, where, v);
+	}
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5513,		pci_fixup_ide_trash },
+	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8622,	        pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
+	{ 0 }
+};
diff -Nru a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/i386.c	Thu May  9 15:21:04 2002
@@ -0,0 +1,324 @@
+/*
+ *	Low-Level PCI Access for i386 machines
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing
+ *      (Unix and Linux consulting and custom programming)
+ *      Drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * Drew's work was sponsored by:
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+#include "pci.h"
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		new |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+	
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
+{
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *	- I/O or memory regions not configured
+ *	- regions configured, but not enabled in the command register
+ *	- bogus I/O addresses above 64K used
+ *	- expansion ROMs left enabled (this may sound harmless, but given
+ *	  the fact the PCI specs explicitly allow address decoders to be
+ *	  shared between expansion ROMs and other resource regions, it's
+ *	  at least dangerous)
+ *
+ *  Our solution:
+ *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *	    This gives us fixed barriers on where we can allocate.
+ *	(2) Allocate resources for all enabled devices.  If there is
+ *	    a collision, just mark the resource as unallocated. Also
+ *	    disable expansion ROMs during this step.
+ *	(3) Try to allocate resources for disabled devices.  If the
+ *	    resources were assigned correctly, everything goes well,
+ *	    if they weren't, they won't disturb allocation of other
+ *	    resources.
+ *	(4) Assign new addresses to resources which were either
+ *	    not configured at all or misconfigured.  If explicitly
+ *	    requested by the user, configure expansion ROM address
+ *	    as well.
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r, *pr;
+
+	/* Depth-First Search on bus tree */
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		if ((dev = bus->self)) {
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+				r = &dev->resource[idx];
+				if (!r->start)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+		}
+		pcibios_allocate_bus_resources(&bus->children);
+	}
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	pci_for_each_dev(dev) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				    r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0) {
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+					/* We'll assign a new address later */
+					r->end -= r->start;
+					r->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
+				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static void __init pcibios_assign_resources(void)
+{
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r;
+
+	pci_for_each_dev(dev) {
+		int class = dev->class >> 8;
+
+		/* Don't touch classless devices and host bridges */
+		if (!class || class == PCI_CLASS_BRIDGE_HOST)
+			continue;
+
+		for(idx=0; idx<6; idx++) {
+			r = &dev->resource[idx];
+
+			/*
+			 *  Don't touch IDE controllers and I/O ports of video cards!
+			 */
+			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+				continue;
+
+			/*
+			 *  We shall assign a new address to this resource, either because
+			 *  the BIOS forgot to do so or because we have decided the old
+			 *  address was unusable for some reason.
+			 */
+			if (!r->start && r->end)
+				pci_assign_resource(dev, idx);
+		}
+
+		if (pci_probe & PCI_ASSIGN_ROMS) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			r->end -= r->start;
+			r->start = 0;
+			if (r->end)
+				pci_assign_resource(dev, PCI_ROM_RESOURCE);
+		}
+	}
+}
+
+void __init pcibios_resource_survey(void)
+{
+	DBG("PCI: Allocating resources\n");
+	pcibios_allocate_bus_resources(&pci_root_buses);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+	pcibios_assign_resources();
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	unsigned long prot;
+
+	/* I/O space cannot be accessed via normal processor loads and
+	 * stores on this platform.
+	 */
+	if (mmap_state == pci_mmap_io)
+		return -EINVAL;
+
+	/* Leave vm_pgoff as-is, the PCI space address is the physical
+	 * address on this platform.
+	 */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+	prot = pgprot_val(vma->vm_page_prot);
+	if (boot_cpu_data.x86 > 3)
+		prot |= _PAGE_PCD | _PAGE_PWT;
+	vma->vm_page_prot = __pgprot(prot);
+
+	/* Write-combine setting is ignored, it is changed via the mtrr
+	 * interfaces on this platform.
+	 */
+	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
diff -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/irq.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,812 @@
+/*
+ *	Low-Level PCI Support for PC -- Routing of Interrupts
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/io_apic.h>
+
+#include "pci.h"
+
+#define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+int pci_use_acpi_routing = 0;
+int broken_hp_bios_irq9;
+
+static struct irq_routing_table *pirq_table;
+
+/*
+ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
+ * Avoid using: 13, 14 and 15 (FP error and IDE).
+ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
+ */
+unsigned int pcibios_irq_mask = 0xfff8;
+
+static int pirq_penalty[16] = {
+	1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
+	0, 0, 0, 0, 1000, 100000, 100000, 100000
+};
+
+struct irq_router {
+	char *name;
+	u16 vendor, device;
+	int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
+	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
+};
+
+int (*pci_lookup_irq)(struct pci_dev * dev, int assign) = NULL;
+
+/*
+ *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
+ */
+
+static struct irq_routing_table * __init pirq_find_routing_table(void)
+{
+	u8 *addr;
+	struct irq_routing_table *rt;
+	int i;
+	u8 sum;
+
+	for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
+		rt = (struct irq_routing_table *) addr;
+		if (rt->signature != PIRQ_SIGNATURE ||
+		    rt->version != PIRQ_VERSION ||
+		    rt->size % 16 ||
+		    rt->size < sizeof(struct irq_routing_table))
+			continue;
+		sum = 0;
+		for(i=0; i<rt->size; i++)
+			sum += addr[i];
+		if (!sum) {
+			DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+			return rt;
+		}
+	}
+	return NULL;
+}
+
+/*
+ *  If we have a IRQ routing table, use it to search for peer host
+ *  bridges.  It's a gross hack, but since there are no other known
+ *  ways how to get a list of buses, we have to go this way.
+ */
+
+static void __init pirq_peer_trick(void)
+{
+	struct irq_routing_table *rt = pirq_table;
+	u8 busmap[256];
+	int i;
+	struct irq_info *e;
+
+	memset(busmap, 0, sizeof(busmap));
+	for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
+		e = &rt->slots[i];
+#ifdef DEBUG
+		{
+			int j;
+			DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
+			for(j=0; j<4; j++)
+				DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
+			DBG("\n");
+		}
+#endif
+		busmap[e->bus] = 1;
+	}
+	for(i=1; i<256; i++)
+		/*
+		 *  It might be a secondary bus, but in this case its parent is already
+		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
+		 */
+		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
+			printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
+	pcibios_last_bus = -1;
+}
+
+/*
+ *  Code for querying and setting of IRQ routes on various interrupt routers.
+ */
+
+void eisa_set_level_irq(unsigned int irq)
+{
+	unsigned char mask = 1 << (irq & 7);
+	unsigned int port = 0x4d0 + (irq >> 3);
+	unsigned char val = inb(port);
+
+	if (!(val & mask)) {
+		DBG(" -> edge");
+		outb(val | mask, port);
+	}
+}
+
+/*
+ * Common IRQ routing practice: nybbles in config space,
+ * offset by some magic constant.
+ */
+static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
+{
+	u8 x;
+	unsigned reg = offset + (nr >> 1);
+
+	pci_read_config_byte(router, reg, &x);
+	return (nr & 1) ? (x >> 4) : (x & 0xf);
+}
+
+static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
+{
+	u8 x;
+	unsigned reg = offset + (nr >> 1);
+
+	pci_read_config_byte(router, reg, &x);
+	x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
+	pci_write_config_byte(router, reg, x);
+}
+
+/*
+ * ALI pirq entries are damn ugly, and completely undocumented.
+ * This has been figured out from pirq tables, and it's not a pretty
+ * picture.
+ */
+static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+
+	return irqmap[read_config_nybble(router, 0x48, pirq-1)];
+}
+
+static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+	unsigned int val = irqmap[irq];
+		
+	if (val) {
+		write_config_nybble(router, 0x48, pirq-1, val);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
+ * just a pointer to the config space.
+ */
+static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+
+	pci_read_config_byte(router, pirq, &x);
+	return (x < 16) ? x : 0;
+}
+
+static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	pci_write_config_byte(router, pirq, irq);
+	return 1;
+}
+
+/*
+ * The VIA pirq rules are nibble-based, like ALI,
+ * but without the ugly irq number munging.
+ */
+static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0x55, pirq);
+}
+
+static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0x55, pirq, irq);
+	return 1;
+}
+
+/*
+ * ITE 8330G pirq rules are nibble-based
+ * FIXME: pirqmap may be { 1, 0, 3, 2 },
+ * 	  2+3 are both mapped to irq 9 on my system
+ */
+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+}
+
+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
+	return 1;
+}
+
+/*
+ * OPTI: high four bits are nibble pointer..
+ * I wonder what the low bits do?
+ */
+static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0xb8, pirq >> 4);
+}
+
+static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0xb8, pirq >> 4, irq);
+	return 1;
+}
+
+/*
+ * Cyrix: nibble offset 0x5C
+ * 0x5C bits 7:4 is INTB bits 3:0 is INTA 
+ * 0x5D bits 7:4 is INTD bits 3:0 is INTC
+ */
+static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	return read_config_nybble(router, 0x5C, (pirq-1)^1);
+}
+
+static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
+	return 1;
+}
+
+/*
+ *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
+ *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
+ *	the related registers work as follows:
+ *	
+ *	general: one byte per re-routable IRQ,
+ *		 bit 7      IRQ mapping enabled (0) or disabled (1)
+ *		 bits [6:4] reserved
+ *		 bits [3:0] IRQ to map to
+ *		     allowed: 3-7, 9-12, 14-15
+ *		     reserved: 0, 1, 2, 8, 13
+ *
+ *	individual registers in device config space:
+ *
+ *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
+ *
+ *	0x61:			IDEIRQ: bits as in general case - but:
+ *				bits [6:5] must be written 01
+ *				bit 4 channel-select primary (0), secondary (1)
+ *
+ *	0x62:			USBIRQ: bits as in general case - but:
+ *				bit 4 OHCI function disabled (0), enabled (1)
+ *	
+ *	0x6a:			ACPI/SCI IRQ - bits as in general case
+ *
+ *	0x7e:			Data Acq. Module IRQ - bits as in general case
+ *
+ *	Apparently there are systems implementing PCI routing table using both
+ *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
+ *	like 0x62 as link values for USBIRQ e.g. So there is no simple
+ *	"register = offset + pirq" relation.
+ *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
+ *	both link mappings.
+ *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
+ */
+
+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+	int reg = pirq;
+
+	switch(pirq) {
+		case 0x01:
+		case 0x02:
+		case 0x03:
+		case 0x04:
+			reg += 0x40;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x44:
+		case 0x62:
+			pci_read_config_byte(router, reg, &x);
+			if (reg != 0x62)
+				break;
+			if (!(x & 0x40))
+				return 0;
+			break;
+		case 0x61:
+		case 0x6a:
+		case 0x7e:
+			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
+			return 0;
+		default:			
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+			return 0;
+	}
+	return (x & 0x80) ? 0 : (x & 0x0f);
+}
+
+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg = pirq;
+
+	switch(pirq) {
+		case 0x01:
+		case 0x02:
+		case 0x03:
+		case 0x04:
+			reg += 0x40;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x44:
+		case 0x62:
+			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
+			if (reg != 0x62)
+				break;
+			/* always mark OHCI enabled, as nothing else knows about this */
+			x |= 0x40;
+			break;
+		case 0x61:
+		case 0x6a:
+		case 0x7e:
+			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
+			return 0;
+		default:			
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+			return 0;
+	}
+	pci_write_config_byte(router, reg, x);
+
+	return 1;
+}
+
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ *       for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	if (pirq > 8) {
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+		return 0;
+	}
+	return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	if (pirq > 8) {
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+		return 0;
+	}
+	write_config_nybble(router, 0x74, pirq-1, irq);
+	return 1;
+}
+
+/*
+ * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
+ * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
+ * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
+ * register is a straight binary coding of desired PIC IRQ (low nibble).
+ *
+ * The 'link' value in the PIRQ table is already in the correct format
+ * for the Index register.  There are some special index values:
+ * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
+ * and 0x03 for SMBus.
+ */
+static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	outb_p(pirq, 0xc00);
+	return inb(0xc01) & 0xf;
+}
+
+static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	outb_p(pirq, 0xc00);
+	outb_p(irq, 0xc01);
+	return 1;
+}
+
+/* Support for AMD756 PCI IRQ Routing
+ * Jhon H. Caicedo <jhcaiced@osso.org.co>
+ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
+ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
+ * The AMD756 pirq rules are nibble-based
+ * offset 0x56 0-3 PIRQA  4-7  PIRQB
+ * offset 0x57 0-3 PIRQC  4-7  PIRQD
+ */
+static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 irq;
+	irq = 0;
+	if (pirq <= 4)
+	{
+		irq = read_config_nybble(router, 0x56, pirq - 1);
+	}
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
+		dev->vendor, dev->device, pirq, irq);
+	return irq;
+}
+
+static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
+		dev->vendor, dev->device, pirq, irq);
+	if (pirq <= 4)
+	{
+		write_config_nybble(router, 0x56, pirq - 1, irq);
+	}
+	return 1;
+}
+
+#ifdef CONFIG_PCI_BIOS
+
+static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	struct pci_dev *bridge;
+	int pin = pci_get_interrupt_pin(dev, &bridge);
+	return pcibios_set_irq_routing(bridge, pin, irq);
+}
+
+static struct irq_router pirq_bios_router =
+	{ "BIOS", 0, 0, NULL, pirq_bios_set };
+
+#endif
+
+static struct irq_router pirq_routers[] = {
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
+
+	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
+
+	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
+
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
+	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
+
+	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
+
+	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
+	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
+	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
+	  pirq_serverworks_get, pirq_serverworks_set },
+	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
+	  pirq_serverworks_get, pirq_serverworks_set },
+	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
+		pirq_amd756_get, pirq_amd756_set },
+
+	{ "default", 0, 0, NULL, NULL }
+};
+
+static struct irq_router *pirq_router;
+static struct pci_dev *pirq_router_dev;
+
+static void __init pirq_find_router(void)
+{
+	struct irq_routing_table *rt = pirq_table;
+	struct irq_router *r;
+
+#ifdef CONFIG_PCI_BIOS
+	if (!rt->signature) {
+		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
+		pirq_router = &pirq_bios_router;
+		return;
+	}
+#endif
+
+	DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
+	    rt->rtr_vendor, rt->rtr_device);
+
+	/* fall back to default router if nothing else found */
+	pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
+
+	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
+	if (!pirq_router_dev) {
+		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
+		return;
+	}
+
+	for(r=pirq_routers; r->vendor; r++) {
+		/* Exact match against router table entry? Use it! */
+		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
+			pirq_router = r;
+			break;
+		}
+		/* Match against router device entry? Use it as a fallback */
+		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
+			pirq_router = r;
+		}
+	}
+	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
+		pirq_router->name,
+		pirq_router_dev->vendor,
+		pirq_router_dev->device,
+		pirq_router_dev->slot_name);
+}
+
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
+{
+	struct irq_routing_table *rt = pirq_table;
+	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	struct irq_info *info;
+
+	for (info = rt->slots; entries--; info++)
+		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
+			return info;
+	return NULL;
+}
+
+static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+{
+	u8 pin;
+	struct irq_info *info;
+	int i, pirq, newirq;
+	int irq = 0;
+	u32 mask;
+	struct irq_router *r = pirq_router;
+	struct pci_dev *dev2;
+	char *msg = NULL;
+
+	/* Find IRQ pin */
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin) {
+		DBG(" -> no interrupt pin\n");
+		return 0;
+	}
+	pin = pin - 1;
+
+	/* Find IRQ routing entry */
+
+	if (!pirq_table)
+		return 0;
+	
+	DBG("IRQ for %s:%d", dev->slot_name, pin);
+	info = pirq_get_info(dev);
+	if (!info) {
+		DBG(" -> not found in routing table\n");
+		return 0;
+	}
+	pirq = info->irq[pin].link;
+	mask = info->irq[pin].bitmap;
+	if (!pirq) {
+		DBG(" -> not routed\n");
+		return 0;
+	}
+	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
+	mask &= pcibios_irq_mask;
+
+	/* Work around broken HP Pavilion Notebooks which assign USB to
+	   IRQ 9 even though it is actually wired to IRQ 11 */
+
+	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+		r->set(pirq_router_dev, dev, pirq, 11);
+	}
+
+	/*
+	 * Find the best IRQ to assign: use the one
+	 * reported by the device if possible.
+	 */
+	newirq = dev->irq;
+	if (!((1 << newirq) & mask)) {
+		if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
+		else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
+	}
+	if (!newirq && assign) {
+		for (i = 0; i < 16; i++) {
+			if (!(mask & (1 << i)))
+				continue;
+			if (pirq_penalty[i] < pirq_penalty[newirq] &&
+			    !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
+				free_irq(i, dev);
+				newirq = i;
+			}
+		}
+	}
+	DBG(" -> newirq=%d", newirq);
+
+	/* Check if it is hardcoded */
+	if ((pirq & 0xf0) == 0xf0) {
+		irq = pirq & 0xf;
+		DBG(" -> hardcoded IRQ %d\n", irq);
+		msg = "Hardcoded";
+	} else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
+	((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
+		DBG(" -> got IRQ %d\n", irq);
+		msg = "Found";
+	} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+		DBG(" -> assigning IRQ %d", newirq);
+		if (r->set(pirq_router_dev, dev, pirq, newirq)) {
+			eisa_set_level_irq(newirq);
+			DBG(" ... OK\n");
+			msg = "Assigned";
+			irq = newirq;
+		}
+	}
+
+	if (!irq) {
+		DBG(" ... failed\n");
+		if (newirq && mask == (1 << newirq)) {
+			msg = "Guessed";
+			irq = newirq;
+		} else
+			return 0;
+	}
+	printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
+
+	/* Update IRQ for all devices with the same pirq value */
+	pci_for_each_dev(dev2) {
+		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+		if (!pin)
+			continue;
+		pin--;
+		info = pirq_get_info(dev2);
+		if (!info)
+			continue;
+		if (info->irq[pin].link == pirq) {
+			/* We refuse to override the dev->irq information. Give a warning! */
+		    	if ( dev2->irq && dev2->irq != irq && \
+			(!(pci_probe & PCI_USE_PIRQ_MASK) || \
+			((1 << dev2->irq) & mask)) ) {
+		    		printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+				       dev2->slot_name, dev2->irq, irq);
+		    		continue;
+		    	}
+			dev2->irq = irq;
+			pirq_penalty[irq]++;
+			if (dev != dev2)
+				printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
+		}
+	}
+	return 1;
+}
+
+static int __init pcibios_irq_init(void)
+{
+	DBG("PCI: IRQ init\n");
+
+	if (pci_lookup_irq)
+		return 0;
+
+	pirq_table = pirq_find_routing_table();
+
+#ifdef CONFIG_PCI_BIOS
+	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+		pirq_table = pcibios_get_irq_routing_table();
+#endif
+	if (pirq_table) {
+		pirq_peer_trick();
+		pirq_find_router();
+		if (pirq_table->exclusive_irqs) {
+			int i;
+			for (i=0; i<16; i++)
+				if (!(pirq_table->exclusive_irqs & (1 << i)))
+					pirq_penalty[i] += 100;
+		}
+		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
+		if (io_apic_assign_pci_irqs)
+			pirq_table = NULL;
+	}
+	pci_lookup_irq = pcibios_lookup_irq;
+	pcibios_fixup_irqs();
+	return 0;
+}
+
+subsys_initcall(pcibios_irq_init);
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev;
+	u8 pin;
+
+	DBG("PCI: IRQ fixup\n");
+	pci_for_each_dev(dev) {
+		/*
+		 * If the BIOS has set an out of range IRQ number, just ignore it.
+		 * Also keep track of which IRQ's are already in use.
+		 */
+		if (dev->irq >= 16) {
+			DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
+			dev->irq = 0;
+		}
+		/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
+		if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
+			pirq_penalty[dev->irq] = 0;
+		pirq_penalty[dev->irq]++;
+	}
+
+	pci_for_each_dev(dev) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+#ifdef CONFIG_X86_IO_APIC
+		/*
+		 * Recalculate IRQ numbers if we use the I/O APIC.
+		 */
+		if (io_apic_assign_pci_irqs)
+		{
+			int irq;
+
+			if (pin) {
+				pin--;		/* interrupt pins are numbered starting from 1 */
+				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+	/*
+	 * Busses behind bridges are typically not listed in the MP-table.
+	 * In this case we have to look up the IRQ based on the parent bus,
+	 * parent slot, and pin number. The SMP code detects such bridged
+	 * busses itself so we should get into this branch reliably.
+	 */
+				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+					struct pci_dev * bridge = dev->bus->self;
+
+					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+							PCI_SLOT(bridge->devfn), pin);
+					if (irq >= 0)
+						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+				}
+				if (irq >= 0) {
+					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+					dev->irq = irq;
+				}
+			}
+		}
+#endif
+		/*
+		 * Still no IRQ? Try to lookup one...
+		 */
+		if (pin && !dev->irq)
+			pci_lookup_irq(dev, 0);
+	}
+}
+
+void pcibios_penalize_isa_irq(int irq)
+{
+	/*
+	 *  If any ISAPnP device reports an IRQ in its list of possible
+	 *  IRQ's, we try to avoid assigning it to PCI devices.
+	 */
+	pirq_penalty[irq] += 100;
+}
+
+void pcibios_enable_irq(struct pci_dev *dev)
+{
+	u8 pin;
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (pin && !pci_lookup_irq(dev, 1) && !dev->irq) {
+		char *msg;
+		if (io_apic_assign_pci_irqs)
+			msg = " Probably buggy MP table.";
+		else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+			msg = "";
+		else
+			msg = " Please try using pci=biosirq.";
+		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+		       'A' + pin - 1, dev->slot_name, msg);
+	}
+}
diff -Nru a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/legacy.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,53 @@
+/*
+ * legacy.c - traditional, old school PCI bus probing
+ */
+#include <linux/pci.h>
+#include "pci.h"
+
+/*
+ * Discover remaining PCI buses in case there are peer host bridges.
+ * We use the number of last PCI bus provided by the PCI BIOS.
+ */
+static void __devinit pcibios_fixup_peer_bridges(void)
+{
+	int n;
+	struct pci_bus bus;
+	struct pci_dev dev;
+	u16 l;
+
+	if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
+		return;
+	DBG("PCI: Peer bridge fixup\n");
+	for (n=0; n <= pcibios_last_bus; n++) {
+		if (pci_bus_exists(&pci_root_buses, n))
+			continue;
+		bus.number = n;
+		bus.ops = pci_root_ops;
+		dev.bus = &bus;
+		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+			    l != 0x0000 && l != 0xffff) {
+				DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
+				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
+				pci_scan_bus(n, pci_root_ops, NULL);
+				break;
+			}
+	}
+}
+
+static int __init pci_legacy_init(void)
+{
+	if (!pci_root_ops) {
+		printk("PCI: System does not support PCI\n");
+		return 0;
+	}
+
+	printk("PCI: Probing PCI hardware\n");
+	pci_root_bus = pcibios_scan_root(0);
+
+	if (!pci_use_acpi_routing)
+		pcibios_fixup_peer_bridges();
+	return 0;
+}
+
+subsys_initcall(pci_legacy_init);
diff -Nru a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/numa.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,119 @@
+/*
+ * numa.c - Low-level PCI access for NUMA-Q machines
+ */
+#include <linux/pci.h>
+
+#include "pci.h"
+
+#define BUS2QUAD(global) (mp_bus_id_to_node[global])
+#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
+#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+	(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
+
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+	switch (len) {
+	case 1:
+		*value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+		break;
+	case 2:
+		*value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+		break;
+	case 4:
+		*value = inl_quad(0xCFC, BUS2QUAD(bus));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+	switch (len) {
+	case 1:
+		outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+		break;
+	case 2:
+		outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+		break;
+	case 4:
+		outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+
+static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+{
+	/*
+	 * i450NX -- Find and scan all secondary buses on all PXB's.
+	 */
+	int pxb, reg;
+	u8 busno, suba, subb;
+	int quad = BUS2QUAD(d->bus->number);
+
+	printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
+	reg = 0xd0;
+	for(pxb=0; pxb<2; pxb++) {
+		pci_read_config_byte(d, reg++, &busno);
+		pci_read_config_byte(d, reg++, &suba);
+		pci_read_config_byte(d, reg++, &subb);
+		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+		if (busno)
+			pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL);	/* Bus A */
+		if (suba < subb)
+			pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL);	/* Bus B */
+	}
+	pcibios_last_bus = -1;
+}
+
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
+};
+
+static int __init pci_numa_init(void)
+{
+	int quad;
+
+	pci_config_read = pci_conf1_read;
+	pci_config_write = pci_conf1_write;
+
+	pci_root_bus = pcibios_scan_root(0);
+	if (clustered_apic_mode && (numnodes > 1)) {
+		for (quad = 1; quad < numnodes; ++quad) {
+			printk("Scanning PCI bus %d for quad %d\n", 
+				QUADLOCAL2BUS(quad,0), quad);
+			pci_scan_bus(QUADLOCAL2BUS(quad,0), 
+				pci_root_ops, NULL);
+		}
+	}
+	return 0;
+}
+
+subsys_initcall(pci_numa_init);
diff -Nru a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/pcbios.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,559 @@
+/*
+ * BIOS32 and PCI BIOS handling.
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
+#define PCIBIOS_FIND_PCI_DEVICE		0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
+#define PCIBIOS_READ_CONFIG_BYTE	0xb108
+#define PCIBIOS_READ_CONFIG_WORD	0xb109
+#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
+#define PCIBIOS_GET_ROUTING_OPTIONS	0xb10e
+#define PCIBIOS_SET_PCI_HW_INT		0xb10f
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/* PCI BIOS hardware mechanism flags */
+#define PCIBIOS_HW_TYPE1		0x01
+#define PCIBIOS_HW_TYPE2		0x02
+#define PCIBIOS_HW_TYPE1_SPEC		0x10
+#define PCIBIOS_HW_TYPE2_SPEC		0x20
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ * 	Standard BIOS 32-bit Service Directory Proposal
+ * 	Revision 0.4 May 24, 1993
+ * 	Phoenix Technologies Ltd.
+ *	Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+	struct {
+		unsigned long signature;	/* _32_ */
+		unsigned long entry;		/* 32 bit physical address */
+		unsigned char revision;		/* Revision level, 0 */
+		unsigned char length;		/* Length in paragraphs should be 01 */
+		unsigned char checksum;		/* All bytes must add up to zero */
+		unsigned char reserved[5]; 	/* Must be zero */
+	} fields;
+	char chars[16];
+};
+
+/*
+ * Physical address of the service directory.  I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} bios32_indirect = { 0, __KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
+{
+	unsigned char return_code;	/* %al */
+	unsigned long address;		/* %ebx */
+	unsigned long length;		/* %ecx */
+	unsigned long entry;		/* %edx */
+	unsigned long flags;
+
+	__save_flags(flags); __cli();
+	__asm__("lcall *(%%edi); cld"
+		: "=a" (return_code),
+		  "=b" (address),
+		  "=c" (length),
+		  "=d" (entry)
+		: "0" (service),
+		  "1" (0),
+		  "D" (&bios32_indirect));
+	__restore_flags(flags);
+
+	switch (return_code) {
+		case 0:
+			return address + entry;
+		case 0x80:	/* Not present */
+			printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
+			return 0;
+		default: /* Shouldn't happen */
+			printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
+				service, return_code);
+			return 0;
+	}
+}
+
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} pci_indirect = { 0, __KERNEL_CS };
+
+static int pci_bios_present;
+
+static int __devinit check_pcibios(void)
+{
+	u32 signature, eax, ebx, ecx;
+	u8 status, major_ver, minor_ver, hw_mech;
+	unsigned long flags, pcibios_entry;
+
+	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+		pci_indirect.address = pcibios_entry + PAGE_OFFSET;
+
+		__save_flags(flags); __cli();
+		__asm__(
+			"lcall *(%%edi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=d" (signature),
+			  "=a" (eax),
+			  "=b" (ebx),
+			  "=c" (ecx)
+			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
+			  "D" (&pci_indirect)
+			: "memory");
+		__restore_flags(flags);
+
+		status = (eax >> 8) & 0xff;
+		hw_mech = eax & 0xff;
+		major_ver = (ebx >> 8) & 0xff;
+		minor_ver = ebx & 0xff;
+		if (pcibios_last_bus < 0)
+			pcibios_last_bus = ecx & 0xff;
+		DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
+			status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
+		if (status || signature != PCI_SIGNATURE) {
+			printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
+				status, signature);
+			return 0;
+		}
+		printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
+			major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
+#ifdef CONFIG_PCI_DIRECT
+		if (!(hw_mech & PCIBIOS_HW_TYPE1))
+			pci_probe &= ~PCI_PROBE_CONF1;
+		if (!(hw_mech & PCIBIOS_HW_TYPE2))
+			pci_probe &= ~PCI_PROBE_CONF2;
+#endif
+		return 1;
+	}
+	return 0;
+}
+
+static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+					unsigned short index, unsigned char *bus, unsigned char *device_fn)
+{
+	unsigned short bx;
+	unsigned short ret;
+
+	__asm__("lcall *(%%edi); cld\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=b" (bx),
+		  "=a" (ret)
+		: "1" (PCIBIOS_FIND_PCI_DEVICE),
+		  "c" (device_id),
+		  "d" (vendor),
+		  "S" ((int) index),
+		  "D" (&pci_indirect));
+	*bus = (bx >> 8) & 0xff;
+	*device_fn = bx & 0xff;
+	return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+	unsigned long result = 0;
+	unsigned long flags;
+	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
+
+	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	switch (len) {
+	case 1:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=c" (*value),
+			  "=a" (result)
+			: "1" (PCIBIOS_READ_CONFIG_BYTE),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	case 2:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=c" (*value),
+			  "=a" (result)
+			: "1" (PCIBIOS_READ_CONFIG_WORD),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	case 4:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=c" (*value),
+			  "=a" (result)
+			: "1" (PCIBIOS_READ_CONFIG_DWORD),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return (int)((result & 0xff00) >> 8);
+}
+
+static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+	unsigned long result = 0;
+	unsigned long flags;
+	unsigned long bx = ((bus << 8) | (dev << 3) | fn);
+
+	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	switch (len) {
+	case 1:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=a" (result)
+			: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+			  "c" (value),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	case 2:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=a" (result)
+			: "0" (PCIBIOS_WRITE_CONFIG_WORD),
+			  "c" (value),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	case 4:
+		__asm__("lcall *(%%esi); cld\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:"
+			: "=a" (result)
+			: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+			  "c" (value),
+			  "b" (bx),
+			  "D" ((long)reg),
+			  "S" (&pci_indirect));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return (int)((result & 0xff00) >> 8);
+}
+
+static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	int result; 
+	u32 data;
+
+	if (!value) 
+		return -EINVAL;
+
+	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, &data);
+
+	*value = (u8)data;
+
+	return result;
+}
+
+static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	int result; 
+	u32 data;
+
+	if (!value) 
+		return -EINVAL;
+
+	result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, &data);
+
+	*value = (u16)data;
+
+	return result;
+}
+
+static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	if (!value) 
+		return -EINVAL;
+	
+	return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+		PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+
+/*
+ * Function table for BIOS32 access
+ */
+
+static struct pci_ops pci_bios_access = {
+      pci_bios_read_config_byte,
+      pci_bios_read_config_word,
+      pci_bios_read_config_dword,
+      pci_bios_write_config_byte,
+      pci_bios_write_config_word,
+      pci_bios_write_config_dword
+};
+
+/*
+ * Try to find PCI BIOS.
+ */
+
+static struct pci_ops * __devinit pci_find_bios(void)
+{
+	union bios32 *check;
+	unsigned char sum;
+	int i, length;
+
+	/*
+	 * Follow the standard procedure for locating the BIOS32 Service
+	 * directory by scanning the permissible address range from
+	 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
+	 */
+
+	for (check = (union bios32 *) __va(0xe0000);
+	     check <= (union bios32 *) __va(0xffff0);
+	     ++check) {
+		if (check->fields.signature != BIOS32_SIGNATURE)
+			continue;
+		length = check->fields.length * 16;
+		if (!length)
+			continue;
+		sum = 0;
+		for (i = 0; i < length ; ++i)
+			sum += check->chars[i];
+		if (sum != 0)
+			continue;
+		if (check->fields.revision != 0) {
+			printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
+				check->fields.revision, check);
+			continue;
+		}
+		DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+		if (check->fields.entry >= 0x100000) {
+			printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
+			return NULL;
+		} else {
+			unsigned long bios32_entry = check->fields.entry;
+			DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+			if (check_pcibios())
+				return &pci_bios_access;
+		}
+		break;	/* Hopefully more than one BIOS32 cannot happen... */
+	}
+
+	return NULL;
+}
+
+/*
+ * Sort the device list according to PCI BIOS. Nasty hack, but since some
+ * fool forgot to define the `correct' device order in the PCI BIOS specs
+ * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
+ * which used BIOS ordering, we are bound to do this...
+ */
+
+void __devinit pcibios_sort(void)
+{
+	LIST_HEAD(sorted_devices);
+	struct list_head *ln;
+	struct pci_dev *dev, *d;
+	int idx, found;
+	unsigned char bus, devfn;
+
+	DBG("PCI: Sorting device list...\n");
+	while (!list_empty(&pci_devices)) {
+		ln = pci_devices.next;
+		dev = pci_dev_g(ln);
+		idx = found = 0;
+		while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+			idx++;
+			for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
+				d = pci_dev_g(ln);
+				if (d->bus->number == bus && d->devfn == devfn) {
+					list_del(&d->global_list);
+					list_add_tail(&d->global_list, &sorted_devices);
+					if (d == dev)
+						found = 1;
+					break;
+				}
+			}
+			if (ln == &pci_devices) {
+				printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+				/*
+				 * We must not continue scanning as several buggy BIOSes
+				 * return garbage after the last device. Grr.
+				 */
+				break;
+			}
+		}
+		if (!found) {
+			printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
+				dev->bus->number, dev->devfn);
+			list_del(&dev->global_list);
+			list_add_tail(&dev->global_list, &sorted_devices);
+		}
+	}
+	list_splice(&sorted_devices, &pci_devices);
+}
+
+/*
+ *  BIOS Functions for IRQ Routing
+ */
+
+struct irq_routing_options {
+	u16 size;
+	struct irq_info *table;
+	u16 segment;
+} __attribute__((packed));
+
+struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
+{
+	struct irq_routing_options opt;
+	struct irq_routing_table *rt = NULL;
+	int ret, map;
+	unsigned long page;
+
+	if (!pci_bios_present)
+		return NULL;
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return NULL;
+	opt.table = (struct irq_info *) page;
+	opt.size = PAGE_SIZE;
+	opt.segment = __KERNEL_DS;
+
+	DBG("PCI: Fetching IRQ routing table... ");
+	__asm__("push %%es\n\t"
+		"push %%ds\n\t"
+		"pop  %%es\n\t"
+		"lcall *(%%esi); cld\n\t"
+		"pop %%es\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret),
+		  "=b" (map)
+		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
+		  "1" (0),
+		  "D" ((long) &opt),
+		  "S" (&pci_indirect));
+	DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
+	if (ret & 0xff00)
+		printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
+	else if (opt.size) {
+		rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
+		if (rt) {
+			memset(rt, 0, sizeof(struct irq_routing_table));
+			rt->size = opt.size + sizeof(struct irq_routing_table);
+			rt->exclusive_irqs = map;
+			memcpy(rt->slots, (void *) page, opt.size);
+			printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
+		}
+	}
+	free_page(page);
+	return rt;
+}
+
+
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
+{
+	int ret;
+
+	__asm__("lcall *(%%esi); cld\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_SET_PCI_HW_INT),
+		  "b" ((dev->bus->number << 8) | dev->devfn),
+		  "c" ((irq << 8) | (pin + 10)),
+		  "S" (&pci_indirect));
+	return !(ret & 0xff00);
+}
+
+static int __init pci_pcbios_init(void)
+{
+	if ((pci_probe & PCI_PROBE_BIOS) 
+		&& ((pci_root_ops = pci_find_bios()))) {
+		pci_probe |= PCI_BIOS_SORT;
+		pci_bios_present = 1;
+		pci_config_read = pci_bios_read;
+		pci_config_write = pci_bios_write;
+	}
+	return 0;
+}
+
+arch_initcall(pci_pcbios_init);
diff -Nru a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/pci.h	Thu May  9 15:21:08 2002
@@ -0,0 +1,75 @@
+/*
+ *	Low-Level PCI Access for i386 machines.
+ *
+ *	(c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_PROBE_BIOS		0x0001
+#define PCI_PROBE_CONF1		0x0002
+#define PCI_PROBE_CONF2		0x0004
+#define PCI_NO_SORT		0x0100
+#define PCI_BIOS_SORT		0x0200
+#define PCI_NO_CHECKS		0x0400
+#define PCI_USE_PIRQ_MASK	0x0800
+#define PCI_ASSIGN_ROMS		0x1000
+#define PCI_BIOS_IRQ_SCAN	0x2000
+#define PCI_ASSIGN_ALL_BUSSES	0x4000
+#define PCI_NO_ACPI_ROUTING	0x8000
+
+extern unsigned int pci_probe;
+
+/* pci-i386.c */
+
+extern unsigned int pcibios_max_latency;
+
+void pcibios_resource_survey(void);
+int pcibios_enable_resources(struct pci_dev *);
+
+/* pci-pc.c */
+
+extern int pcibios_last_bus;
+extern struct pci_bus *pci_root_bus;
+extern struct pci_ops *pci_root_ops;
+
+/* pci-irq.c */
+
+struct irq_info {
+	u8 bus, devfn;			/* Bus, device and function */
+	struct {
+		u8 link;		/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;		/* Available IRQs */
+	} __attribute__((packed)) irq[4];
+	u8 slot;			/* Slot number, 0=onboard */
+	u8 rfu;
+} __attribute__((packed));
+
+struct irq_routing_table {
+	u32 signature;			/* PIRQ_SIGNATURE should be here */
+	u16 version;			/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
+	u16 exclusive_irqs;		/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;		/* Crap */
+	u8 rfu[11];
+	u8 checksum;			/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__((packed));
+
+extern unsigned int pcibios_irq_mask;
+
+extern int pci_use_acpi_routing;
+extern spinlock_t pci_config_lock;
+
+void pcibios_fixup_irqs(void);
+void pcibios_enable_irq(struct pci_dev *dev);
+
+extern int (*pci_lookup_irq)(struct pci_dev * dev, int assign);
diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/pci/visws.c	Thu May  9 15:21:03 2002
@@ -0,0 +1,141 @@
+/*
+ *	Low-Level PCI Support for SGI Visual Workstation
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/smp.h>
+#include <asm/lithium.h>
+#include <asm/io.h>
+
+#include "pci-i386.h"
+
+unsigned int pci_probe = 0;
+
+/*
+ *  The VISWS uses configuration access type 1 only.
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inb(0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	*value = inw(0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inl(0xCFC);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	outb(value, 0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outw(value, 0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outl(value, 0xCFC);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops visws_pci_ops = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+static void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev, *p;
+	u8 pin;
+	int irq;
+
+	pci_for_each_dev(dev) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+		dev->irq = 0;
+		if (!pin)
+			continue;
+		pin--;
+		if (dev->bus->parent) {
+			p = dev->bus->parent->self;
+			pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		} else
+			p = dev;
+		irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
+		if (irq >= 0)
+			dev->irq = irq;
+		DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
+	}
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+#if 0
+static struct resource visws_pci_bus_resources[2] = {
+	{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
+	{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
+};
+#endif
+
+void __init pcibios_init(void)
+{
+	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
+
+	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
+	pci_scan_bus(0, &visws_pci_ops, NULL);
+	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
+	pcibios_fixup_irqs();
+	pcibios_resource_survey();
+}
+
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	return pcibios_enable_resources(dev);
+}
+
+void __init pcibios_penalize_isa_irq(irq)
+{
+}
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Thu May  9 15:21:02 2002
+++ b/arch/ia64/defconfig	Thu May  9 15:21:02 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
diff -Nru a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c
--- a/arch/ia64/kernel/pci.c	Thu May  9 15:21:06 2002
+++ b/arch/ia64/kernel/pci.c	Thu May  9 15:21:06 2002
@@ -259,10 +259,6 @@
 void __init
 pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
 }
 
 int
@@ -278,7 +274,8 @@
 }
 
 void
-pcibios_align_resource (void *data, struct resource *res, unsigned long size)
+pcibios_align_resource (void *data, struct resource *res,
+		        unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp
--- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	Thu May  9 15:21:05 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	Thu May  9 15:21:05 2002
@@ -205,7 +205,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 CONFIG_BLK_DEV_ADMA=y
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp
--- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	Thu May  9 15:21:04 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	Thu May  9 15:21:04 2002
@@ -205,7 +205,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 CONFIG_BLK_DEV_ADMA=y
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-dig-mp b/arch/ia64/sn/configs/sn1/defconfig-dig-mp
--- a/arch/ia64/sn/configs/sn1/defconfig-dig-mp	Thu May  9 15:21:08 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-dig-mp	Thu May  9 15:21:08 2002
@@ -161,7 +161,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-dig-sp b/arch/ia64/sn/configs/sn1/defconfig-dig-sp
--- a/arch/ia64/sn/configs/sn1/defconfig-dig-sp	Thu May  9 15:21:02 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-dig-sp	Thu May  9 15:21:02 2002
@@ -161,7 +161,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-generic-mp b/arch/ia64/sn/configs/sn1/defconfig-generic-mp
--- a/arch/ia64/sn/configs/sn1/defconfig-generic-mp	Thu May  9 15:21:04 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-generic-mp	Thu May  9 15:21:04 2002
@@ -156,7 +156,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-generic-sp b/arch/ia64/sn/configs/sn1/defconfig-generic-sp
--- a/arch/ia64/sn/configs/sn1/defconfig-generic-sp	Thu May  9 15:21:05 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-generic-sp	Thu May  9 15:21:05 2002
@@ -156,7 +156,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-prom-medusa b/arch/ia64/sn/configs/sn1/defconfig-prom-medusa
--- a/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	Thu May  9 15:21:05 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	Thu May  9 15:21:05 2002
@@ -169,7 +169,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp
--- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	Thu May  9 15:21:04 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	Thu May  9 15:21:04 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules
--- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	Thu May  9 15:21:08 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	Thu May  9 15:21:08 2002
@@ -228,7 +228,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0
--- a/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	Thu May  9 15:21:06 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	Thu May  9 15:21:06 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-sn1-sp b/arch/ia64/sn/configs/sn1/defconfig-sn1-sp
--- a/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	Thu May  9 15:21:01 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	Thu May  9 15:21:01 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-dig-numa b/arch/ia64/sn/configs/sn2/defconfig-dig-numa
--- a/arch/ia64/sn/configs/sn2/defconfig-dig-numa	Thu May  9 15:21:03 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-dig-numa	Thu May  9 15:21:03 2002
@@ -162,7 +162,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	Thu May  9 15:21:09 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	Thu May  9 15:21:09 2002
@@ -161,7 +161,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	Thu May  9 15:21:06 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	Thu May  9 15:21:06 2002
@@ -161,7 +161,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	Thu May  9 15:21:03 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	Thu May  9 15:21:03 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	Thu May  9 15:21:08 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	Thu May  9 15:21:08 2002
@@ -228,7 +228,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa b/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	Thu May  9 15:21:06 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	Thu May  9 15:21:06 2002
@@ -169,7 +169,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/ia64/sn/configs/sn2/defconfig-sn2-sp b/arch/ia64/sn/configs/sn2/defconfig-sn2-sp
--- a/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	Thu May  9 15:21:03 2002
+++ b/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	Thu May  9 15:21:03 2002
@@ -226,7 +226,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
diff -Nru a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
--- a/arch/m68k/amiga/amiints.c	Thu May  9 15:21:07 2002
+++ b/arch/m68k/amiga/amiints.c	Thu May  9 15:21:07 2002
@@ -40,6 +40,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/errno.h>
 #include <linux/seq_file.h>
 
 #include <asm/system.h>
diff -Nru a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c
--- a/arch/m68k/amiga/chipram.c	Thu May  9 15:21:08 2002
+++ b/arch/m68k/amiga/chipram.c	Thu May  9 15:21:08 2002
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <asm/page.h>
 #include <asm/amigahw.h>
 
 unsigned long amiga_chip_size;
diff -Nru a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
--- a/arch/m68k/amiga/config.c	Thu May  9 15:21:01 2002
+++ b/arch/m68k/amiga/config.c	Thu May  9 15:21:01 2002
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/rtc.h>
 #include <linux/init.h>
 #ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
@@ -89,9 +90,8 @@
 extern int show_amiga_interrupts (struct seq_file *, void *);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset (void);
-static void a3000_gettod (int *, int *, int *, int *, int *, int *);
-static void a2000_gettod (int *, int *, int *, int *, int *, int *);
-static int amiga_hwclk (int, struct hwclk_time *);
+static int a3000_hwclk (int, struct rtc_time *);
+static int a2000_hwclk (int, struct rtc_time *);
 static int amiga_set_clock_mmss (unsigned long);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
@@ -404,12 +404,12 @@
   mach_get_irq_list    = show_amiga_interrupts;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
-    mach_gettod  = a3000_gettod;
+    mach_hwclk         = a3000_hwclk;
     rtc_resource.name = "A3000 RTC";
     request_resource(&iomem_resource, &rtc_resource);
   }
   else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
-    mach_gettod  = a2000_gettod;
+    mach_hwclk         = a2000_hwclk;
     rtc_resource.name = "A2000 RTC";
     request_resource(&iomem_resource, &rtc_resource);
   }
@@ -424,7 +424,6 @@
 				      * system.                  /Jes
 				      */
 
-  mach_hwclk           = amiga_hwclk;
   mach_set_clock_mmss  = amiga_set_clock_mmss;
 #ifdef CONFIG_AMIGA_FLOPPY
   mach_floppy_setup    = amiga_floppy_setup;
@@ -569,25 +568,47 @@
 	return ticks + offset;
 }
 
-static void a3000_gettod (int *yearp, int *monp, int *dayp,
-			  int *hourp, int *minp, int *secp)
+static int a3000_hwclk(int op, struct rtc_time *t)
 {
 	volatile struct tod3000 *tod = TOD_3000;
 
 	tod->cntrl1 = TOD3000_CNTRL1_HOLD;
 
-	*secp  = tod->second1 * 10 + tod->second2;
-	*minp  = tod->minute1 * 10 + tod->minute2;
-	*hourp = tod->hour1   * 10 + tod->hour2;
-	*dayp  = tod->day1    * 10 + tod->day2;
-	*monp  = tod->month1  * 10 + tod->month2;
-	*yearp = tod->year1   * 10 + tod->year2;
+	if (!op) { /* read */
+		t->tm_sec  = tod->second1 * 10 + tod->second2;
+		t->tm_min  = tod->minute1 * 10 + tod->minute2;
+		t->tm_hour = tod->hour1   * 10 + tod->hour2;
+		t->tm_mday = tod->day1    * 10 + tod->day2;
+		t->tm_wday = tod->weekday;
+		t->tm_mon  = tod->month1  * 10 + tod->month2 - 1;
+		t->tm_year = tod->year1   * 10 + tod->year2;
+		if (t->tm_year <= 69)
+			t->tm_year += 100;
+	} else {
+		tod->second1 = t->tm_sec / 10;
+		tod->second2 = t->tm_sec % 10;
+		tod->minute1 = t->tm_min / 10;
+		tod->minute2 = t->tm_min % 10;
+		tod->hour1   = t->tm_hour / 10;
+		tod->hour2   = t->tm_hour % 10;
+		tod->day1    = t->tm_mday / 10;
+		tod->day2    = t->tm_mday % 10;
+		if (t->tm_wday != -1)
+			tod->weekday = t->tm_wday;
+		tod->month1  = (t->tm_mon + 1) / 10;
+		tod->month2  = (t->tm_mon + 1) % 10;
+		if (t->tm_year >= 100)
+			t->tm_year -= 100;
+		tod->year1   = t->tm_year / 10;
+		tod->year2   = t->tm_year % 10;
+	}
 
 	tod->cntrl1 = TOD3000_CNTRL1_FREE;
+
+	return 0;
 }
 
-static void a2000_gettod (int *yearp, int *monp, int *dayp,
-			  int *hourp, int *minp, int *secp)
+static int a2000_hwclk(int op, struct rtc_time *t)
 {
 	volatile struct tod2000 *tod = TOD_2000;
 
@@ -596,112 +617,49 @@
 	while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
 		;
 
-	*secp  = tod->second1     * 10 + tod->second2;
-	*minp  = tod->minute1     * 10 + tod->minute2;
-	*hourp = (tod->hour1 & 3) * 10 + tod->hour2;
-	*dayp  = tod->day1        * 10 + tod->day2;
-	*monp  = tod->month1      * 10 + tod->month2;
-	*yearp = tod->year1       * 10 + tod->year2;
-
-	if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-		if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
-			*hourp = 0;
-		else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
-			*hourp += 12;
+	if (!op) { /* read */
+		t->tm_sec  = tod->second1     * 10 + tod->second2;
+		t->tm_min  = tod->minute1     * 10 + tod->minute2;
+		t->tm_hour = (tod->hour1 & 3) * 10 + tod->hour2;
+		t->tm_mday = tod->day1        * 10 + tod->day2;
+		t->tm_wday = tod->weekday;
+		t->tm_mon  = tod->month1      * 10 + tod->month2 - 1;
+		t->tm_year = tod->year1       * 10 + tod->year2;
+		if (t->tm_year <= 69)
+			t->tm_year += 100;
+
+		if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
+			if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
+				t->tm_hour = 0;
+			else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
+				t->tm_hour += 12;
+		}
+	} else {
+		tod->second1 = t->tm_sec / 10;
+		tod->second2 = t->tm_sec % 10;
+		tod->minute1 = t->tm_min / 10;
+		tod->minute2 = t->tm_min % 10;
+		if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
+			tod->hour1 = t->tm_hour / 10;
+		else if (t->tm_hour >= 12)
+			tod->hour1 = TOD2000_HOUR1_PM +
+				(t->tm_hour - 12) / 10;
+		else
+			tod->hour1 = t->tm_hour / 10;
+		tod->hour2   = t->tm_hour % 10;
+		tod->day1    = t->tm_mday / 10;
+		tod->day2    = t->tm_mday % 10;
+		if (t->tm_wday != -1)
+			tod->weekday = t->tm_wday;
+		tod->month1  = (t->tm_mon + 1) / 10;
+		tod->month2  = (t->tm_mon + 1) % 10;
+		if (t->tm_year >= 100)
+			t->tm_year -= 100;
+		tod->year1   = t->tm_year / 10;
+		tod->year2   = t->tm_year % 10;
 	}
 
 	tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-}
-
-static int amiga_hwclk(int op, struct hwclk_time *t)
-{
-	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
-
-		if (!op) { /* read */
-			t->sec  = tod->second1 * 10 + tod->second2;
-			t->min  = tod->minute1 * 10 + tod->minute2;
-			t->hour = tod->hour1   * 10 + tod->hour2;
-			t->day  = tod->day1    * 10 + tod->day2;
-			t->wday = tod->weekday;
-			t->mon  = tod->month1  * 10 + tod->month2 - 1;
-			t->year = tod->year1   * 10 + tod->year2;
-			if (t->year <= 69)
-				t->year += 100;
-		} else {
-			tod->second1 = t->sec / 10;
-			tod->second2 = t->sec % 10;
-			tod->minute1 = t->min / 10;
-			tod->minute2 = t->min % 10;
-			tod->hour1   = t->hour / 10;
-			tod->hour2   = t->hour % 10;
-			tod->day1    = t->day / 10;
-			tod->day2    = t->day % 10;
-			if (t->wday != -1)
-				tod->weekday = t->wday;
-			tod->month1  = (t->mon + 1) / 10;
-			tod->month2  = (t->mon + 1) % 10;
-			if (t->year >= 100)
-				t->year -= 100;
-			tod->year1   = t->year / 10;
-			tod->year2   = t->year % 10;
-		}
-
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
-	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
-
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
-
-		if (!op) { /* read */
-			t->sec  = tod->second1     * 10 + tod->second2;
-			t->min  = tod->minute1     * 10 + tod->minute2;
-			t->hour = (tod->hour1 & 3) * 10 + tod->hour2;
-			t->day  = tod->day1        * 10 + tod->day2;
-			t->wday = tod->weekday;
-			t->mon  = tod->month1      * 10 + tod->month2 - 1;
-			t->year = tod->year1       * 10 + tod->year2;
-			if (t->year <= 69)
-				t->year += 100;
-
-			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-				if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12)
-					t->hour = 0;
-				else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12)
-					t->hour += 12;
-			}
-		} else {
-			tod->second1 = t->sec / 10;
-			tod->second2 = t->sec % 10;
-			tod->minute1 = t->min / 10;
-			tod->minute2 = t->min % 10;
-			if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
-				tod->hour1 = t->hour / 10;
-			else if (t->hour >= 12)
-				tod->hour1 = TOD2000_HOUR1_PM +
-					(t->hour - 12) / 10;
-			else
-				tod->hour1 = t->hour / 10;
-			tod->hour2   = t->hour % 10;
-			tod->day1    = t->day / 10;
-			tod->day2    = t->day % 10;
-			if (t->wday != -1)
-				tod->weekday = t->wday;
-			tod->month1  = (t->mon + 1) / 10;
-			tod->month2  = (t->mon + 1) % 10;
-			if (t->year >= 100)
-				t->year -= 100;
-			tod->year1   = t->year / 10;
-			tod->year2   = t->year % 10;
-		}
-
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-	}
 
 	return 0;
 }
diff -Nru a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
--- a/arch/m68k/apollo/config.c	Thu May  9 15:21:05 2002
+++ b/arch/m68k/apollo/config.c	Thu May  9 15:21:05 2002
@@ -4,6 +4,7 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/rtc.h>
 
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
@@ -33,8 +34,7 @@
 extern void dn_disable_irq(unsigned int);
 extern int show_dn_interrupts(struct seq_file *, void *);
 extern unsigned long dn_gettimeoffset(void);
-extern void dn_gettod(int *, int *, int *, int *, int *, int *);
-extern int dn_dummy_hwclk(int, struct hwclk_time *);
+extern int dn_dummy_hwclk(int, struct rtc_time *);
 extern int dn_dummy_set_clock_mmss(unsigned long);
 extern void dn_mksound(unsigned int count, unsigned int ticks);
 extern void dn_dummy_reset(void);
@@ -175,7 +175,6 @@
 	disable_irq     = dn_disable_irq;
 	mach_get_irq_list    = show_dn_interrupts;
 	mach_gettimeoffset   = dn_gettimeoffset;
-	mach_gettod	     = dn_gettod; /* */
 	mach_max_dma_address = 0xffffffff;
 	mach_hwclk           = dn_dummy_hwclk; /* */
 	mach_set_clock_mmss  = dn_dummy_set_clock_mmss; /* */
@@ -240,40 +239,26 @@
 
 }
 
-void dn_gettod(int *yearp, int *monp, int *dayp,
-	       int *hourp, int *minp, int *secp) {
-
-  *yearp=rtc->year;
-  *monp=rtc->month;
-  *dayp=rtc->day_of_month;
-  *hourp=rtc->hours;
-  *minp=rtc->minute;
-  *secp=rtc->second;
-
-printk("gettod: %d %d %d %d %d %d\n",*yearp,*monp,*dayp,*hourp,*minp,*secp);
-
-}
-
-int dn_dummy_hwclk(int op, struct hwclk_time *t) {
+int dn_dummy_hwclk(int op, struct rtc_time *t) {
 
 
   if(!op) { /* read */
-    t->sec=rtc->second;
-    t->min=rtc->minute;
-    t->hour=rtc->hours;
-    t->day=rtc->day_of_month;
-    t->wday=rtc->day_of_week;
-    t->mon=rtc->month;
-    t->year=rtc->year;
+    t->tm_sec=rtc->second;
+    t->tm_min=rtc->minute;
+    t->tm_hour=rtc->hours;
+    t->tm_mday=rtc->day_of_month;
+    t->tm_wday=rtc->day_of_week;
+    t->tm_mon=rtc->month;
+    t->tm_year=rtc->year;
   } else {
-    rtc->second=t->sec;
-    rtc->minute=t->min;
-    rtc->hours=t->hour;
-    rtc->day_of_month=t->day;
-    if(t->wday!=-1)
-      rtc->day_of_week=t->wday;
-    rtc->month=t->mon;
-    rtc->year=t->year;
+    rtc->second=t->tm_sec;
+    rtc->minute=t->tm_min;
+    rtc->hours=t->tm_hour;
+    rtc->day_of_month=t->tm_mday;
+    if(t->tm_wday!=-1)
+      rtc->day_of_week=t->tm_wday;
+    rtc->month=t->tm_mon;
+    rtc->year=t->tm_year;
   }
 
   return 0;
diff -Nru a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
--- a/arch/m68k/atari/ataints.c	Thu May  9 15:21:03 2002
+++ b/arch/m68k/atari/ataints.c	Thu May  9 15:21:03 2002
@@ -169,7 +169,7 @@
 void atari_slow_irq_##n##_dummy (void) {				   \
 __asm__ (__ALIGN_STR "\n"						   \
 "atari_slow_irq_" #n "_handler:\t"					   \
-"	addql	#1,irq_stat+8\n" /* local_irq_count */			   \
+"	addql	#1,%5\n"		/* local_irq_count++ */		   \
 	SAVE_ALL_INT "\n"						   \
 	GET_CURRENT(%%d0) "\n"						   \
 "	andb	#~(1<<(%c3&7)),%a4:w\n"	/* mask this interrupt */	   \
@@ -194,8 +194,10 @@
 	 : : "i" (&kstat.irqs[0][n+8]), "i" (&irq_handler[n+8]),	   \
 	     "n" (PT_OFF_SR), "n" (n),					   \
 	     "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a)	   \
-		        : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b))	   \
+		        : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)),	   \
+	     "m" (local_irq_count(0))					   \
 );									   \
+	for (;;);			/* fake noreturn */		   \
 }
 
 BUILD_SLOW_IRQ(0);
@@ -275,7 +277,7 @@
 "atari_fast_irq_handler:
 	orw 	#0x700,%%sr		/* disable all interrupts */
 atari_prio_irq_handler:\t
-	addql	#1,irq_stat+8\n" /* local_irq_count */
+	addql	#1,%2\n"		/* local_irq_count++ */
 	SAVE_ALL_INT "\n"
 	GET_CURRENT(%%d0) "
 	/* get vector number from stack frame and convert to source */
@@ -295,8 +297,10 @@
 	addql	#8,%%sp
 	addql	#4,%%sp
 	jbra	ret_from_interrupt"
-	 : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC)
+	 : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC),
+	     "m" (local_irq_count(0))
 );
+	for (;;);
 }
 
 /* GK:
diff -Nru a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
--- a/arch/m68k/atari/config.c	Thu May  9 15:21:02 2002
+++ b/arch/m68k/atari/config.c	Thu May  9 15:21:02 2002
@@ -38,6 +38,7 @@
 #include <asm/atariints.h>
 #include <asm/atari_stram.h>
 #include <asm/system.h>
+#include <asm/keyboard.h>
 #include <asm/machdep.h>
 #include <asm/hwtest.h>
 #include <asm/io.h>
@@ -79,10 +80,8 @@
 /* atari specific timer functions (in time.c) */
 extern void atari_sched_init(void (*)(int, void *, struct pt_regs *));
 extern unsigned long atari_gettimeoffset (void);
-extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
-extern void atari_tt_gettod (int *, int *, int *, int *, int *, int *);
-extern int atari_mste_hwclk (int, struct hwclk_time *);
-extern int atari_tt_hwclk (int, struct hwclk_time *);
+extern int atari_mste_hwclk (int, struct rtc_time *);
+extern int atari_tt_hwclk (int, struct rtc_time *);
 extern int atari_mste_set_clock_mmss (unsigned long);
 extern int atari_tt_set_clock_mmss (unsigned long);
 
@@ -258,7 +257,9 @@
     mach_keyb_init       = atari_keyb_init;
     mach_kbdrate         = atari_kbdrate;
     mach_kbd_translate   = atari_kbd_translate;
+#ifdef CONFIG_MAGIC_SYSRQ
     SYSRQ_KEY            = 0xff;
+#endif
     mach_kbd_leds        = atari_kbd_leds;
     mach_init_IRQ        = atari_init_IRQ;
     mach_request_irq     = atari_request_irq;
@@ -442,14 +443,12 @@
     if (hwreg_present( &tt_rtc.regsel )) {
 	ATARIHW_SET(TT_CLK);
         printk( "TT_CLK " );
-        mach_gettod = atari_tt_gettod;
         mach_hwclk = atari_tt_hwclk;
         mach_set_clock_mmss = atari_tt_set_clock_mmss;
     }
     if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) {
 	ATARIHW_SET(MSTE_CLK);
         printk( "MSTE_CLK ");
-        mach_gettod = atari_mste_gettod;
         mach_hwclk = atari_mste_hwclk;
         mach_set_clock_mmss = atari_mste_set_clock_mmss;
     }
diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
--- a/arch/m68k/atari/stram.c	Thu May  9 15:21:03 2002
+++ b/arch/m68k/atari/stram.c	Thu May  9 15:21:03 2002
@@ -236,8 +236,8 @@
 static void do_stram_request(request_queue_t *);
 static int stram_open( struct inode *inode, struct file *filp );
 static int stram_release( struct inode *inode, struct file *filp );
-#endif
 static void reserve_region(void *start, void *end);
+#endif
 static BLOCK *add_region( void *addr, unsigned long size );
 static BLOCK *find_region( void *addr );
 static int remove_region( BLOCK *block );
@@ -296,7 +296,7 @@
 		max_swap_size =
 			(!MACH_IS_HADES &&
 			 (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <=
-			  (high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;
+			  ((unsigned long)high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;
 	DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size );
 #endif
 
@@ -660,7 +660,7 @@
 		pmd_clear(dir);
 		return;
 	}
-	pte = pte_offset(dir, address);
+	pte = pte_offset_kernel(dir, address);
 	offset += address & PMD_MASK;
 	address &= ~PMD_MASK;
 	end = address + size;
@@ -759,7 +759,7 @@
 			/* Get a page for the entry, using the existing
 			   swap cache page if there is one.  Otherwise,
 			   get a clean page and read the swap into it. */
-			page = read_swap_cache(entry);
+			page = read_swap_cache_async(entry);
 			if (!page) {
 				swap_free(entry);
 				return -ENOMEM;
@@ -768,7 +768,7 @@
 			for_each_task(p)
 				unswap_process(p->mm, entry, page);
 			read_unlock(&tasklist_lock);
-			shm_unuse(entry, page);
+			shmem_unuse(entry, page);
 			/* Now get rid of the extra reference to the
 			   temporary page we've been using. */
 			if (PageSwapCache(page))
@@ -1069,7 +1069,6 @@
 	return( 0 );
 }
 
-#endif /* CONFIG_STRAM_SWAP */
 
 
 /* ------------------------------------------------------------------------ */
@@ -1082,6 +1081,7 @@
 	reserve_bootmem (virt_to_phys(start), end - start);
 }
 
+#endif /* CONFIG_STRAM_SWAP */
 
 
 /* ------------------------------------------------------------------------ */
diff -Nru a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
--- a/arch/m68k/atari/time.c	Thu May  9 15:21:09 2002
+++ b/arch/m68k/atari/time.c	Thu May  9 15:21:09 2002
@@ -14,6 +14,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/rtc.h>
 
 #include <asm/rtc.h>
 
@@ -83,88 +84,21 @@
 
 #define	RTC_READ(reg)				\
     ({	unsigned char	__val;			\
-		(void) writeb(reg,&tt_rtc.regsel);	\
+		(void) atari_writeb(reg,&tt_rtc.regsel);	\
 		__val = tt_rtc.data;		\
 		__val;				\
 	})
 
 #define	RTC_WRITE(reg,val)			\
     do {					\
-		writeb(reg,&tt_rtc.regsel);	\
+		atari_writeb(reg,&tt_rtc.regsel);	\
 		tt_rtc.data = (val);		\
 	} while(0)
 
 
-void atari_mste_gettod (int *yearp, int *monp, int *dayp,
-			int *hourp, int *minp, int *secp)
-{
-    int hr24=0, hour;
-    struct MSTE_RTC val;
-
-    mste_rtc.mode=(mste_rtc.mode | 1);
-    hr24=mste_rtc.mon_tens & 1;
-    mste_rtc.mode=(mste_rtc.mode & ~1);
-
-    mste_read(&val);
-    *secp = val.sec_ones + val.sec_tens * 10;
-    *minp = val.min_ones + val.min_tens * 10;
-    hour = val.hr_ones + val.hr_tens * 10;
-    if (!hr24) {
-        if (hour == 12 || hour == 12 + 20)
-	    hour -= 12;
-	if (hour >= 20)
-	    hour += 12 - 20;
-    }
-    *hourp = hour;
-    *dayp = val.day_ones + val.day_tens * 10;
-    *monp = val.mon_ones + val.mon_tens * 10;
-    *yearp = val.year_ones + val.year_tens * 10 + 80;	
-}
-
-  
-void atari_tt_gettod (int *yearp, int *monp, int *dayp,
-		      int *hourp, int *minp, int *secp)
-{
-    unsigned char	ctrl;
-    int hour, pm;
-
-    while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
-    while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
-
-    *secp  = RTC_READ(RTC_SECONDS);
-    *minp  = RTC_READ(RTC_MINUTES);
-    hour = RTC_READ(RTC_HOURS);
-    *dayp  = RTC_READ(RTC_DAY_OF_MONTH);
-    *monp  = RTC_READ(RTC_MONTH);
-    *yearp = RTC_READ(RTC_YEAR);
-    pm = hour & 0x80;
-    hour &= ~0x80;
-
-    ctrl = RTC_READ(RTC_CONTROL); 
-
-    if (!(ctrl & RTC_DM_BINARY)) {
-        BCD_TO_BIN(*secp);
-        BCD_TO_BIN(*minp);
-        BCD_TO_BIN(hour);
-        BCD_TO_BIN(*dayp);
-        BCD_TO_BIN(*monp);
-        BCD_TO_BIN(*yearp);
-    }
-    if (!(ctrl & RTC_24H)) {
-	if (!pm && hour == 12)
-	    hour = 0;
-	else if (pm && hour != 12)
-            hour += 12;
-    }
-    *hourp = hour;
-
-    /* Adjust values (let the setup valid) */
-    *yearp += atari_rtc_year_offset;
-}
-
 #define HWCLK_POLL_INTERVAL	5
 
-int atari_mste_hwclk( int op, struct hwclk_time *t )
+int atari_mste_hwclk( int op, struct rtc_time *t )
 {
     int hour, year;
     int hr24=0;
@@ -177,11 +111,11 @@
     if (op) {
         /* write: prepare values */
         
-        val.sec_ones = t->sec % 10;
-        val.sec_tens = t->sec / 10;
-        val.min_ones = t->min % 10;
-        val.min_tens = t->min / 10;
-        hour = t->hour;
+        val.sec_ones = t->tm_sec % 10;
+        val.sec_tens = t->tm_sec / 10;
+        val.min_ones = t->tm_min % 10;
+        val.min_tens = t->tm_min / 10;
+        hour = t->tm_hour;
         if (!hr24) {
 	    if (hour > 11)
 		hour += 20 - 12;
@@ -190,14 +124,14 @@
         }
         val.hr_ones = hour % 10;
         val.hr_tens = hour / 10;
-        val.day_ones = t->day % 10;
-        val.day_tens = t->day / 10;
-        val.mon_ones = (t->mon+1) % 10;
-        val.mon_tens = (t->mon+1) / 10;
-        year = t->year - 80;
+        val.day_ones = t->tm_mday % 10;
+        val.day_tens = t->tm_mday / 10;
+        val.mon_ones = (t->tm_mon+1) % 10;
+        val.mon_tens = (t->tm_mon+1) / 10;
+        year = t->tm_year - 80;
         val.year_ones = year % 10;
         val.year_tens = year / 10;
-        val.weekday = t->wday;
+        val.weekday = t->tm_wday;
         mste_write(&val);
         mste_rtc.mode=(mste_rtc.mode | 1);
         val.year_ones = (year % 4);	/* leap year register */
@@ -205,8 +139,8 @@
     }
     else {
         mste_read(&val);
-        t->sec = val.sec_ones + val.sec_tens * 10;
-        t->min = val.min_ones + val.min_tens * 10;
+        t->tm_sec = val.sec_ones + val.sec_tens * 10;
+        t->tm_min = val.min_ones + val.min_tens * 10;
         hour = val.hr_ones + val.hr_tens * 10;
 	if (!hr24) {
 	    if (hour == 12 || hour == 12 + 20)
@@ -214,16 +148,16 @@
 	    if (hour >= 20)
                 hour += 12 - 20;
         }
-	t->hour = hour;
-	t->day = val.day_ones + val.day_tens * 10;
-        t->mon = val.mon_ones + val.mon_tens * 10 - 1;
-        t->year = val.year_ones + val.year_tens * 10 + 80;
-        t->wday = val.weekday;
+	t->tm_hour = hour;
+	t->tm_mday = val.day_ones + val.day_tens * 10;
+        t->tm_mon  = val.mon_ones + val.mon_tens * 10 - 1;
+        t->tm_year = val.year_ones + val.year_tens * 10 + 80;
+        t->tm_wday = val.weekday;
     }
     return 0;
 }
 
-int atari_tt_hwclk( int op, struct hwclk_time *t )
+int atari_tt_hwclk( int op, struct rtc_time *t )
 {
     int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; 
     unsigned long 	flags;
@@ -236,13 +170,13 @@
     if (op) {
         /* write: prepare values */
         
-        sec  = t->sec;
-        min  = t->min;
-        hour = t->hour;
-        day  = t->day;
-        mon  = t->mon + 1;
-        year = t->year - atari_rtc_year_offset;
-        wday = t->wday + (t->wday >= 0);
+        sec  = t->tm_sec;
+        min  = t->tm_min;
+        hour = t->tm_hour;
+        day  = t->tm_mday;
+        mon  = t->tm_mon + 1;
+        year = t->tm_year - atari_rtc_year_offset;
+        wday = t->tm_wday + (t->tm_wday >= 0);
         
         if (!(ctrl & RTC_24H)) {
 	    if (hour > 11) {
@@ -331,13 +265,13 @@
 		hour += 12;
         }
 
-        t->sec  = sec;
-        t->min  = min;
-        t->hour = hour;
-        t->day  = day;
-        t->mon  = mon - 1;
-        t->year = year + atari_rtc_year_offset;
-        t->wday = wday - 1;
+        t->tm_sec  = sec;
+        t->tm_min  = min;
+        t->tm_hour = hour;
+        t->tm_mday = day;
+        t->tm_mon  = mon - 1;
+        t->tm_year = year + atari_rtc_year_offset;
+        t->tm_wday = wday - 1;
     }
 
     return( 0 );
diff -Nru a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
--- a/arch/m68k/bvme6000/config.c	Thu May  9 15:21:02 2002
+++ b/arch/m68k/bvme6000/config.c	Thu May  9 15:21:02 2002
@@ -22,6 +22,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <linux/major.h>
+#include <linux/rtc.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -46,9 +47,7 @@
 extern int  bvme6000_keyb_init(void);
 extern int  bvme6000_kbdrate (struct kbd_repeat *);
 extern unsigned long bvme6000_gettimeoffset (void);
-extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec);
-extern int bvme6000_hwclk (int, struct hwclk_time *);
+extern int bvme6000_hwclk (int, struct rtc_time *);
 extern int bvme6000_set_clock_mmss (unsigned long);
 extern void bvme6000_check_partition (struct gendisk *hd, unsigned int dev);
 extern void bvme6000_mksound( unsigned int count, unsigned int ticks );
@@ -138,7 +137,6 @@
     mach_kbdrate         = bvme6000_kbdrate;
     mach_init_IRQ        = bvme6000_init_IRQ;
     mach_gettimeoffset   = bvme6000_gettimeoffset;
-    mach_gettod  	 = bvme6000_gettod;
     mach_hwclk           = bvme6000_hwclk;
     mach_set_clock_mmss	 = bvme6000_set_clock_mmss;
 /*  mach_mksound         = bvme6000_mksound; */
@@ -181,8 +179,8 @@
         unsigned long *old = (unsigned long *)0xf8000000;
 
         /* Wait for button release */
-	while (*config_reg_ptr & BVME_ABORT_STATUS)
-		;
+        while (*(volatile unsigned char *)BVME_LOCAL_IRQ_STAT & BVME_ABORT_STATUS)
+                ;
 
         *(new+4) = *(old+4);            /* Illegal instruction */
         *(new+9) = *(old+9);            /* Trace */
@@ -284,26 +282,6 @@
     return v;
 }
 
-extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec)
-{
-	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
-	unsigned char msr = rtc->msr & 0xc0;
-
-	rtc->msr = 0;		/* Ensure clock accessible */
-
-	do {	/* Loop until we get a reading with a stable seconds field */
-		*sec = bcd2bin (rtc->bcd_sec);
-		*min = bcd2bin (rtc->bcd_min);
-		*hour = bcd2bin (rtc->bcd_hr);
-		*day = bcd2bin (rtc->bcd_dom);
-		*mon = bcd2bin (rtc->bcd_mth);
-		*year = bcd2bin (rtc->bcd_year);
-	} while (bcd2bin (rtc->bcd_sec) != *sec);
-
-	rtc->msr = msr;
-}
-
 static unsigned char bcd2bin (unsigned char b)
 {
 	return ((b>>4)*10 + (b&15));
@@ -330,7 +308,7 @@
  * };
  */
 
-int bvme6000_hwclk(int op, struct hwclk_time *t)
+int bvme6000_hwclk(int op, struct rtc_time *t)
 {
 	volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
 	unsigned char msr = rtc->msr & 0xc0;
@@ -339,31 +317,31 @@
 				 * are accessible */
 	if (op)
 	{	/* Write.... */
-		rtc->t0cr_rtmr = t->year%4;
+		rtc->t0cr_rtmr = t->tm_year%4;
 		rtc->bcd_tenms = 0;
-		rtc->bcd_sec = bin2bcd(t->sec);
-		rtc->bcd_min = bin2bcd(t->min);
-		rtc->bcd_hr  = bin2bcd(t->hour);
-		rtc->bcd_dom = bin2bcd(t->day);
-		rtc->bcd_mth = bin2bcd(t->mon + 1);
-		rtc->bcd_year = bin2bcd(t->year%100);
-		if (t->wday >= 0)
-			rtc->bcd_dow = bin2bcd(t->wday+1);
-		rtc->t0cr_rtmr = t->year%4 | 0x08;
+		rtc->bcd_sec = bin2bcd(t->tm_sec);
+		rtc->bcd_min = bin2bcd(t->tm_min);
+		rtc->bcd_hr  = bin2bcd(t->tm_hour);
+		rtc->bcd_dom = bin2bcd(t->tm_mday);
+		rtc->bcd_mth = bin2bcd(t->tm_mon + 1);
+		rtc->bcd_year = bin2bcd(t->tm_year%100);
+		if (t->tm_wday >= 0)
+			rtc->bcd_dow = bin2bcd(t->tm_wday+1);
+		rtc->t0cr_rtmr = t->tm_year%4 | 0x08;
 	}
 	else
 	{	/* Read....  */
 		do {
-			t->sec =  bcd2bin(rtc->bcd_sec);
-			t->min =  bcd2bin(rtc->bcd_min);
-			t->hour = bcd2bin(rtc->bcd_hr);
-			t->day =  bcd2bin(rtc->bcd_dom);
-			t->mon =  bcd2bin(rtc->bcd_mth)-1;
-			t->year = bcd2bin(rtc->bcd_year);
-			if (t->year < 70)
-				t->year += 100;
-			t->wday = bcd2bin(rtc->bcd_dow)-1;
-		} while (t->sec != bcd2bin(rtc->bcd_sec));
+			t->tm_sec  = bcd2bin(rtc->bcd_sec);
+			t->tm_min  = bcd2bin(rtc->bcd_min);
+			t->tm_hour = bcd2bin(rtc->bcd_hr);
+			t->tm_mday = bcd2bin(rtc->bcd_dom);
+			t->tm_mon  = bcd2bin(rtc->bcd_mth)-1;
+			t->tm_year = bcd2bin(rtc->bcd_year);
+			if (t->tm_year < 70)
+				t->tm_year += 100;
+			t->tm_wday = bcd2bin(rtc->bcd_dow)-1;
+		} while (t->tm_sec != bcd2bin(rtc->bcd_sec));
 	}
 
 	rtc->msr = msr;
@@ -419,55 +397,3 @@
 {
 	return 0;
 }
-
-/*-------------------  Serial console stuff ------------------------*/
-
-static void bvme_scc_write(struct console *co, const char *str, unsigned cnt);
-
-
-void bvme6000_init_console_port (struct console *co, int cflag)
-{
-        co->write = bvme_scc_write;
-}
-
-
-static void scc_delay (void)
-{
-        int n;
-	volatile int trash;
-
-        for (n = 0; n < 20; n++)
-		trash = n;
-}
-
-static void scc_write (char ch)
-{
-        volatile char *p = (volatile char *)BVME_SCC_A_ADDR;
-
-        do {
-                scc_delay();
-        }
-        while (!(*p & 4));
-        scc_delay();
-        *p = 8;
-        scc_delay();
-        *p = ch;
-}
-
-
-static void bvme_scc_write (struct console *co, const char *str, unsigned count)
-{
-        unsigned long   flags;
-
-        save_flags(flags);
-        cli();
-
-        while (count--)
-        {
-                if (*str == '\n')
-                        scc_write ('\r');
-                scc_write (*str++);
-        }
-        restore_flags(flags);
-}
-
diff -Nru a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
--- a/arch/m68k/bvme6000/rtc.c	Thu May  9 15:21:01 2002
+++ b/arch/m68k/bvme6000/rtc.c	Thu May  9 15:21:01 2002
@@ -94,7 +94,7 @@
 
 		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
 
-		if ((mon > 12) || (day == 0))
+		if ((mon > 12) || (mon < 1) || (day == 0))
 			return -EINVAL;
 
 		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in
--- a/arch/m68k/config.in	Thu May  9 15:21:09 2002
+++ b/arch/m68k/config.in	Thu May  9 15:21:09 2002
@@ -14,7 +14,6 @@
 mainmenu_option next_comment
 comment 'Platform dependent setup'
 
-define_bool CONFIG_ISA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_PCMCIA n
@@ -130,11 +129,18 @@
    fi
 fi
 
+if [ "$CONFIG_Q40" = "y" -o "$CONFIG_AMIGA_PCMCIA" = "y" \
+      -o "$CONFIG_GG2" = "y" ]; then
+   define_bool CONFIG_ISA y
+else
+   define_bool CONFIG_ISA n
+fi
+
 source drivers/pci/Config.in
 source drivers/zorro/Config.in
 
 if [ "$CONFIG_Q40" = "y" ]; then
-source drivers/pnp/Config.in
+   source drivers/pnp/Config.in
 fi
 
 endmenu
@@ -251,7 +257,7 @@
    fi
 
    if [ "$CONFIG_SUN3" = "y" ]; then
-	dep_tristate 'Sun3 NCR5380 OBIO SCSI' CONFIG_SUN3_SCSI $CONFIG_SCSI
+	dep_tristate 'Sun3 NCR5380 SCSI' CONFIG_SUN3_SCSI $CONFIG_SCSI
    fi
 
    if [ "$CONFIG_SUN3X" = "y" ]; then
@@ -280,9 +286,17 @@
 	 bool '    Keepalive and linefill' CONFIG_SLIP_SMART
 	 bool '    Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
       fi
-      tristate '  PPP (point-to-point) support' CONFIG_PPP
+      tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
       if [ ! "$CONFIG_PPP" = "n" ]; then
-	 comment 'CCP compressors for PPP are only built as modules.'
+         dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
+         dep_bool '  PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
+         dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+         dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+         dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+         dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
+         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+             dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+         fi
       fi
       tristate '  EQL (serial line load balancing) support' CONFIG_EQUALIZER
       if [ "$CONFIG_ZORRO" = "y" ]; then
@@ -335,7 +349,7 @@
          if [  "$CONFIG_PARPORT" != "n" ]; then
 	    dep_tristate '  PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 	 fi
-         tristate 'NE2000/NE1000 support' CONFIG_NE2000
+         dep_tristate 'NE2000/NE1000 support' CONFIG_NE2000 m
       fi
    fi
    endmenu
@@ -350,7 +364,6 @@
 fi
 
 if [ "$CONFIG_SERIAL" = "y" ]; then
-   bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
    bool '  Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
 fi
 
@@ -460,7 +473,8 @@
         "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
         "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
         "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-        "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
+        "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" -o \
+        "$CONFIG_SERIAL" = "y" ]; then
       bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
    fi
 fi
@@ -495,7 +509,7 @@
    if [ "$CONFIG_SUN3" = "y" ]; then
       define_bool CONFIG_GEN_RTC y
    else
-      bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+      tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
    fi
 fi
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
@@ -526,8 +540,13 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Verbose BUG() reporting' CONFIG_DEBUG_BUGVERBOSE
+fi
+
 endmenu
 
 source lib/Config.in
diff -Nru a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
--- a/arch/m68k/hp300/config.c	Thu May  9 15:21:02 2002
+++ b/arch/m68k/hp300/config.c	Thu May  9 15:21:02 2002
@@ -73,9 +73,6 @@
   mach_get_irq_list    = show_hp300_interrupts;
   mach_gettimeoffset   = hp300_gettimeoffset;
   mach_default_handler = &hp300_default_handler;
-#if 0
-  mach_gettod          = hp300_gettod;
-#endif
   mach_reset           = hp300_reset;
 #ifdef CONFIG_HEARTBEAT
   mach_heartbeat       = hp300_pulse;
diff -Nru a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
--- a/arch/m68k/hp300/time.c	Thu May  9 15:21:09 2002
+++ b/arch/m68k/hp300/time.c	Thu May  9 15:21:09 2002
@@ -41,7 +41,7 @@
   unsigned long tmp;
   void (*vector)(int, void *, struct pt_regs *) = dev_id;
   readb(CLOCKBASE + CLKSR);
-  asm volatile ("movpw %1@(5),%0" : "=r" (tmp) : "a" (CLOCKBASE));
+  asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
   vector(irq, NULL, regs);
 }
 
diff -Nru a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
--- a/arch/m68k/kernel/head.S	Thu May  9 15:21:07 2002
+++ b/arch/m68k/kernel/head.S	Thu May  9 15:21:07 2002
@@ -2764,22 +2764,6 @@
 LSCC_CTRL	= 0xff8c81
 LSCC_DATA	= 0xff8c83
 
-/* Initialisation table for SCC */
-L(scc_initable):
-	.byte	9,12		/* Reset */
-	.byte	4,0x44		/* x16, 1 stopbit, no parity */
-	.byte	3,0xc0		/* receiver: 8 bpc */
-	.byte	5,0xe2		/* transmitter: 8 bpc, assert dtr/rts */
-	.byte	9,0		/* no interrupts */
-	.byte	10,0		/* NRZ */
-	.byte	11,0x50		/* use baud rate generator */
-	.byte	12,24,13,0	/* 9600 baud */
-	.byte	14,2,14,3	/* use master clock for BRG, enable */
-	.byte	3,0xc1		/* enable receiver */
-	.byte	5,0xea		/* enable transmitter */
-	.byte	-1
-	.even
-
 #elif defined(USE_MFP)
 
 LMFP_UCR     = 0xfffa29
diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
--- a/arch/m68k/kernel/process.c	Thu May  9 15:21:07 2002
+++ b/arch/m68k/kernel/process.c	Thu May  9 15:21:07 2002
@@ -44,7 +44,7 @@
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 union task_union init_task_union
-__attribute__((section("init_task"), aligned(KTHREAD_SIZE)))
+__attribute__((section("init_task"), aligned(THREAD_SIZE)))
 	= { task: INIT_TASK(init_task_union.task) };
 
 asmlinkage void ret_from_fork(void);
@@ -53,19 +53,15 @@
 /*
  * The idle loop on an m68k..
  */
-static void default_idle(void)
+void default_idle(void)
 {
-	while(1) {
-		if (!need_resched())
+	if (!need_resched())
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
-			/* block out HSYNC on the atari (falcon) */
-			__asm__("stop #0x2200" : : : "cc");
+		/* block out HSYNC on the atari (falcon) */
+		__asm__("stop #0x2200" : : : "cc");
 #else
-			__asm__("stop #0x2000" : : : "cc");
+		__asm__("stop #0x2000" : : : "cc");
 #endif
-		schedule();
-		check_pgt_cache();
-	}
 }
 
 void (*idle)(void) = default_idle;
@@ -79,9 +75,11 @@
 void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
-	init_idle();
-	current->nice = 20;
-	idle();
+	while (1) {
+		while (!need_resched())
+			idle();
+		schedule();
+	}
 }
 
 void machine_restart(char * __unused)
@@ -150,7 +148,7 @@
 	   : "=d" (retval)
 	   : "0" (__NR_clone), "i" (__NR_exit),
 	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
-	     "i" (-KTHREAD_SIZE)
+	     "i" (-THREAD_SIZE)
 	   : "d0", "d2");
 	pid = retval;
 	}
@@ -208,8 +206,8 @@
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset, *retp;
 
-	stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs);
-	childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
+	stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
+	childregs = (struct pt_regs *) ((unsigned long) (p->thread_info) + stack_offset);
 
 	*childregs = *regs;
 	childregs->d0 = 0;
diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
--- a/arch/m68k/kernel/ptrace.c	Thu May  9 15:21:04 2002
+++ b/arch/m68k/kernel/ptrace.c	Thu May  9 15:21:04 2002
@@ -141,7 +141,7 @@
 		if (request != PTRACE_KILL)
 			goto out_tsk;
 	}
-	if (child->p_pptr != current)
+	if (child->parent != current)
 		goto out_tsk;
 
 	switch (request) {
diff -Nru a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
--- a/arch/m68k/kernel/setup.c	Thu May  9 15:21:09 2002
+++ b/arch/m68k/kernel/setup.c	Thu May  9 15:21:09 2002
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/seq_file.h>
 #include <linux/module.h>
 
 #include <asm/bootinfo.h>
@@ -84,8 +85,7 @@
 void (*mach_process_int) (int, struct pt_regs *) = NULL;
 /* machine dependent timer functions */
 unsigned long (*mach_gettimeoffset) (void);
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
-int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
+int (*mach_hwclk) (int, struct rtc_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
 void (*mach_halt)( void ) = NULL;
@@ -407,7 +407,7 @@
 #endif
 }
 
-int get_cpuinfo(char * buffer)
+static int show_cpuinfo(struct seq_file *m, void *v)
 {
     const char *cpu, *mmu, *fpu;
     unsigned long clockfreq, clockfactor;
@@ -468,7 +468,7 @@
 
     clockfreq = loops_per_jiffy*HZ*clockfactor;
 
-    return(sprintf(buffer, "CPU:\t\t%s\n"
+    seq_printf(m, "CPU:\t\t%s\n"
 		   "MMU:\t\t%s\n"
 		   "FPU:\t\t%s\n"
 		   "Clocking:\t%lu.%1luMHz\n"
@@ -477,9 +477,28 @@
 		   cpu, mmu, fpu,
 		   clockfreq/1000000,(clockfreq/100000)%10,
 		   loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
-		   loops_per_jiffy));
+		   loops_per_jiffy);
+    return 0;
+}
 
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < 1 ? (void *)1 : NULL;
 }
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
 
 int get_hardware_list(char *buffer)
 {
@@ -518,15 +537,6 @@
 /* for "kbd-reset" cmdline param */
 void __init kbd_reset_setup(char *str, int *ints)
 {
-}
-
-void arch_gettod(int *year, int *mon, int *day, int *hour,
-		 int *min, int *sec)
-{
-	if (mach_gettod)
-		mach_gettod(year, mon, day, hour, min, sec);
-	else
-		*year = *mon = *day = *hour = *min = *sec = 0;
 }
 
 void check_bugs(void)
diff -Nru a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
--- a/arch/m68k/kernel/signal.c	Thu May  9 15:21:03 2002
+++ b/arch/m68k/kernel/signal.c	Thu May  9 15:21:03 2002
@@ -38,6 +38,9 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/highuid.h>
+#include <linux/personality.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -1080,9 +1083,9 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
-				info.si_uid16 = high2lowuid(current->p_pptr->uid);
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
+				info.si_uid16 = high2lowuid(current->parent->uid);
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -1118,14 +1121,17 @@
 					continue;
 				/* FALLTHRU */
 
-			case SIGSTOP:
+			case SIGSTOP: {
+				struct signal_struct *sig;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1]
-				      .sa.sa_flags & SA_NOCLDSTOP))
+				sig = current->parent->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags 
+					     & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGIOT: case SIGFPE: case SIGSEGV:
diff -Nru a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
--- a/arch/m68k/kernel/sun3-head.S	Thu May  9 15:21:00 2002
+++ b/arch/m68k/kernel/sun3-head.S	Thu May  9 15:21:00 2002
@@ -1,5 +1,6 @@
 #include <linux/linkage.h>
 
+#include <asm/entry.h>
 #include <asm/page.h>
 #include <asm/contregs.h>
 #include <asm/sun3-head.h>
@@ -69,8 +70,8 @@
 	jmp	1f:l		
 
 /* Following code executes at high addresses (0xE000xxx). */
-1:	lea	init_task_union,%a2			| get initial thread...
-	lea	%a2@(KTHREAD_SIZE),%sp			| ...and its stack.
+1:	lea	init_task,%curptr			| get initial thread...
+	lea	init_thread_union+THREAD_SIZE,%sp	| ...and its stack.
 
 /* copy bootinfo records from the loader to _end */
 	lea	_end, %a1
diff -Nru a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
--- a/arch/m68k/kernel/time.c	Thu May  9 15:21:04 2002
+++ b/arch/m68k/kernel/time.c	Thu May  9 15:21:04 2002
@@ -17,6 +17,7 @@
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/rtc.h>
 
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -104,17 +105,17 @@
 
 void time_init(void)
 {
-	unsigned int year, mon, day, hour, min, sec;
+	struct rtc_time time;
 
-	extern void arch_gettod(int *year, int *mon, int *day, int *hour,
-				int *min, int *sec);
+	if (mach_hwclk) {
+		mach_hwclk(0, &time);
 
-	arch_gettod (&year, &mon, &day, &hour, &min, &sec);
-
-	if ((year += 1900) < 1970)
-		year += 100;
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+		if ((time.tm_year += 1900) < 1970)
+			time.tm_year += 100;
+		xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
+				      time.tm_hour, time.tm_min, time.tm_sec);
+		xtime.tv_usec = 0;
+	}
 
 	mach_sched_init(timer_interrupt);
 }
diff -Nru a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
--- a/arch/m68k/kernel/traps.c	Thu May  9 15:21:07 2002
+++ b/arch/m68k/kernel/traps.c	Thu May  9 15:21:07 2002
@@ -23,7 +23,7 @@
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/types.h>
+#include <linux/module.h>
 #include <linux/a.out.h>
 #include <linux/user.h>
 #include <linux/string.h>
@@ -816,15 +816,71 @@
 
 
 int kstack_depth_to_print = 48;
+extern struct module kernel_module;
 
-/* MODULE_RANGE is a guess of how much space is likely to be
-   vmalloced.  */
-#define MODULE_RANGE (8*1024*1024)
+static inline int kernel_text_address(unsigned long addr)
+{
+	struct module *mod;
+	int retval = 0;
+	extern char _stext, _etext;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+#ifdef CONFIG_MODULES
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+#endif
+
+	return retval;
+}
+
+void show_trace(unsigned long *stack)
+{
+	unsigned long *endstack;
+	unsigned long addr;
+	int i;
+
+	printk("Call Trace:");
+	addr = (unsigned long)stack + THREAD_SIZE - 1;
+	endstack = (unsigned long *)(addr & -THREAD_SIZE);
+	i = 0;
+	while (stack + 1 <= endstack) {
+		addr = *stack++;
+		/*
+		 * If the address is either in the text segment of the
+		 * kernel, or in the region which contains vmalloc'ed
+		 * memory, it *may* be the address of a calling
+		 * routine; if so, print it so that someone tracing
+		 * down the cause of the crash will be able to figure
+		 * out the call path that was taken.
+		 */
+		if (kernel_text_address(addr)) {
+			if (i % 4 == 0)
+				printk("\n       ");
+			printk(" [<%08lx>]", addr);
+			i++;
+		}
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	show_trace((unsigned long *)tsk->thread.esp0);
+}
 
 static void dump_stack(struct frame *fp)
 {
-	unsigned long *stack, *endstack, addr, module_start, module_end;
-	extern char _start, _etext;
+	unsigned long *stack, *endstack, addr;
 	int i;
 
 	addr = (unsigned long)&fp->un;
@@ -881,7 +937,7 @@
 	}
 
 	stack = (unsigned long *)addr;
-	endstack = (unsigned long *)PAGE_ALIGN(addr);
+	endstack = (unsigned long *)((addr + THREAD_SIZE - 1) & -THREAD_SIZE);
 
 	printk("Stack from %08lx:", (unsigned long)stack);
 	for (i = 0; i < kstack_depth_to_print; i++) {
@@ -891,32 +947,10 @@
 			printk("\n       ");
 		printk(" %08lx", *stack++);
 	}
+	printk("\n");
+	show_trace((unsigned long *)addr);
 
-	printk ("\nCall Trace:");
-	stack = (unsigned long *) addr;
-	i = 0;
-	module_start = VMALLOC_START;
-	module_end = module_start + MODULE_RANGE;
-	while (stack + 1 <= endstack) {
-		addr = *stack++;
-		/*
-		 * If the address is either in the text segment of the
-		 * kernel, or in the region which contains vmalloc'ed
-		 * memory, it *may* be the address of a calling
-		 * routine; if so, print it so that someone tracing
-		 * down the cause of the crash will be able to figure
-		 * out the call path that was taken.
-		 */
-		if (((addr >= (unsigned long) &_start) &&
-		     (addr <= (unsigned long) &_etext)) ||
-		    ((addr >= module_start) && (addr <= module_end))) {
-			if (i % 4 == 0)
-				printk("\n       ");
-			printk(" [<%08lx>]", addr);
-			i++;
-		}
-	}
-	printk("\nCode: ");
+	printk("Code: ");
 	for (i = 0; i < 10; i++)
 		printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
 	printk ("\n");
diff -Nru a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
--- a/arch/m68k/mac/config.c	Thu May  9 15:21:06 2002
+++ b/arch/m68k/mac/config.c	Thu May  9 15:21:06 2002
@@ -62,9 +62,8 @@
 unsigned long mac_orig_videoaddr;
 
 /* Mac specific timer functions */
-extern void mac_gettod (int *, int *, int *, int *, int *, int *);
 extern unsigned long mac_gettimeoffset (void);
-extern int mac_hwclk (int, struct hwclk_time *);
+extern int mac_hwclk (int, struct rtc_time *);
 extern int mac_set_clock_mmss (unsigned long);
 extern int show_mac_interrupts(struct seq_file *, void *);
 extern void iop_preinit(void);
@@ -243,8 +242,10 @@
 	mach_default_handler = &mac_handlers;
 	mach_get_irq_list    = show_mac_interrupts;
 	mach_gettimeoffset   = mac_gettimeoffset;
-	mach_gettod          = mac_gettod;
+#warning move to adb/via init
+#if 0
 	mach_hwclk           = mac_hwclk;
+#endif
 	mach_set_clock_mmss	 = mac_set_clock_mmss;
 #if 0
 	mach_mksound         = mac_mksound;
diff -Nru a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
--- a/arch/m68k/mac/misc.c	Thu May  9 15:21:07 2002
+++ b/arch/m68k/mac/misc.c	Thu May  9 15:21:07 2002
@@ -11,7 +11,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-
+#include <linux/rtc.h>
 #include <linux/mm.h>
 
 #include <linux/adb.h>
@@ -571,31 +571,11 @@
 	return;
 }
 
-/*
- * Return the boot time for use in initializing the kernel clock.
- *
- * I'd like to read the hardware clock here but many machines read
- * the PRAM through ADB, and interrupts aren't initialized when this
- * is called so ADB obviously won't work.
- */
-
-void mac_gettod(int *yearp, int *monp, int *dayp,
-	       int *hourp, int *minp, int *secp)
-{
-	/* Yes the GMT bias is backwards.  It looks like Penguin is
-           screwing up the boottime it gives us... This works for me
-           in Canada/Eastern but it might be wrong everywhere else. */
-	unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60,
-		yearp, monp, dayp, hourp, minp, secp);
-	/* For some reason this is off by one */
-	*monp = *monp + 1;
-}
-
 /* 
  * Read/write the hardware clock.
  */
 
-int mac_hwclk(int op, struct hwclk_time *t)
+int mac_hwclk(int op, struct rtc_time *t)
 {
 	unsigned long now;
 
@@ -613,19 +593,19 @@
 			now = 0;
 		}
 
-		t->wday = 0;
+		t->tm_wday = 0;
 		unmktime(now, 0,
-			 &t->year, &t->mon, &t->day,
-			 &t->hour, &t->min, &t->sec);
+			 &t->tm_year, &t->tm_mon, &t->tm_mday,
+			 &t->tm_hour, &t->tm_min, &t->tm_sec);
 		printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n",
-			t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec);
+			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
 	} else { /* write */
 		printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
-			t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec);
+			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
 
 #if 0	/* it trashes my rtc */
-		now = mktime(t->year + 1900, t->mon + 1, t->day,
-			     t->hour, t->min, t->sec);
+		now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+			     t->tm_hour, t->tm_min, t->tm_sec);
 
 		if (macintosh_config->adb_type == MAC_ADB_II) {
 			via_write_time(now);
@@ -648,11 +628,11 @@
 
 int mac_set_clock_mmss (unsigned long nowtime)
 {
-	struct hwclk_time now;
+	struct rtc_time now;
 
 	mac_hwclk(0, &now);
-	now.sec = nowtime % 60;
-	now.min = (nowtime / 60) % 60;
+	now.tm_sec = nowtime % 60;
+	now.tm_min = (nowtime / 60) % 60;
 	mac_hwclk(1, &now);
 
 	return 0;
diff -Nru a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h
--- a/arch/m68k/math-emu/fp_emu.h	Thu May  9 15:21:01 2002
+++ b/arch/m68k/math-emu/fp_emu.h	Thu May  9 15:21:01 2002
@@ -38,7 +38,9 @@
 #ifndef _FP_EMU_H
 #define _FP_EMU_H
 
+#ifdef __ASSEMBLY__
 #include "../kernel/m68k_defs.h"
+#endif
 #include <asm/math-emu.h>
 
 #ifndef __ASSEMBLY__
diff -Nru a/arch/m68k/math-emu/multi_arith.h b/arch/m68k/math-emu/multi_arith.h
--- a/arch/m68k/math-emu/multi_arith.h	Thu May  9 15:21:06 2002
+++ b/arch/m68k/math-emu/multi_arith.h	Thu May  9 15:21:06 2002
@@ -376,7 +376,7 @@
 	asm ("divu.l %2,%1:%0" : "=d" (quot), "=d" (rem)		\
 		: "dm" (div), "1" (srch), "0" (srcl))
 #define fp_add64(dest1, dest2, src1, src2) ({				\
-	asm ("add.l %1,%0" : "=d,=dm" (dest2)				\
+	asm ("add.l %1,%0" : "=d,dm" (dest2)				\
 		: "dm,d" (src2), "0,0" (dest2));			\
 	asm ("addx.l %1,%0" : "=d" (dest1)				\
 		: "d" (src1), "0" (dest1));				\
@@ -391,14 +391,14 @@
 		: "d" (0), "0" (dest->m32[0]));				\
 })
 #define fp_sub64(dest, src) ({						\
-	asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[1])			\
+	asm ("sub.l %1,%0" : "=d,dm" (dest.m32[1])			\
 		: "dm,d" (src.m32[1]), "0,0" (dest.m32[1]));		\
 	asm ("subx.l %1,%0" : "=d" (dest.m32[0])			\
 		: "d" (src.m32[0]), "0" (dest.m32[0]));			\
 })
 #define fp_sub96c(dest, srch, srcm, srcl) ({				\
 	char carry;							\
-	asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[2])			\
+	asm ("sub.l %1,%0" : "=d,dm" (dest.m32[2])			\
 		: "dm,d" (srcl), "0,0" (dest.m32[2]));			\
 	asm ("subx.l %1,%0" : "=d" (dest.m32[1])			\
 		: "d" (srcm), "0" (dest.m32[1]));			\
diff -Nru a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
--- a/arch/m68k/mvme147/config.c	Thu May  9 15:21:04 2002
+++ b/arch/m68k/mvme147/config.c	Thu May  9 15:21:04 2002
@@ -46,9 +46,7 @@
 extern int mvme147_keyb_init(void);
 extern int mvme147_kbdrate (struct kbd_repeat *);
 extern unsigned long mvme147_gettimeoffset (void);
-extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec);
-extern int mvme147_hwclk (int, struct hwclk_time *);
+extern int mvme147_hwclk (int, struct rtc_time *);
 extern int mvme147_set_clock_mmss (unsigned long);
 extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev);
 extern void mvme147_reset (void);
@@ -107,7 +105,6 @@
 	mach_kbdrate		= mvme147_kbdrate;
 	mach_init_IRQ		= mvme147_init_IRQ;
 	mach_gettimeoffset	= mvme147_gettimeoffset;
-	mach_gettod		= mvme147_gettod;
 	mach_hwclk		= mvme147_hwclk;
 	mach_set_clock_mmss	= mvme147_set_clock_mmss;
 	mach_reset		= mvme147_reset;
@@ -166,26 +163,24 @@
 	return (unsigned long)n * 25 / 4;
 }
 
-extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec)
-{
-	m147_rtc->ctrl = RTC_READ;
-	*year = bcd2int (m147_rtc->bcd_year);
-	*mon = bcd2int (m147_rtc->bcd_mth);
-	*day = bcd2int (m147_rtc->bcd_dom);
-	*hour = bcd2int (m147_rtc->bcd_hr);
-	*min = bcd2int (m147_rtc->bcd_min);
-	*sec = bcd2int (m147_rtc->bcd_sec);
-	m147_rtc->ctrl = 0;
-}
-
 static int bcd2int (unsigned char b)
 {
 	return ((b>>4)*10 + (b&15));
 }
 
-int mvme147_hwclk(int op, struct hwclk_time *t)
+int mvme147_hwclk(int op, struct rtc_time *t)
 {
+#warning check me!
+	if (!op) {
+		m147_rtc->ctrl = RTC_READ;
+		t->tm_year = bcd2int (m147_rtc->bcd_year);
+		t->tm_mon  = bcd2int (m147_rtc->bcd_mth);
+		t->tm_mday = bcd2int (m147_rtc->bcd_dom);
+		t->tm_hour = bcd2int (m147_rtc->bcd_hr);
+		t->tm_min  = bcd2int (m147_rtc->bcd_min);
+		t->tm_sec  = bcd2int (m147_rtc->bcd_sec);
+		m147_rtc->ctrl = 0;
+	}
 	return 0;
 }
 
diff -Nru a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
--- a/arch/m68k/mvme16x/config.c	Thu May  9 15:21:05 2002
+++ b/arch/m68k/mvme16x/config.c	Thu May  9 15:21:05 2002
@@ -50,9 +50,7 @@
 extern int  mvme16x_keyb_init(void);
 extern int  mvme16x_kbdrate (struct kbd_repeat *);
 extern unsigned long mvme16x_gettimeoffset (void);
-extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec);
-extern int mvme16x_hwclk (int, struct hwclk_time *);
+extern int mvme16x_hwclk (int, struct rtc_time *);
 extern int mvme16x_set_clock_mmss (unsigned long);
 extern void mvme16x_check_partition (struct gendisk *hd, unsigned int dev);
 extern void mvme16x_mksound( unsigned int count, unsigned int ticks );
@@ -149,7 +147,6 @@
     mach_kbdrate         = mvme16x_kbdrate;
     mach_init_IRQ        = mvme16x_init_IRQ;
     mach_gettimeoffset   = mvme16x_gettimeoffset;
-    mach_gettod  	 = mvme16x_gettod;
     mach_hwclk           = mvme16x_hwclk;
     mach_set_clock_mmss	 = mvme16x_set_clock_mmss;
 /*  kd_mksound           = mvme16x_mksound; */
@@ -273,26 +270,24 @@
     return (*(volatile unsigned long *)0xfff42008);
 }
 
-extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec)
-{
-	rtc->ctrl = RTC_READ;
-	*year = bcd2int (rtc->bcd_year);
-	*mon = bcd2int (rtc->bcd_mth);
-	*day = bcd2int (rtc->bcd_dom);
-	*hour = bcd2int (rtc->bcd_hr);
-	*min = bcd2int (rtc->bcd_min);
-	*sec = bcd2int (rtc->bcd_sec);
-	rtc->ctrl = 0;
-}
-
 int bcd2int (unsigned char b)
 {
 	return ((b>>4)*10 + (b&15));
 }
 
-int mvme16x_hwclk(int op, struct hwclk_time *t)
+int mvme16x_hwclk(int op, struct rtc_time *t)
 {
+#warning check me!
+	if (!op) {
+		rtc->ctrl = RTC_READ;
+		t->tm_year = bcd2int (rtc->bcd_year);
+		t->tm_mon  = bcd2int (rtc->bcd_mth);
+		t->tm_mday = bcd2int (rtc->bcd_dom);
+		t->tm_hour = bcd2int (rtc->bcd_hr);
+		t->tm_min  = bcd2int (rtc->bcd_min);
+		t->tm_sec  = bcd2int (rtc->bcd_sec);
+		rtc->ctrl = 0;
+	}
 	return 0;
 }
 
diff -Nru a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
--- a/arch/m68k/q40/config.c	Thu May  9 15:21:07 2002
+++ b/arch/m68k/q40/config.c	Thu May  9 15:21:07 2002
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/major.h>
 #include <linux/serial_reg.h>
+#include <linux/rtc.h>
 
 #include <asm/io.h>
 #include <asm/rtc.h>
@@ -53,9 +54,7 @@
 extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
 
 extern unsigned long q40_gettimeoffset (void);
-extern void q40_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec);
-extern int q40_hwclk (int, struct hwclk_time *);
+extern int q40_hwclk (int, struct rtc_time *);
 extern int q40_set_clock_mmss (unsigned long);
 extern void q40_reset (void);
 void q40_halt(void);
@@ -226,7 +225,6 @@
     mach_kbd_translate   = q40kbd_translate;
     mach_init_IRQ        = q40_init_IRQ;   
     mach_gettimeoffset   = q40_gettimeoffset; 
-    mach_gettod  	 = q40_gettod;
     mach_hwclk           = q40_hwclk; 
     mach_set_clock_mmss	 = q40_set_clock_mmss;
 
@@ -292,21 +290,6 @@
     return 5000*(ql_ticks!=0);
 }
 
-extern void q40_gettod (int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec)
-{
-	RTC_CTRL |= RTC_READ;
-	*year = bcd2bin (RTC_YEAR);
-	*mon = bcd2bin (RTC_MNTH);
-	*day = bcd2bin (RTC_DATE);
-	*hour = bcd2bin (RTC_HOUR);
-	*min = bcd2bin (RTC_MINS);
-	*sec = bcd2bin (RTC_SECS);
-	RTC_CTRL &= ~(RTC_READ);
-
-}
-
-
 
 /*
  * Looks like op is non-zero for setting the clock, and zero for
@@ -323,39 +306,39 @@
  * };
  */
 
-int q40_hwclk(int op, struct hwclk_time *t)
+int q40_hwclk(int op, struct rtc_time *t)
 {
         if (op)
 	{	/* Write.... */
-	        RTC_CTRL |= RTC_WRITE;
+	        Q40_RTC_CTRL |= Q40_RTC_WRITE;
 
-		RTC_SECS = bin2bcd(t->sec);
-		RTC_MINS = bin2bcd(t->min);
-		RTC_HOUR = bin2bcd(t->hour);
-		RTC_DATE = bin2bcd(t->day);
-		RTC_MNTH = bin2bcd(t->mon + 1);
-		RTC_YEAR = bin2bcd(t->year%100);
-		if (t->wday >= 0)
-			RTC_DOW = bin2bcd(t->wday+1);
+		Q40_RTC_SECS = bin2bcd(t->tm_sec);
+		Q40_RTC_MINS = bin2bcd(t->tm_min);
+		Q40_RTC_HOUR = bin2bcd(t->tm_hour);
+		Q40_RTC_DATE = bin2bcd(t->tm_mday);
+		Q40_RTC_MNTH = bin2bcd(t->tm_mon + 1);
+		Q40_RTC_YEAR = bin2bcd(t->tm_year%100);
+		if (t->tm_wday >= 0)
+			Q40_RTC_DOW = bin2bcd(t->tm_wday+1);
 
-	        RTC_CTRL &= ~(RTC_WRITE);
+	        Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
 	}
 	else
 	{	/* Read....  */
-	  RTC_CTRL |= RTC_READ;
+	  Q40_RTC_CTRL |= Q40_RTC_READ;
 
-	  t->year = bcd2bin (RTC_YEAR);
-	  t->mon  = bcd2bin (RTC_MNTH)-1;
-	  t->day  = bcd2bin (RTC_DATE);
-	  t->hour = bcd2bin (RTC_HOUR);
-	  t->min  = bcd2bin (RTC_MINS);
-	  t->sec  = bcd2bin (RTC_SECS);
+	  t->tm_year = bcd2bin (Q40_RTC_YEAR);
+	  t->tm_mon  = bcd2bin (Q40_RTC_MNTH)-1;
+	  t->tm_mday = bcd2bin (Q40_RTC_DATE);
+	  t->tm_hour = bcd2bin (Q40_RTC_HOUR);
+	  t->tm_min  = bcd2bin (Q40_RTC_MINS);
+	  t->tm_sec  = bcd2bin (Q40_RTC_SECS);
 
-	  RTC_CTRL &= ~(RTC_READ);
+	  Q40_RTC_CTRL &= ~(Q40_RTC_READ);
 	  
-	  if (t->year < 70)
-	    t->year += 100;
-	  t->wday = bcd2bin(RTC_DOW)-1;
+	  if (t->tm_year < 70)
+	    t->tm_year += 100;
+	  t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
 
 	}
 
@@ -375,16 +358,16 @@
 	int rtc_minutes;
 
 
-	rtc_minutes = bcd2bin (RTC_MINS);
+	rtc_minutes = bcd2bin (Q40_RTC_MINS);
 
 	if ((rtc_minutes < real_minutes
 		? real_minutes - rtc_minutes
 			: rtc_minutes - real_minutes) < 30)
 	{	   
-	        RTC_CTRL |= RTC_WRITE;
-		RTC_MINS = bin2bcd(real_minutes);
-		RTC_SECS = bin2bcd(real_seconds);
-		RTC_CTRL &= ~(RTC_WRITE);
+	        Q40_RTC_CTRL |= Q40_RTC_WRITE;
+		Q40_RTC_MINS = bin2bcd(real_minutes);
+		Q40_RTC_SECS = bin2bcd(real_seconds);
+		Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
 	}
 	else
 		retval = -1;
diff -Nru a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
--- a/arch/m68k/sun3/config.c	Thu May  9 15:21:08 2002
+++ b/arch/m68k/sun3/config.c	Thu May  9 15:21:08 2002
@@ -36,13 +36,11 @@
 char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
 
 extern unsigned long sun3_gettimeoffset(void);
-extern int show_sun3_interrupts (char *);
+extern int show_sun3_interrupts (struct seq_file *, void *);
 extern void sun3_sched_init(void (*handler)(int, void *, struct pt_regs *));
 extern void sun3_get_model (char* model);
 extern void idprom_init (void);
-extern void sun3_gettod (int *yearp, int *monp, int *dayp,
-                   int *hourp, int *minp, int *secp);
-extern int sun3_hwclk(int set, struct hwclk_time *t);
+extern int sun3_hwclk(int set, struct rtc_time *t);
 
 extern void sun_serial_setup(void);
 volatile char* clock_va; 
@@ -50,6 +48,18 @@
 extern unsigned long availmem;
 unsigned long num_pages;
 
+static int sun3_get_hardware_list(char *buffer)
+{
+	
+	int len = 0;
+
+	len += sprintf(buffer + len, "PROM Revision:\t%s\n",
+		       romvec->pv_monid);
+	
+	return len;
+
+}
+
 void __init sun3_init(void)
 {
 	unsigned char enable_register;
@@ -146,12 +156,12 @@
         disable_irq  	     =  sun3_disable_irq;
 	mach_process_int     =  sun3_process_int;
         mach_get_irq_list    =  show_sun3_interrupts;
-        mach_gettod          =  sun3_gettod;	
         mach_reset           =  sun3_reboot;
 	mach_gettimeoffset   =  sun3_gettimeoffset;
 	mach_get_model	     =  sun3_get_model;
 	mach_hwclk           =  sun3_hwclk;
 	mach_halt	     =  sun3_halt;
+	mach_get_hardware_list = sun3_get_hardware_list;
 #if !defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_FB)
 	conswitchp 	     = &dummy_con;
 #endif
@@ -166,7 +176,6 @@
 	sun3_bootmem_alloc(memory_start, memory_end);
 
 	sun_serial_setup();
-
 
 }
 
diff -Nru a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
--- a/arch/m68k/sun3/intersil.c	Thu May  9 15:21:01 2002
+++ b/arch/m68k/sun3/intersil.c	Thu May  9 15:21:01 2002
@@ -11,8 +11,10 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/rtc.h>
 
 #include <asm/system.h>
+#include <asm/semaphore.h>
 #include <asm/rtc.h>
 #include <asm/intersil.h>
 
@@ -27,37 +29,10 @@
   return 1;
 }
 
-void sun3_gettod (int *yearp, int *monp, int *dayp,
-                   int *hourp, int *minp, int *secp)
-{
-	unsigned char wday;
-	volatile struct intersil_dt* todintersil;
-	unsigned long flags;
-
-        todintersil = (struct intersil_dt *) &intersil_clock->counter;
-
-	save_and_cli(flags);
-
-	intersil_clock->cmd_reg = STOP_VAL;
-
-	*secp  = todintersil->csec;
-        *hourp = todintersil->hour;
-        *minp  = todintersil->minute;
-        *secp  = todintersil->second; 
-        *monp  = todintersil->month;
-        *dayp  = todintersil->day;
-        *yearp = todintersil->year+68; /* The base year for sun3 is 1968 */
-	wday = todintersil->weekday;
-
-	intersil_clock->cmd_reg = START_VAL;
-
-	restore_flags(flags);
-}
-
 
 /* get/set hwclock */
 
-int sun3_hwclk(int set, struct hwclk_time *t)
+int sun3_hwclk(int set, struct rtc_time *t)
 {
 	volatile struct intersil_dt *todintersil;
 	unsigned long flags;
@@ -71,23 +46,23 @@
 	/* set or read the clock */
 	if(set) {
 		todintersil->csec = 0;
-		todintersil->hour = t->hour;
-		todintersil->minute = t->min;
-		todintersil->second = t->sec;
-		todintersil->month = t->mon;
-		todintersil->day = t->day;
-		todintersil->year = t->year - 68;
-		todintersil->weekday = t->wday;
+		todintersil->hour = t->tm_hour;
+		todintersil->minute = t->tm_min;
+		todintersil->second = t->tm_sec;
+		todintersil->month = t->tm_mon;
+		todintersil->day = t->tm_mday;
+		todintersil->year = t->tm_year - 68;
+		todintersil->weekday = t->tm_wday;
 	} else {
 		/* read clock */
-		t->sec = todintersil->csec;
-		t->hour = todintersil->hour;
-		t->min = todintersil->minute;
-		t->sec = todintersil->second;
-		t->mon = todintersil->month;
-		t->day = todintersil->day;
-		t->year = todintersil->year + 68;
-		t->wday = todintersil->weekday;
+		t->tm_sec = todintersil->csec;
+		t->tm_hour = todintersil->hour;
+		t->tm_min = todintersil->minute;
+		t->tm_sec = todintersil->second;
+		t->tm_mon = todintersil->month;
+		t->tm_mday = todintersil->day;
+		t->tm_year = todintersil->year + 68;
+		t->tm_wday = todintersil->weekday;
 	}
 
 	intersil_clock->cmd_reg = START_VAL;
diff -Nru a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
--- a/arch/m68k/sun3x/config.c	Thu May  9 15:21:01 2002
+++ b/arch/m68k/sun3x/config.c	Thu May  9 15:21:01 2002
@@ -77,9 +77,9 @@
 	mach_gettimeoffset   = sun3x_gettimeoffset;
 	mach_reset           = sun3x_reboot;
 
-	mach_gettod          = sun3x_gettod;
 	mach_hwclk           = sun3x_hwclk;
-	mach_get_model       = sun3x_get_model;
+	mach_get_model       = sun3_get_model;
+	mach_get_hardware_list = sun3x_get_hardware_list;
 
 	sun3_intreg = (unsigned char *)SUN3X_INTREG;
 
diff -Nru a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
--- a/arch/m68k/sun3x/time.c	Thu May  9 15:21:08 2002
+++ b/arch/m68k/sun3x/time.c	Thu May  9 15:21:08 2002
@@ -10,6 +10,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
+#include <linux/rtc.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -38,54 +39,33 @@
 #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
 #define BIN_TO_BCD(val) (((val/10) << 4) | (val % 10))
 
-/* Read the Mostek */
-void sun3x_gettod (int *yearp, int *monp, int *dayp,
-                   int *hourp, int *minp, int *secp)
-{
-    volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM;
-
-    /* Stop updates */
-    *(eeprom + M_CONTROL) |= C_READ;
-
-    /* Read values */
-    *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
-    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH)) +1;
-    *dayp  = BCD_TO_BIN(*(eeprom + M_DATE));
-    *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
-    *minp  = BCD_TO_BIN(*(eeprom + M_MIN));
-    *secp  = BCD_TO_BIN(*(eeprom + M_SEC));
-
-    /* Restart updates */
-    *(eeprom + M_CONTROL) &= ~C_READ;
-}
-
-int sun3x_hwclk(int set, struct hwclk_time *t)
+int sun3x_hwclk(int set, struct rtc_time *t)
 {
 	volatile struct mostek_dt *h = 
-		(unsigned char *)(SUN3X_EEPROM+M_CONTROL);
+		(struct mostek_dt *)(SUN3X_EEPROM+M_CONTROL);
 	unsigned long flags;
 
 	save_and_cli(flags);
 	
 	if(set) {
 		h->csr |= C_WRITE;
-		h->sec = BIN_TO_BCD(t->sec);
-		h->min = BIN_TO_BCD(t->min);
-		h->hour = BIN_TO_BCD(t->hour);
-		h->wday = BIN_TO_BCD(t->wday);
-		h->mday = BIN_TO_BCD(t->day);
-		h->month = BIN_TO_BCD(t->mon);
-		h->year = BIN_TO_BCD(t->year);
+		h->sec = BIN_TO_BCD(t->tm_sec);
+		h->min = BIN_TO_BCD(t->tm_min);
+		h->hour = BIN_TO_BCD(t->tm_hour);
+		h->wday = BIN_TO_BCD(t->tm_wday);
+		h->mday = BIN_TO_BCD(t->tm_mday);
+		h->month = BIN_TO_BCD(t->tm_mon);
+		h->year = BIN_TO_BCD(t->tm_year);
 		h->csr &= ~C_WRITE;
 	} else {
 		h->csr |= C_READ;
-		t->sec = BCD_TO_BIN(h->sec);
-		t->min = BCD_TO_BIN(h->min);
-		t->hour = BCD_TO_BIN(h->hour);
-		t->wday = BCD_TO_BIN(h->wday);
-		t->day = BCD_TO_BIN(h->mday);
-		t->mon = BCD_TO_BIN(h->month);
-		t->year = BCD_TO_BIN(h->year);
+		t->tm_sec = BCD_TO_BIN(h->sec);
+		t->tm_min = BCD_TO_BIN(h->min);
+		t->tm_hour = BCD_TO_BIN(h->hour);
+		t->tm_wday = BCD_TO_BIN(h->wday);
+		t->tm_mday = BCD_TO_BIN(h->mday);
+		t->tm_mon = BCD_TO_BIN(h->month);
+		t->tm_year = BCD_TO_BIN(h->year);
 		h->csr &= ~C_READ;
 	}
 
diff -Nru a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
--- a/arch/m68k/sun3x/time.h	Thu May  9 15:21:09 2002
+++ b/arch/m68k/sun3x/time.h	Thu May  9 15:21:09 2002
@@ -1,9 +1,7 @@
 #ifndef SUN3X_TIME_H
 #define SUN3X_TIME_H
 
-extern void sun3x_gettod (int *yearp, int *monp, int *dayp,
-                   int *hourp, int *minp, int *secp);
-extern int sun3x_hwclk(int set, struct hwclk_time *t);
+extern int sun3x_hwclk(int set, struct rtc_time *t);
 unsigned long sun3x_gettimeoffset (void);
 void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
 
diff -Nru a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c
--- a/arch/mips/ddb5074/pci.c	Thu May  9 15:21:07 2002
+++ b/arch/mips/ddb5074/pci.c	Thu May  9 15:21:07 2002
@@ -319,10 +319,6 @@
 void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
 				      struct pbus_set_ranges_data *ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
 }
 
 int pcibios_enable_resources(struct pci_dev *dev)
@@ -396,7 +392,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Nru a/arch/mips/ddb5476/pci.c b/arch/mips/ddb5476/pci.c
--- a/arch/mips/ddb5476/pci.c	Thu May  9 15:21:05 2002
+++ b/arch/mips/ddb5476/pci.c	Thu May  9 15:21:05 2002
@@ -470,7 +470,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Nru a/arch/mips/ddb5xxx/common/pci.c b/arch/mips/ddb5xxx/common/pci.c
--- a/arch/mips/ddb5xxx/common/pci.c	Thu May  9 15:21:09 2002
+++ b/arch/mips/ddb5xxx/common/pci.c	Thu May  9 15:21:09 2002
@@ -164,7 +164,8 @@
 }
 
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	/* this should not be called */
 	MIPS_ASSERT(1 == 0);
diff -Nru a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476
--- a/arch/mips/defconfig-ddb5476	Thu May  9 15:21:06 2002
+++ b/arch/mips/defconfig-ddb5476	Thu May  9 15:21:06 2002
@@ -221,7 +221,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/mips/defconfig-it8172 b/arch/mips/defconfig-it8172
--- a/arch/mips/defconfig-it8172	Thu May  9 15:21:05 2002
+++ b/arch/mips/defconfig-it8172	Thu May  9 15:21:05 2002
@@ -286,7 +286,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c
--- a/arch/mips/gt64120/common/pci.c	Thu May  9 15:21:07 2002
+++ b/arch/mips/gt64120/common/pci.c	Thu May  9 15:21:07 2002
@@ -886,7 +886,7 @@
 }
 
 void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
+			    unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Nru a/arch/mips/ite-boards/generic/it8172_pci.c b/arch/mips/ite-boards/generic/it8172_pci.c
--- a/arch/mips/ite-boards/generic/it8172_pci.c	Thu May  9 15:21:08 2002
+++ b/arch/mips/ite-boards/generic/it8172_pci.c	Thu May  9 15:21:08 2002
@@ -241,7 +241,8 @@
 
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
     printk("pcibios_align_resource\n");
 }
diff -Nru a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c
--- a/arch/mips/kernel/pci.c	Thu May  9 15:21:03 2002
+++ b/arch/mips/kernel/pci.c	Thu May  9 15:21:03 2002
@@ -161,7 +161,8 @@
 }
 
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	/* this should not be called */
 }
diff -Nru a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c
--- a/arch/mips/mips-boards/generic/pci.c	Thu May  9 15:21:06 2002
+++ b/arch/mips/mips-boards/generic/pci.c	Thu May  9 15:21:06 2002
@@ -286,7 +286,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
--- a/arch/mips/sni/pci.c	Thu May  9 15:21:07 2002
+++ b/arch/mips/sni/pci.c	Thu May  9 15:21:07 2002
@@ -199,7 +199,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/mips64/mips-boards/generic/pci.c b/arch/mips64/mips-boards/generic/pci.c
--- a/arch/mips64/mips-boards/generic/pci.c	Thu May  9 15:21:02 2002
+++ b/arch/mips64/mips-boards/generic/pci.c	Thu May  9 15:21:02 2002
@@ -290,7 +290,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/mips64/sgi-ip27/ip27-pci.c b/arch/mips64/sgi-ip27/ip27-pci.c
--- a/arch/mips64/sgi-ip27/ip27-pci.c	Thu May  9 15:21:09 2002
+++ b/arch/mips64/sgi-ip27/ip27-pci.c	Thu May  9 15:21:09 2002
@@ -238,10 +238,6 @@
 pcibios_fixup_pbus_ranges(struct pci_bus * bus,
                           struct pbus_set_ranges_data * ranges)
 {
-	ranges->io_start  -= bus->resource[0]->start;
-	ranges->io_end    -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end   -= bus->resource[1]->start;
 }
 
 int __init
@@ -252,7 +248,8 @@
 }
 
 void __init
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/mips64/sgi-ip32/ip32-pci.c b/arch/mips64/sgi-ip32/ip32-pci.c
--- a/arch/mips64/sgi-ip32/ip32-pci.c	Thu May  9 15:21:10 2002
+++ b/arch/mips64/sgi-ip32/ip32-pci.c	Thu May  9 15:21:10 2002
@@ -329,7 +329,7 @@
 }
 
 void __init pcibios_align_resource (void *data, struct resource *res,
-				    unsigned long size)
+				    unsigned long size, unsigned long align)
 {
 }
 
@@ -352,10 +352,6 @@
 void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
 				      struct pbus_set_ranges_data * ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
 }
 
 /*
diff -Nru a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
--- a/arch/parisc/kernel/pci.c	Thu May  9 15:21:01 2002
+++ b/arch/parisc/kernel/pci.c	Thu May  9 15:21:01 2002
@@ -337,13 +337,15 @@
 ** than res->start.
 */
 void __devinit
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long alignment)
 {
 	unsigned long mask, align;
 
-	DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx)\n",
+	DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
 		((struct pci_dev *) data)->slot_name,
-		res->parent, res->start, res->end, (int) res->flags, size);
+		res->parent, res->start, res->end,
+		(int) res->flags, size, alignment);
 
 	/* has resource already been aligned/assigned? */
 	if (res->parent)
@@ -400,11 +402,11 @@
 
 			if (res.flags & IORESOURCE_IO) {
 				res.start = inner.io_end;
-				pcibios_align_resource(dev, &res, size);
+				pcibios_align_resource(dev, &res, size, 0);
 				inner.io_end += res.start + size;
 			} else if (res.flags & IORESOURCE_MEM) {
 				res.start = inner.mem_end;
-				pcibios_align_resource(dev, &res, size);
+				pcibios_align_resource(dev, &res, size, 0);
 				inner.mem_end = res.start + size;
 			}
 
diff -Nru a/arch/ppc/Config.help b/arch/ppc/Config.help
--- a/arch/ppc/Config.help	Thu May  9 15:21:04 2002
+++ b/arch/ppc/Config.help	Thu May  9 15:21:04 2002
@@ -1,59 +1,54 @@
 CONFIG_SMP
   This enables support for systems with more than one CPU. If you have
-  a system with only one CPU, like most personal computers, say N. If
-  you have a system with more than one CPU, say Y.
+  a system with only one CPU, say N. If you have a system with more
+  than one CPU, say Y.  Note that the kernel does not currently
+  support SMP machines with 603/603e/603ev or PPC750 ("G3") processors
+  since they have inadequate hardware support for multiprocessor
+  operation.
 
   If you say N here, the kernel will run on single and multiprocessor
   machines, but will use only one CPU of a multiprocessor machine. If
-  you say Y here, the kernel will run on many, but not all,
-  singleprocessor machines. On a singleprocessor machine, the kernel
-  will run faster if you say N here.
-
-  Note that if you say Y here and choose architecture "586" or
-  "Pentium" under "Processor family", the kernel will not work on 486
-  architectures. Similarly, multiprocessor kernels for the "PPro"
-  architecture may not work on all Pentium based boards.
-
-  People using multiprocessor machines who say Y here should also say
-  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
-  Management" code will be disabled if you say Y here.
-
-  See also the <file:Documentation/smp.tex>,
-  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
-  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-  <http://www.linuxdoc.org/docs.html#howto>.
+  you say Y here, the kernel will run on single-processor machines.
+  On a single-processor machine, the kernel will run faster if you say
+  N here.
 
   If you don't know what to do here, say N.
 
-CONFIG_PPC
-  The PowerPC is a very capable 32-bit RISC processor from Motorola,
-  the successor to their 68000 and 88000 series.  It powers recent
-  Macintoshes and also a widely-used series of single-board computers
-  from Motorola.  The Linux PowerPC port has a home page at
-  <http://penguinppc.org/>.
+CONFIG_PREEMPT
+  This option reduces the latency of the kernel when reacting to
+  real-time or interactive events by allowing a low priority process to
+  be preempted even if it is in kernel mode executing a system call.
+  Unfortunately the kernel code has some race conditions if both
+  CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
+  currently disabled if you are building an SMP kernel.
 
-CONFIG_MATH_EMULATION
-  Linux can emulate a math coprocessor (used for floating point
-  operations) if you don't have one. 486DX and Pentium processors have
-  a math coprocessor built in, 486SX and 386 do not, unless you added
-  a 487DX or 387, respectively. (The messages during boot time can
-  give you some hints here ["man dmesg"].) Everyone needs either a
-  coprocessor or this emulation.
-
-  If you don't have a math coprocessor, you need to say Y here; if you
-  say Y here even though you have a coprocessor, the coprocessor will
-  be used nevertheless. (This behavior can be changed with the kernel
-  command line option "no387", which comes handy if your coprocessor
-  is broken. Try "man bootparam" or see the documentation of your boot
-  loader (lilo or loadlin) about how to pass options to the kernel at
-  boot time.) This means that it is a good idea to say Y here if you
-  intend to use this kernel on different machines.
+  Say Y here if you are building a kernel for a desktop, embedded
+  or real-time system.  Say N if you are unsure.
 
-  More information about the internals of the Linux math coprocessor
-  emulation can be found in <file:arch/i386/math-emu/README>.
+CONFIG_PPC
+  The PowerPC is a modern RISC architecture descended from the POWER
+  architecture designed by IBM.  The PowerPC architecture is designed
+  to allow high-speed implementations which can execute several
+  instructions in each clock cycle.  IBM and Motorola design and
+  manufacture PowerPC processors aimed at embedded, desktop and server
+  applications.  PowerPC chips are used in Apple Power Macintoshes
+  (including iMacs, iBooks and PowerBooks), in IBM pSeries (RS/6000)
+  and iSeries (AS/400) machines, and in a broad range of embedded
+  applications.  The Linux PowerPC port has a home page at
+  <http://penguinppc.org/intro.shtml>.
 
-  If you are not sure, say Y; apart from resulting in a 66 KB bigger
-  kernel, it won't hurt.
+CONFIG_MATH_EMULATION
+  Some PowerPC chips designed for embedded applications do not have 
+  a floating-point unit and therefore do not implement the
+  floating-point instructions in the PowerPC instruction set.  If you
+  say Y here, the kernel will include code to emulate a floating-point
+  unit, which will allow programs that use floating-point
+  instructions to run.
+
+  If you have an Apple machine or an IBM RS/6000 or pSeries machine,
+  or any machine with a 6xx, 7xx or 7xxx series processor, say N
+  here.  Saying Y here will not hurt performance (on any machine) but
+  will increase the size of the kernel.
 
 CONFIG_MAC_FLOPPY
   If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
@@ -69,11 +64,8 @@
 
   Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
   for mass storage units such as hard disks. It was designed by
-  Western Digital and Compaq Computer in 1984. It was then named
-  ST506. Quite a number of disks use the IDE interface.
-
-  AT Attachment (ATA) is the superset of the IDE specifications.
-  ST506 was also called ATA-1.
+  Western Digital and Compaq Computer in 1984.  Quite a number of
+  disks use the IDE interface.
 
   Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
   ATA-3. It provides support for larger disks (up to 8.4GB by means of
@@ -111,50 +103,28 @@
 CONFIG_ISA
   Find out whether you have ISA slots on your motherboard.  ISA is the
   name of a bus system, i.e. the way the CPU talks to the other stuff
-  inside your box.  Other bus systems are PCI, EISA, MicroChannel
-  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
-  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+  inside your box.  If you have an Apple machine, say N here; if you
+  have an IBM RS/6000 or pSeries machine or a PReP machine, say Y.  If
+  you have an embedded board, consult your board documentation.
 
 CONFIG_PCI
-  Find out whether you have a PCI motherboard. PCI is the name of a
-  bus system, i.e. the way the CPU talks to the other stuff inside
-  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N.
-
-  The PCI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information about which PCI hardware does work under Linux and which
-  doesn't.
+  Find out whether your system includes a PCI bus. PCI is the name of
+  a bus system, i.e. the way the CPU talks to the other stuff inside
+  your box.  If you say Y here, the kernel will include drivers and
+  infrastructure code to support PCI bus devices.
 
 CONFIG_PCI_QSPAN
-  Find out whether you have a PCI motherboard. PCI is the name of a
-  bus system, i.e. the way the CPU talks to the other stuff inside
-  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N.
-
-  The PCI-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-  information about which PCI hardware does work under Linux and which
-  doesn't.
+  Say Y here if you have a system based on a Motorola 8xx-series
+  embedded processor with a QSPAN PCI interface, otherwise say N.
 
 CONFIG_MCA
-  MicroChannel Architecture is found in some IBM PS/2 machines and
-  laptops.  It is a bus system similar to PCI or ISA. See
-  <file:Documentation/mca.txt> (and especially the web page given
-  there) before attempting to build an MCA bus kernel.
+  MicroChannel Architecture is found in some older IBM RS/6000
+  machines.  It is a bus system similar to PCI or ISA.  MCA-based
+  RS/6000 machines are currently not supported by Linux.
 
 CONFIG_EISA
-  The Extended Industry Standard Architecture (EISA) bus was
-  developed as an open alternative to the IBM MicroChannel bus.
-
-  The EISA bus provided some of the features of the IBM MicroChannel
-  bus while maintaining backward compatibility with cards made for
-  the older ISA bus.  The EISA bus saw limited use between 1988 and
-  1995 when it was made obsolete by the PCI bus.
-
-  Say Y here if you are building a kernel for an EISA-based machine.
-
-  Otherwise, say N.
+  The Extended Industry Standard Architecture (EISA) bus is a bus
+  architecture used on some older intel-based PCs.
 
 CONFIG_HOTPLUG
   Say Y here if you want to plug devices into your computer while
@@ -193,57 +163,27 @@
 
 CONFIG_KCORE_ELF
   If you enabled support for /proc file system then the file
-  /proc/kcore will contain the kernel core image. This can be used
-  in gdb:
+  /proc/kcore will contain the kernel core image in ELF format. This
+  can be used in gdb:
 
   $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
 
-  You have two choices here: ELF and A.OUT. Selecting ELF will make
-  /proc/kcore appear in ELF core format as defined by the Executable
-  and Linking Format specification. Selecting A.OUT will choose the
-  old "a.out" format which may be necessary for some old versions
-  of binutils or on some architectures.
-
   This is especially useful if you have compiled the kernel with the
   "-g" option to preserve debugging information. It is mainly used
-  for examining kernel data structures on the live kernel so if you
-  don't understand what this means or are not a kernel hacker, just
-  leave it at its default value ELF.
+  for examining kernel data structures on the live kernel.
 
 CONFIG_BINFMT_ELF
   ELF (Executable and Linkable Format) is a format for libraries and
   executables used across different architectures and operating
-  systems. Saying Y here will enable your kernel to run ELF binaries
-  and enlarge it by about 13 KB. ELF support under Linux has now all
-  but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC)
-  because it is portable (this does *not* mean that you will be able
-  to run executables from different architectures or operating systems
-  however) and makes building run-time libraries very easy. Many new
-  executables are distributed solely in ELF format. You definitely
-  want to say Y here.
-
-  Information about ELF is contained in the ELF HOWTO available from
-  <http://www.linuxdoc.org/docs.html#howto>.
-
-  If you find that after upgrading from Linux kernel 1.2 and saying Y
-  here, you still can't run any ELF binaries (they just crash), then
-  you'll have to install the newest ELF runtime libraries, including
-  ld.so (check the file <file:Documentation/Changes> for location and
-  latest version).
-
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  The module
-  will be called binfmt_elf.o. Saying M or N here is dangerous because
-  some crucial programs on your system might be in ELF format.
+  systems.
 
 CONFIG_BINFMT_MISC
   If you say Y here, it will be possible to plug wrapper-driven binary
   formats into the kernel. You will like this especially when you use
   programs that need an interpreter to run like Java, Python or
-  Emacs-Lisp. It's also useful if you often run DOS executables under
+  Emacs-Lisp.  It's also useful if you often run DOS executables under
   the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>). Once you have
+  <http://www.linuxdoc.org/docs.html#howto>).  Once you have
   registered such a binary class with the kernel, you can start one of
   those programs simply by typing in its name at a shell prompt; Linux
   will automatically feed it to the correct interpreter.
@@ -262,20 +202,17 @@
 
 CONFIG_VGA_CONSOLE
   Saying Y here will allow you to use Linux in text mode through a
-  display that complies with the generic VGA standard. Virtually
-  everyone wants that.
+  display that complies with the generic VGA standard.  This can be
+  useful on PReP systems and IBM RS/6000 or pSeries machines but is of
+  limited usefulness on Apple machines.
 
-  The program SVGATextMode can be used to utilize SVGA video cards to
-  their full potential in text mode. Download it from
-  <ftp://ibiblio.org/pub/Linux/utils/console/>.
-
-  Say Y.
+  Say N here if you have an Apple machine.
 
 CONFIG_IRQ_ALL_CPUS
   This option gives the kernel permission to distribute IRQs across
   multiple CPUs.  Saying N here will route all IRQs to the first
-  CPU. Generally SMP PowerMacs can answer Y. SMP IBM CHRP boxes or
-  Power3 boxes should say N for now.
+  CPU.  Generally saying Y is safe, although some problems have been
+  reported with SMP Power Macintoshes with this option enabled.
 
 CONFIG_FB
   The frame buffer device provides an abstraction for the graphics
@@ -300,14 +237,9 @@
   <http://www.tahallah.demon.co.uk/programming/prog.html> for more
   information.
 
-  Say Y here and to the driver for your graphics board below if you
-  are compiling a kernel for a non-x86 architecture.
-
-  If you are compiling for the x86 architecture, you can say Y if you
-  want to play with it, but it is not essential. Please note that
-  running graphical applications that directly touch the hardware
-  (e.g. an accelerated X server) and that are not frame buffer
-  device-aware may cause unexpected results. If unsure, say N.
+  Saying Y here is recommended if your machine has graphics hardware,
+  and strongly recommended if you are compiling a kernel for an Apple
+  machine.
 
 CONFIG_FB_COMPAT_XPMAC
   If you use the Xpmac X server (common with mklinux), you'll need to
@@ -414,26 +346,28 @@
 CONFIG_ADB
   Apple Desktop Bus (ADB) support is for support of devices which
   are connected to an ADB port.  ADB devices tend to have 4 pins.
-  If you have an Apple Macintosh prior to the iMac, or a
-  "Blue and White G3", you probably want to say Y here.  Otherwise
-  say N.
+  If you have an Apple Macintosh prior to the iMac, an iBook or
+  PowerBook, or a "Blue and White G3", you probably want to say Y
+  here.  Otherwise say N.
 
 CONFIG_ADB_CUDA
   This provides support for CUDA based Power Macintosh systems.  This
   includes most OldWorld PowerMacs, the first generation iMacs, the
-  Blue&White G3 and the Yikes G4 (PCI Graphics).  All later models
-  should use CONFIG_ADB_PMU instead.
+  Blue&White G3 and the "Yikes" G4 (PCI Graphics).  All later models
+  should use CONFIG_ADB_PMU instead.  It is safe to say Y here even if
+  your machine doesn't have a CUDA.
 
   If unsure say Y.
 
 CONFIG_ADB_PMU
-  On the PowerBook 3400 and 2400, the PMU is a 6805 microprocessor
-  core whose primary function is to control battery charging and
-  system power.  The PMU also controls the ADB (Apple Desktop Bus)
-  which connects to the keyboard and mouse, as well as the
-  non-volatile RAM and the RTC (real time clock) chip.  Say Y to
-  enable support for this device; you should do so if your machine
-  is one of these PowerBooks.
+  On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
+  PMU is an embedded microprocessor whose primary function is to
+  control system power, and battery charging on the portable models.
+  The PMU also controls the ADB (Apple Desktop Bus) which connects to
+  the keyboard and mouse on some machines, as well as the non-volatile
+  RAM and the RTC (real time clock) chip.  Say Y to enable support for
+  this device; you should do so if your machine is one of those
+  mentioned above.
 
 CONFIG_ADB_MACIO
   Say Y here to include direct support for the ADB controller in the
@@ -464,7 +398,7 @@
   your boot loader (lilo or loadlin) about how to pass options to the
   kernel at boot time.)
 
-  If you don't have a VGA card installed and you say Y here, the
+  If you don't have a graphics card installed and you say Y here, the
   kernel will automatically use the first serial line, /dev/ttyS0, as
   system console.
 
@@ -476,14 +410,11 @@
   for them, you can't currently use the serial console feature.
 
 CONFIG_BUSMOUSE
-  Say Y here if your machine has a bus mouse as opposed to a serial
-  mouse. Most people have a regular serial MouseSystem or
-  Microsoft mouse (made by Logitech) that plugs into a COM port
-  (rectangular with 9 or 25 pins). These people say N here. 
-
-  If you have a laptop, you either have to check the documentation or
-  experiment a bit to find out whether the trackball is a serial mouse
-  or not; it's best to say Y here for you.
+  Say Y here if your machine has a bus mouse as opposed to a serial,
+  PS/2 or USB mouse.  Say Y here if you have an Apple machine with an
+  ADB mouse and you are not using the input layer (that is,
+  CONFIG_INPUT_ADBHID is N), or if you have a PC-style mouse interface
+  card plugged into your PCI or ISA bus.  Otherwise say N.
 
   This is the generic bus mouse driver code. If you have a bus mouse,
   you will have to say Y here and also to the specific driver for your
@@ -496,17 +427,10 @@
 
 CONFIG_MOUSE
   This is for machines with a mouse which is neither a serial nor a
-  bus mouse. Examples are PS/2 mice (such as the track balls on some
-  laptops) and some digitizer pads. Most people have a regular serial
-  MouseSystem or Microsoft mouse (made by Logitech) that plugs into a
-  COM port (rectangular with 9 or 25 pins). These people say N here.
-  If you have something else, read the Busmouse-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. This HOWTO contains
-  information about all non-serial mice, not just bus mice.
-
-  If you have a laptop, you either have to check the documentation or
-  experiment a bit to find out whether the trackball is a serial mouse
-  or not; it's best to say Y here for you.
+  USB nor a bus mouse.  Examples are PS/2 mice (including the track
+  balls on some laptops) and some digitizer pads.  Say Y here if you
+  have a CHRP machine (such as an IBM RS/6000 or pSeries machine) with
+  a PS/2-style mouse.
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause the configurator to skip all
@@ -523,16 +447,8 @@
   keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
   unless you really know what this hack does.
 
-CONFIG_PROC_HARDWARE
-  Say Y here to support the /proc/hardware file, which gives you
-  access to information about the machine you're running on,
-  including the model, CPU, MMU, clock speed, BogoMIPS rating,
-  and memory size.
-
 CONFIG_AMIGA
-  This option enables support for the Amiga series of computers. If
-  you plan to use this kernel on an Amiga, say Y here and browse the
-  material available in <file:Documentation/m68k>; otherwise say N.
+  This option enables support for the Amiga series of computers.
 
 CONFIG_A2232
   This option supports the 2232 7-port serial card shipped with the
@@ -581,10 +497,6 @@
   The module is called amigamouse.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_BOOTX_TEXT
-  Say Y here to see progress messages from the boot firmware in text
-  mode. Requires either BootX or Open Firmware.
-
 CONFIG_AMIGA_BUILTIN_SERIAL
   If you want to use your Amiga's built-in serial port in Linux,
   answer Y.
@@ -615,16 +527,20 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.
 
+CONFIG_BOOTX_TEXT
+  Say Y here to see progress messages from the boot firmware in text
+  mode. Requires either BootX or Open Firmware.
+
 CONFIG_6xx
   There are four types of PowerPC chips supported.  The more common
   types (601, 603, 604, 740, 750, 7400), the Motorola embedded
   versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions
-  (403 and 405) and the high end 64 bit Power processors (Power 3,
-  Power 4).  Unless you are building a kernel for one of the embedded
-  processor systems, or a 64 bit IBM RS/6000, choose 6xx.  Note that
-  the kernel runs in 32-bit mode even on 64-bit chips.  Also note that
-  because the 82xx family has a 603e core, specific support for that
-  chipset is asked later on.
+  (403 and 405) and the high end 64 bit Power processors (POWER 3)
+  Unless you are building a kernel for one of the embedded processor
+  systems, or a 64 bit IBM RS/6000, choose 6xx.  Note that the kernel
+  runs in 32-bit mode even on 64-bit chips.  Also note that because
+  the 82xx family has a 603e core, specific support for that chipset
+  is asked later on.
 
 CONFIG_8260
   The MPC8260 CPM (Communications Processor Module) is a typical
@@ -662,11 +578,14 @@
   Starmax series), PReP (PowerPC Reference Platform) machines (such
   as the Motorola PowerStacks, Motorola cPCI/VME embedded systems,
   and some IBM RS/6000 systems), CHRP (Common Hardware Reference
-  Platform), and several embedded PowerPC systems containing 4xx, 6xx,
-  7xx, 8xx, 74xx, and 82xx processors.  Currently, the default option
-  is to build a kernel which works on the first three.
-
-  Select PowerMac/PReP/MTX/CHRP if configuring for any of the above.
+  Platform) machines (including all of the recent IBM RS/6000 and
+  pSeries machines), and several embedded PowerPC systems containing
+  4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors.  Currently, the
+  default option is to build a kernel which works on the first three.
+
+  Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or
+  pSeries machine, a Power Macintosh (including iMacs, iBooks and
+  Powerbooks), or a PReP machine.
 
   Select Gemini if configuring for a Synergy Microsystems' Gemini
   series Single Board Computer.  More information is available at:
@@ -722,22 +641,28 @@
   debugging, leave this option off.
 
 CONFIG_TAU_AVERAGE
-  The TAU hardware can compare the temperature to an upper and lower bound.
-  The default behavior is to show both the upper and lower bound in
-  /proc/cpuinfo. If the range is large, the temperature is either changing
-  a lot, or the TAU hardware is broken (likely on some G4's). If the range
-  is small (around 4 degrees), the temperature is relatively stable.
+  The TAU hardware can compare the temperature to an upper and lower
+  bound.  The default behavior is to show both the upper and lower
+  bound in /proc/cpuinfo. If the range is large, the temperature is
+  either changing a lot, or the TAU hardware is broken (likely on some
+  G4's). If the range is small (around 4 degrees), the temperature is
+  relatively stable.  If you say Y here, a single temperature value,
+  halfway between the upper and lower bounds, will be reported in
+  /proc/cpuinfo.
+
+  If in doubt, say N here.
 
 CONFIG_PMAC_PBOOK
   This provides support for putting a PowerBook to sleep; it also
   enables media bay support.  Power management works on the
-  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3. You
-  must get the power management daemon, pmud, to make it work and you
-  must have the /dev/pmu device (see the pmud README).
+  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
+  the Titanium Powerbook G4, as well as the iBooks.  You should get
+  the power management daemon, pmud, to make it work and you must have
+  the /dev/pmu device (see the pmud README).
 
   Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
 
-  If you have a PowerBook, you should say Y.
+  If you have a PowerBook, you should say Y here.
 
   You may also want to compile the dma sound driver as a module and
   have it autoloaded. The act of removing the module shuts down the
@@ -955,11 +880,11 @@
     URL: <http://www.microsys.de/html/cu824.html>
 
 CONFIG_MAC_ADBKEYCODES
-  This provides support for sending raw ADB keycodes to console
-  devices.  This is the default up to 2.4.0, but in future this may be
-  phased out in favor of generic Linux keycodes.  If you say Y here,
-  you can dynamically switch via the
-      /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
+  This provides support for sending ADB keycodes to console devices in
+  raw mode, rather than generic "Linux" keycodes.  This is the default
+  up to 2.4.0, but in future this may be phased out in favor of
+  generic Linux keycodes.  If you say Y here, you can dynamically
+  switch via the /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
   sysctl and with the "keyboard_sends_linux_keycodes=" kernel
   argument.
 
@@ -974,6 +899,8 @@
       /proc/sys/dev/mac_hid/mouse_button2_keycode
       /proc/sys/dev/mac_hid/mouse_button3_keycode
 
+  If you have an Apple machine with a 1-button mouse, say Y here.
+
 CONFIG_PPC_RTC
   If you say Y here and create a character special file /dev/rtc with
   major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -1018,30 +945,31 @@
   If unsure, say Y.
 
 CONFIG_CMDLINE
-  On some architectures (EBSA110 and CATS), there is currently no way
-  for the boot loader to pass arguments to the kernel. For these
-  architectures, you should supply some command-line options at build
-  time by entering them here. As a minimum, you should specify the
-  memory size and the root device (e.g., mem=64M root=/dev/nfs).
+  On some platforms, there is currently no way for the boot loader to
+  pass arguments to the kernel. For these platforms, you can supply
+  some command-line options at build time by entering them here.  In
+  most cases you will need to specify the root device here.
 
 CONFIG_KGDB
   Include in-kernel hooks for kgdb, the Linux kernel source level
-  debugger.  This project has a web page at
-  <http://kgdb.sourceforge.net/>.
+  debugger.  See <http://kgdb.sourceforge.net/> for more information.
+  Unless you are intending to debug the kernel, say N here.
 
 CONFIG_XMON
-  Include in-kernel hooks for the xmon kernel monitor/debugger
-  supported by the PPC port.
+  Include in-kernel hooks for the xmon kernel monitor/debugger.
+  Unless you are intending to debug the kernel, say N here.
 
 Include BDI2000 debugger support
 CONFIG_BDI_SWITCH
   Include in-kernel support for the Abatron BDI2000 debugger.
+  Unless you are intending to debug the kernel with one of these
+  machines, say N here.
 
 Add additional CFLAGS to the kernel build
 CONFIG_MORE_COMPILE_OPTIONS
-  If you want to add additional CFLAGS to the kernel build, such as
-  -g for KGDB, XMON or the BDI2000, enable this option and then
-  enter what you would like to add in the next question.
+  If you want to add additional CFLAGS to the kernel build, such as -g
+  for KGDB or the BDI2000, enable this option and then enter what you
+  would like to add in the next question.
 
 CONFIG_ADVANCED_OPTIONS
   This option will enable prompting for a variety of advanced kernel
@@ -1049,39 +977,42 @@
   work if they are set incorrectly, but can be used to optimize certain
   aspects of kernel memory management.
 
-  Unless you know what you are doing you *should not* enable this option.
+  Unless you know what you are doing, say N here.
 
 CONFIG_HIGHMEM_START_BOOL
-  Unless you know what you are doing you *should not* set this option.
+  This option allows you to set the base address of the kernel virtual
+  area used to map high memory pages.  This can be useful in
+  optimizing the layout of kernel virtual memory.
 
-  It can be used to override the default PKMAP_BASE address which
-  is the location of the high memory pool.  This can be useful in
-  optimizing virtual memory usage in a system.
+  Say N here unless you know what you are doing.
 
 CONFIG_LOWMEM_SIZE_BOOL
-  Unless you know what you are doing you *should not* set this option.
+  This option allows you to set the maximum amount of memory which
+  will be used as "low memory", that is, memory which the kernel can
+  access directly, without having to set up a kernel virtual mapping.
+  This can be useful in optimizing the layout of kernel virtual
+  memory.
 
-  It can be used to override the standard calculated value of
-  MAX_LOW_MEM. This can be useful in optimizing virtual memory usage
-  in a system.
+  Say N here unless you know what you are doing.
 
 CONFIG_KERNEL_START_BOOL
-  Unless you know what you are doing you *should not* set this option.
+  This option allows you to set the kernel virtual address at which
+  the kernel will map low memory (the kernel image will be linked at
+  this address).  This can be useful in optimizing the virtual memory
+  layout of the system.
 
-  It can be used to override the standard PAGE_OFFSET/KERNELBASE
-  value used by the kernel.  This can be useful in controlling
-  amount of virtual address space available to the kernel.
+  Say N here unless you know what you are doing.
 
 CONFIG_TASK_SIZE_BOOL
-  Unless you know what you are doing you *should not* set this option.
+  This option allows you to set the amount of virtual address space
+  allocated to user tasks.  This can be useful in optimizing the
+  virtual memory layout of the system.
 
-  It can be used to override the standard TASK_SIZE value used
-  by the kernel.  This can be useful in controlling amount of
-  virtual address space available to user tasks.
+  Say N here unless you know what you are doing.
 
 CONFIG_BOOT_LOAD_BOOL
-  Unless you know what you are doing you *should not* set this option.
+  This option allows you to set the initial load address of the zImage
+  or zImage.initrd file.  This can be useful if you are on a board
+  which has a small amount of memory.
 
-  It can be used to change the initial load address of the zImage or
-  zImage.initrd file.  This can be useful if you are on a board which has
-  a small ammount of memory.
+  Say N here unless you know what you are doing.
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Thu May  9 15:21:02 2002
+++ b/arch/ppc/Makefile	Thu May  9 15:21:02 2002
@@ -111,7 +111,7 @@
 	cp -f arch/ppc/configs/$(@:config=defconfig) arch/ppc/defconfig
 
 archclean:
-	rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name}
+	rm -f arch/ppc/kernel/{mk_defs,asm-offsets.h,find_name}
 	rm -f arch/ppc/iSeries/ReleaseData.h
 	@$(MAKEBOOT) clean
 
diff -Nru a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
--- a/arch/ppc/boot/simple/embed_config.c	Thu May  9 15:21:02 2002
+++ b/arch/ppc/boot/simple/embed_config.c	Thu May  9 15:21:02 2002
@@ -706,11 +706,29 @@
 #endif
 
 #ifdef CONFIG_EP405
+#include <linux/serial_reg.h>
+
 void
 embed_config(bd_t **bdp)
 {
+	u32 chcr0;
 	u_char *cp;
 	bd_t	*bd;
+
+	/* Different versions of the PlanetCore firmware vary in how
+	   they set up the serial port - in particular whether they
+	   use the internal or external serial clock for UART0.  Make
+	   sure the UART is in a known state. */
+	/* FIXME: We should use the board's 11.0592MHz external serial
+	   clock - it will be more accurate for serial rates.  For
+	   now, however the baud rates in ep405.h are for the internal
+	   clock. */
+	chcr0 = mfdcr(DCRN_CHCR0);
+	if ( (chcr0 & 0x1fff) != 0x103e ) {
+		mtdcr(DCRN_CHCR0, (chcr0 & 0xffffe000) | 0x103e);
+		/* The following tricks serial_init() into resetting the baud rate */
+		writeb(0, UART0_IO_BASE + UART_LCR);
+	}
 
 	bd = &bdinfo;
 	*bdp = bd;
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Thu May  9 15:21:01 2002
+++ b/arch/ppc/config.in	Thu May  9 15:21:01 2002
@@ -123,10 +123,16 @@
 	 SBS-K2			CONFIG_K2		\
 	 Synergy-Gemini		CONFIG_GEMINI		\
 	 Zynx-ZX4500		CONFIG_ZX4500"		CHRP/PowerMac/PReP
-fi
 
-if [ "$CONFIG_PCORE" = "y" -o "$CONFIG_POWERPMC250" = "y" ]; then
-   define_bool CONFIG_FORCE y
+   if [ "$CONFIG_SANDPOINT" = "y" ]; then
+      bool '  Sandpoint X3' CONFIG_SANDPOINT_X3
+   fi
+   if [ "$CONFIG_PCORE" = "y" -o "$CONFIG_POWERPMC250" = "y" ]; then
+      define_bool CONFIG_FORCE y
+   fi
+   if [ "$CONFIG_LOPEC" = "y" -o "$CONFIG_SANDPOINT_X3" = "y" ]; then
+      define_bool CONFIG_EPIC_SERIAL_MODE y
+   fi
 fi
 
 if [ "$CONFIG_FORCE" = "y" -o "$CONFIG_MENF1" = "y" \
@@ -147,13 +153,6 @@
    bool 'MVME5100 configured with an IPMC761' CONFIG_MVME5100_IPMC761_PRESENT
 fi
 
-if [ "$CONFIG_SANDPOINT" = "y" ]; then
-   bool 'Sandpoint X3' CONFIG_SANDPOINT_X3
-   if [ "$CONFIG_SANDPOINT_X3" = "y" ]; then
-      define_bool CONFIG_EPIC_SERIAL_MODE y
-   fi
-fi
-
 if [ "$CONFIG_SPRUCE" = "y" ]; then
    bool 'Spruce baud clock support' CONFIG_SPRUCE_BAUD_33M
 fi
@@ -166,7 +165,9 @@
 if [ "$CONFIG_SMP" = "y" ]; then
    bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
 fi
-define_bool CONFIG_PREEMPT n
+if [ "$CONFIG_SMP" != "y" ]; then
+   bool 'Preemptible Kernel' CONFIG_PREEMPT
+fi
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
    bool 'AltiVec Support' CONFIG_ALTIVEC
@@ -618,9 +619,10 @@
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
    bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
 fi
-if [ "$CONFIG_MCPN765" = "y" -o "$CONFIG_SANDPOINT" = "y" \
-     -o "$CONFIG_ZX4500" = "y" -o "$CONFIG_PRPMC800" = "y" \
-     -o "$CONFIG_4xx" = "y" -o "$CONFIG_GT64260" = "y" ]; then
+if [ "$CONFIG_4xx" = "y" -o "$CONFIG_GT64260" = "y"		\
+     -o "$CONFIG_LOPEC" = "y" -o "$CONFIG_MCPN765" = "y"	\
+     -o "$CONFIG_PRPMC800" = "y" -o "$CONFIG_SANDPOINT" = "y"	\
+     -o "$CONFIG_ZX4500" = "y" ]; then
    bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
 fi
 endmenu
diff -Nru a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig
--- a/arch/ppc/configs/apus_defconfig	Thu May  9 15:21:04 2002
+++ b/arch/ppc/configs/apus_defconfig	Thu May  9 15:21:04 2002
@@ -256,7 +256,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_IDEDOUBLER=y
diff -Nru a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
--- a/arch/ppc/configs/common_defconfig	Thu May  9 15:21:04 2002
+++ b/arch/ppc/configs/common_defconfig	Thu May  9 15:21:04 2002
@@ -249,7 +249,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -282,7 +281,6 @@
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
diff -Nru a/arch/ppc/configs/cpci405_defconfig b/arch/ppc/configs/cpci405_defconfig
--- a/arch/ppc/configs/cpci405_defconfig	Thu May  9 15:21:05 2002
+++ b/arch/ppc/configs/cpci405_defconfig	Thu May  9 15:21:05 2002
@@ -214,7 +214,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_CPCI405_IDE=y
 # CONFIG_IDE_CHIPSETS is not set
diff -Nru a/arch/ppc/configs/k2_defconfig b/arch/ppc/configs/k2_defconfig
--- a/arch/ppc/configs/k2_defconfig	Thu May  9 15:21:01 2002
+++ b/arch/ppc/configs/k2_defconfig	Thu May  9 15:21:01 2002
@@ -232,7 +232,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig
--- a/arch/ppc/configs/menf1_defconfig	Thu May  9 15:21:00 2002
+++ b/arch/ppc/configs/menf1_defconfig	Thu May  9 15:21:00 2002
@@ -236,7 +236,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig
--- a/arch/ppc/configs/mvme5100_defconfig	Thu May  9 15:21:02 2002
+++ b/arch/ppc/configs/mvme5100_defconfig	Thu May  9 15:21:02 2002
@@ -230,7 +230,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig
--- a/arch/ppc/configs/pmac_defconfig	Thu May  9 15:21:09 2002
+++ b/arch/ppc/configs/pmac_defconfig	Thu May  9 15:21:09 2002
@@ -239,7 +239,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -272,7 +271,6 @@
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
diff -Nru a/arch/ppc/configs/pplus_defconfig b/arch/ppc/configs/pplus_defconfig
--- a/arch/ppc/configs/pplus_defconfig	Thu May  9 15:21:08 2002
+++ b/arch/ppc/configs/pplus_defconfig	Thu May  9 15:21:08 2002
@@ -243,7 +243,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/ppc/configs/sandpoint_defconfig b/arch/ppc/configs/sandpoint_defconfig
--- a/arch/ppc/configs/sandpoint_defconfig	Thu May  9 15:21:06 2002
+++ b/arch/ppc/configs/sandpoint_defconfig	Thu May  9 15:21:06 2002
@@ -206,7 +206,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
diff -Nru a/arch/ppc/defconfig b/arch/ppc/defconfig
--- a/arch/ppc/defconfig	Thu May  9 15:21:04 2002
+++ b/arch/ppc/defconfig	Thu May  9 15:21:04 2002
@@ -249,7 +249,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -282,7 +281,6 @@
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Thu May  9 15:21:05 2002
+++ b/arch/ppc/kernel/Makefile	Thu May  9 15:21:05 2002
@@ -100,25 +100,22 @@
 
 include $(TOPDIR)/Rules.make
 
-entry.o: entry.S ppc_defs.h
-misc.o: misc.S ppc_defs.h
-l2cr.o: l2cr.S ppc_defs.h
-head.o: head.S ppc_defs.h
-head_4xx.o: head_4xx.S ppc_defs.h
-head_8xx.o: head_8xx.S ppc_defs.h
-iSeries_head.o: iSeries_head.S ppc_defs.h
-iSeries_misc.o: iSeries_misc.S ppc_defs.h
+entry.o: entry.S asm-offsets.h
+misc.o: misc.S asm-offsets.h
+l2cr.o: l2cr.S asm-offsets.h
+head.o: head.S asm-offsets.h
+head_4xx.o: head_4xx.S asm-offsets.h
+head_8xx.o: head_8xx.S asm-offsets.h
+iSeries_head.o: iSeries_head.S asm-offsets.h
+iSeries_misc.o: iSeries_misc.S asm-offsets.h
 
-ppc_defs.h: mk_defs.c ppc_defs.head \
+asm-offsets.h: mk_defs.c asm-offsets.head \
 		$(TOPDIR)/include/asm/mmu.h \
 		$(TOPDIR)/include/asm/processor.h \
 		$(TOPDIR)/include/asm/pgtable.h \
 		$(TOPDIR)/include/asm/ptrace.h
 	$(CC) $(CFLAGS) -S mk_defs.c
-	cp ppc_defs.head ppc_defs.h
-# for bk, this way we can write to the file even if it's not checked out
-	chmod u+w ppc_defs.h
-	grep '^#define' mk_defs.s >> ppc_defs.h
+	(cat asm-offsets.head; grep '^#define' mk_defs.s) >asm-offsets.h
 	rm mk_defs.s
 
 find_name : find_name.c
diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
--- a/arch/ppc/kernel/align.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/align.c	Thu May  9 15:21:01 2002
@@ -200,6 +200,8 @@
 		unsigned char v[8];
 	} data;
 
+	CHECK_FULL_REGS(regs);
+
 #if defined(CONFIG_4xx)
 	/* The 4xx-family processors have no DSISR register,
 	 * so we emulate it.
diff -Nru a/arch/ppc/kernel/asm-offsets.head b/arch/ppc/kernel/asm-offsets.head
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/asm-offsets.head	Thu May  9 15:21:06 2002
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff -Nru a/arch/ppc/kernel/btext.c b/arch/ppc/kernel/btext.c
--- a/arch/ppc/kernel/btext.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/btext.c	Thu May  9 15:21:01 2002
@@ -195,17 +195,20 @@
 {
 	unsigned long base, offset, size;
 	boot_infos_t *bi = &disp_bi;
+	unsigned char *vbase;
 
+	/* By default, we are no longer mapped */
+	boot_text_mapped = 0;
 	if (bi->dispDeviceBase == 0)
 		return;
 	base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
 	offset = ((unsigned long) bi->dispDeviceBase) - base;
 	size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
 		+ bi->dispDeviceRect[0];
-	bi->logicalDisplayBase = ioremap(base, size);
-	if (bi->logicalDisplayBase == 0)
+	vbase = ioremap(base, size);
+	if (vbase == 0)
 		return;
-	bi->logicalDisplayBase += offset;
+	bi->logicalDisplayBase = vbase + offset;
 	boot_text_mapped = 1;
 }
 
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Thu May  9 15:21:08 2002
+++ b/arch/ppc/kernel/cputable.c	Thu May  9 15:21:08 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_8xx(int cpu_nr);
 extern void __setup_cpu_generic(int cpu_nr);
@@ -61,21 +63,24 @@
     },
     {	/* 603 */
     	0xffff0000, 0x00030000, "603",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
     	32, 32,
 	__setup_cpu_603
     },
     {	/* 603e */
     	0xffff0000, 0x00060000, "603e",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_603
     },
     {	/* 603ev */
     	0xffff0000, 0x00070000, "603ev",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_603
@@ -115,7 +120,7 @@
     {	/* 740/750 (0x4202, don't support TAU ?) */
     	0xffffffff, 0x00084202, "740/750",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -123,7 +128,7 @@
     {	/* 745/755 */
     	0xfffff000, 0x00083000, "745/755",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -131,7 +136,7 @@
     {	/* 750CX (80100 and 8010x?) */
     	0xfffffff0, 0x00080100, "750CX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -139,7 +144,7 @@
     {	/* 750CX (82201 and 82202) */
     	0xfffffff0, 0x00082200, "750CX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -147,7 +152,7 @@
     {	/* 750CXe (82214) */
     	0xfffffff0, 0x00082210, "750CXe",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -163,7 +168,8 @@
     {	/* 7400 rev 1.1 ? (no TAU) */
     	0xffffffff, 0x000c1101, "7400 (1.1)",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7400
@@ -171,7 +177,8 @@
     {	/* 7400 */
     	0xffff0000, 0x000c0000, "7400",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7400
@@ -179,7 +186,8 @@
     {	/* 7410 */
     	0xffff0000, 0x800c0000, "7410",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7410
@@ -187,20 +195,38 @@
     {	/* 7450 2.0 - no doze/nap */
     	0xffffffff, 0x80000200, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP |
+	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
     },
-    {	/* 7450 others */
-    	0xffff0000, 0x80000000, "7450",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP |
+    {	/* 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,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	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 |
+	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_7455
     },
     {	/* 82xx (8240, 8245, 8260 are all 603e cores) */
 	0x7fff0000, 0x00810000, "82xx",
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Thu May  9 15:21:05 2002
+++ b/arch/ppc/kernel/entry.S	Thu May  9 15:21:05 2002
@@ -33,7 +33,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 #ifdef	CONFIG_PPC_ISERIES
 #include "iSeries_asm.h"
 #endif /* CONFIG_PPC_ISERIES */
@@ -46,45 +46,42 @@
  * This code finishes saving the registers to the exception frame
  * and jumps to the appropriate handler for the exception, turning
  * on address translation.
+ * Note that we rely on the caller having set cr0.eq iff the exception
+ * occurred in kernel mode (i.e. MSR:PR = 0).
  */
+	.globl	transfer_to_handler_full
+transfer_to_handler_full:
+	SAVE_NVGPRS(r11)
+	/* fall through */
+
 	.globl	transfer_to_handler
 transfer_to_handler:
-	stw	r22,_NIP(r21)
-	stw	r23,_MSR(r21)
-	SAVE_4GPRS(8, r21)
-	SAVE_8GPRS(12, r21)
-	SAVE_8GPRS(24, r21)
-	andi.	r23,r23,MSR_PR
-	mfspr	r23,SPRG3
-	addi	r2,r23,-THREAD		/* set r2 to current */
-	tovirt(r2,r2)
+	stw	r2,GPR2(r11)
+	stw	r12,_NIP(r11)
+	stw	r9,_MSR(r11)
+	mfctr	r12
+	mfspr	r2,XER
+	stw	r12,_CTR(r11)
+	stw	r2,_XER(r11)
+	mfspr	r12,SPRG3
+	addi	r2,r12,-THREAD
+	tovirt(r2,r2)			/* set r2 to current */
 	beq	2f			/* if from user, fix up THREAD.regs */
-	addi	r24,r1,STACK_FRAME_OVERHEAD
-	stw	r24,PT_REGS(r23)
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
-	mfspr	r22,SPRN_VRSAVE		/* if G4, save vrsave register value */
-	stw	r22,THREAD_VRSAVE(r23)
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif /* CONFIG_ALTIVEC */
+	addi	r11,r1,STACK_FRAME_OVERHEAD
+	stw	r11,PT_REGS(r12)
 	b	3f
 2:	/* if from kernel, check for stack overflow */
-	lwz	r22,THREAD_INFO-THREAD(r23)
-	cmplw	r1,r22			/* if r1 <= current->thread_info */
+	lwz	r11,THREAD_INFO-THREAD(r12)
+	cmplw	r1,r11			/* if r1 <= current->thread_info */
 	ble-	stack_ovf		/* then the kernel stack overflowed */
 3:
-	mflr	r23
-	andi.	r24,r23,0x3f00		/* get vector offset */
-	stw	r24,TRAP(r21)
-	li	r22,0
-	stw	r22,RESULT(r21)
-	mtspr	SPRG2,r22		/* r1 is now kernel sp */
-	lwz	r24,0(r23)		/* virtual address of handler */
-	lwz	r23,4(r23)		/* where to go when done */
-	FIX_SRR1(r20,r22)
-	mtspr	SRR0,r24
-	mtspr	SRR1,r20
-	mtlr	r23
+	mflr	r9
+	lwz	r11,0(r9)		/* virtual address of handler */
+	lwz	r9,4(r9)		/* where to go when done */
+	FIX_SRR1(r10,r12)
+	mtspr	SRR0,r11
+	mtspr	SRR1,r10
+	mtlr	r9
 	SYNC
 	RFI				/* jump to handler, enable MMU */
 
@@ -93,108 +90,63 @@
  * and call StackOverflow(regs), which should not return.
  */
 stack_ovf:
+	SAVE_NVGPRS(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
+	tovirt(r2,r2)			/* set r2 to current */
 	lis	r1,init_thread_union@ha
 	addi	r1,r1,init_thread_union@l
 	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
-	lis	r24,StackOverflow@ha
-	addi	r24,r24,StackOverflow@l
-	li	r20,MSR_KERNEL
-	FIX_SRR1(r20,r22)
-	mtspr	SRR0,r24
-	mtspr	SRR1,r20
+	lis	r9,StackOverflow@ha
+	addi	r9,r9,StackOverflow@l
+	li	r10,MSR_KERNEL
+	FIX_SRR1(r10,r12)
+	mtspr	SRR0,r9
+	mtspr	SRR1,r10
 	SYNC
 	RFI
 #endif /* CONFIG_PPC_ISERIES */
 
-#ifdef SHOW_SYSCALLS_TASK
-	.data
-show_syscalls_task:
-	.long	-1
-#endif
-
 /*
  * Handle a system call.
  */
-	.text
 	.stabs	"arch/ppc/kernel/",N_SO,0,0,0f
 	.stabs	"entry.S",N_SO,0,0,0f
 0:
 
 _GLOBAL(DoSyscall)
 	stw	r0,THREAD+LAST_SYSCALL(r2)
+	stw	r3,ORIG_GPR3(r1)
+	li	r12,0
+	stw	r12,RESULT(r1)
 	lwz	r11,_CCR(r1)	/* Clear SO bit in CR */
-	lis	r10,0x1000
-	andc	r11,r11,r10
+	rlwinm	r11,r11,0,4,2
 	stw	r11,_CCR(r1)
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
-	lis	r31,show_syscalls_task@ha
-	lwz	r31,show_syscalls_task@l(r31)
-	cmp	0,r2,r31
-	bne	1f
-#endif
-	lis	r3,7f@ha
-	addi	r3,r3,7f@l
-	lwz	r4,GPR0(r1)
-	lwz	r5,GPR3(r1)
-	lwz	r6,GPR4(r1)
-	lwz	r7,GPR5(r1)
-	lwz	r8,GPR6(r1)
-	lwz	r9,GPR7(r1)
-	bl	printk
-	lis	r3,77f@ha
-	addi	r3,r3,77f@l
-	lwz	r4,GPR8(r1)
-	lwz	r5,GPR9(r1)
-	mr	r6,r2
-	bl	printk
-	lwz	r0,GPR0(r1)
-	lwz	r3,GPR3(r1)
-	lwz	r4,GPR4(r1)
-	lwz	r5,GPR5(r1)
-	lwz	r6,GPR6(r1)
-	lwz	r7,GPR7(r1)
-	lwz	r8,GPR8(r1)
-1:
+	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
-	cmpi	0,r0,0x7777	/* Special case for 'sys_sigreturn' */
-	beq-	10f
-	cmpi    0,r0,0x6666     /* Special case for 'sys_rt_sigreturn' */
-	beq-    16f
+	cmpli	0,r0,NR_syscalls
+	bge-	66f
 	rlwinm	r10,r1,0,0,18	/* current_thread_info() */
 	lwz	r10,TI_FLAGS(r10)
 	andi.	r10,r10,_TIF_SYSCALL_TRACE
-	bne-	50f
-	cmpli	0,r0,NR_syscalls
-	bge-	66f
+	bne-	syscall_dotrace
+syscall_dotrace_cont:
 	lis	r10,sys_call_table@h
 	ori	r10,r10,sys_call_table@l
 	slwi	r0,r0,2
 	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
-	cmpi	0,r10,0
-	beq-	66f
 	mtlr	r10
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
-	.globl	ret_from_syscall_1
-ret_from_syscall_1:
-20:	stw	r3,RESULT(r1)	/* Save result */
+	.globl	ret_from_syscall
+ret_from_syscall:
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
-	cmp	0,r2,r31
-	bne	91f
+	bl	do_show_syscall_exit
 #endif
-	mr	r4,r3
-	lis	r3,79f@ha
-	addi	r3,r3,79f@l
-	bl	printk
-	lwz	r3,RESULT(r1)
-91:
-#endif
-	li	r10,-_LAST_ERRNO
-	cmpl	0,r3,r10
-	blt	30f
+	mr	r6,r3
+	li	r11,-_LAST_ERRNO
+	cmpl	0,r3,r11
+	blt+	30f
 	neg	r3,r3
 	cmpi	0,r3,ERESTARTNOHAND
 	bne	22f
@@ -202,24 +154,50 @@
 22:	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
 	oris	r10,r10,0x1000
 	stw	r10,_CCR(r1)
-30:	stw	r3,GPR3(r1)	/* Update return value */
-	b	ret_from_except
+
+	/* disable interrupts so current_thread_info()->flags can't change */
+30:	li	r10,MSR_KERNEL	/* doesn't include MSR_EE */
+	SYNC
+	MTMSRD(r10)
+	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
+	lwz	r9,TI_FLAGS(r12)
+	andi.	r0,r9,(_TIF_SYSCALL_TRACE|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	bne-	syscall_exit_work
+syscall_exit_cont:
+	PPC405_ERR77(0,r1)
+	stwcx.	r0,0,r1			/* to clear the reservation */
+	lwz	r4,_LINK(r1)
+	lwz	r5,_CCR(r1)
+	mtlr	r4
+	mtcr	r5
+	lwz	r7,_NIP(r1)
+	lwz	r8,_MSR(r1)
+	FIX_SRR1(r8, r0)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	mtspr	SRR0,r7
+	mtspr	SRR1,r8
+	SYNC
+	RFI
+
 66:	li	r3,ENOSYS
 	b	22b
-/* sys_sigreturn */
-10:	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	sys_sigreturn
-	cmpi    0,r3,0          /* Check for restarted system call */
-	bge     ret_from_except
-	b       20b
-/* sys_rt_sigreturn */
-16:	addi    r3,r1,STACK_FRAME_OVERHEAD
-	bl      sys_rt_sigreturn
-	cmpi	0,r3,0		/* Check for restarted system call */
-	bge	ret_from_except
-	b	20b
+
+	.globl	ret_from_fork
+ret_from_fork:
+	REST_NVGPRS(r1)
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+	bl	schedule_tail
+#endif
+	li	r3,0
+	b	ret_from_syscall
+
 /* Traced system call support */
-50:	bl	do_syscall_trace
+syscall_dotrace:
+	SAVE_NVGPRS(r1)
+	li	r0,0xc00
+	stw	r0,TRAP(r1)
+	bl	do_syscall_trace
 	lwz	r0,GPR0(r1)	/* Restore original registers */
 	lwz	r3,GPR3(r1)
 	lwz	r4,GPR4(r1)
@@ -227,43 +205,167 @@
 	lwz	r6,GPR6(r1)
 	lwz	r7,GPR7(r1)
 	lwz	r8,GPR8(r1)
-	lwz	r9,GPR9(r1)
-	cmpli	0,r0,NR_syscalls
-	bge-	66f
-	lis	r10,sys_call_table@h
-	ori	r10,r10,sys_call_table@l
-	slwi	r0,r0,2
-	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
-	cmpi	0,r10,0
-	beq-	66f
-	mtlr	r10
-	addi	r9,r1,STACK_FRAME_OVERHEAD
-	blrl			/* Call handler */
-	.globl	ret_from_syscall_2
-ret_from_syscall_2:
-	stw	r3,RESULT(r1)	/* Save result */	
-	stw	r3,GPR0(r1)	/* temporary gross hack to make strace work */
-	li	r10,-_LAST_ERRNO
-	cmpl	0,r3,r10
-	blt	60f
-	neg	r3,r3
-	cmpi	0,r3,ERESTARTNOHAND
-	bne	52f
-	li	r3,EINTR
-52:	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
-	oris	r10,r10,0x1000
-	stw	r10,_CCR(r1)
-60:	stw	r3,GPR3(r1)	/* Update return value */
+	REST_NVGPRS(r1)
+	b	syscall_dotrace_cont
+
+syscall_exit_work:
+	stw	r6,RESULT(r1)	/* Save result */
+	stw	r3,GPR3(r1)	/* Update return value */
+	andi.	r0,r9,_TIF_SYSCALL_TRACE
+	beq	5f
+	stw	r6,GPR0(r1)	/* temporary gross hack to make strace work */
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)		/* re-enable interrupts */
+	lwz	r4,TRAP(r1)
+	andi.	r4,r4,1
+	beq	4f
+	SAVE_NVGPRS(r1)
+	li	r4,0xc00
+	stw	r4,TRAP(r1)
+4:
 	bl	do_syscall_trace
-	b	ret_from_except
-66:	li	r3,ENOSYS
-	b	52b
+	REST_NVGPRS(r1)
+2:
+	lwz	r3,GPR3(r1)
+	li	r10,MSR_KERNEL	/* doesn't include MSR_EE */
+	SYNC
+	MTMSRD(r10)		/* disable interrupts again */
+	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
+	lwz	r9,TI_FLAGS(r12)
+5:
+	andi.	r0,r9,_TIF_NEED_RESCHED
+	bne	1f
+	lwz	r5,_MSR(r1)
+	andi.	r5,r5,MSR_PR
+	beq	syscall_exit_cont
+	andi.	r0,r9,_TIF_SIGPENDING
+	beq	syscall_exit_cont
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)		/* re-enable interrupts */
+	b	syscall_do_signal
+1:
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)		/* re-enable interrupts */
+	bl	schedule
+	b	2b
+
 #ifdef SHOW_SYSCALLS
+do_show_syscall:
+#ifdef SHOW_SYSCALLS_TASK
+	lis	r11,show_syscalls_task@ha
+	lwz	r11,show_syscalls_task@l(r11)
+	cmp	0,r2,r11
+	bnelr
+#endif
+	stw	r31,GPR31(r1)
+	mflr	r31
+	lis	r3,7f@ha
+	addi	r3,r3,7f@l
+	lwz	r4,GPR0(r1)
+	lwz	r5,GPR3(r1)
+	lwz	r6,GPR4(r1)
+	lwz	r7,GPR5(r1)
+	lwz	r8,GPR6(r1)
+	lwz	r9,GPR7(r1)
+	bl	printk
+	lis	r3,77f@ha
+	addi	r3,r3,77f@l
+	lwz	r4,GPR8(r1)
+	mr	r5,r2
+	bl	printk
+	lwz	r0,GPR0(r1)
+	lwz	r3,GPR3(r1)
+	lwz	r4,GPR4(r1)
+	lwz	r5,GPR5(r1)
+	lwz	r6,GPR6(r1)
+	lwz	r7,GPR7(r1)
+	lwz	r8,GPR8(r1)
+	mtlr	r31
+	lwz	r31,GPR31(r1)
+	blr
+
+do_show_syscall_exit:
+#ifdef SHOW_SYSCALLS_TASK
+	lis	r11,show_syscalls_task@ha
+	lwz	r11,show_syscalls_task@l(r11)
+	cmp	0,r2,r11
+	bnelr
+#endif
+	stw	r31,GPR31(r1)
+	mflr	r31
+	stw	r3,RESULT(r1)	/* Save result */
+	mr	r4,r3
+	lis	r3,79f@ha
+	addi	r3,r3,79f@l
+	bl	printk
+	lwz	r3,RESULT(r1)
+	mtlr	r31
+	lwz	r31,GPR31(r1)
+	blr
+
 7:	.string	"syscall %d(%x, %x, %x, %x, %x, "
-77:	.string	"%x, %x), current=%p\n"
+77:	.string	"%x), current=%p\n"
 79:	.string	" -> %x\n"
 	.align	2,0
+
+#ifdef SHOW_SYSCALLS_TASK
+	.data
+	.globl	show_syscalls_task
+show_syscalls_task:
+	.long	-1
+	.text
 #endif
+#endif /* SHOW_SYSCALLS */
+
+/*
+ * The sigsuspend and rt_sigsuspend system calls can call do_signal
+ * and thus put the process into the stopped state where we might
+ * want to examine its user state with ptrace.  Therefore we need
+ * to save all the nonvolatile registers (r13 - r31) before calling
+ * the C code.
+ */
+	.globl	ppc_sigsuspend
+ppc_sigsuspend:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
+	stw	r0,TRAP(r1)		/* register set saved */
+	b	sys_sigsuspend
+
+	.globl	ppc_rt_sigsuspend
+ppc_rt_sigsuspend:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30
+	stw	r0,TRAP(r1)
+	b	sys_rt_sigsuspend
+
+	.globl	ppc_fork
+ppc_fork:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
+	stw	r0,TRAP(r1)		/* register set saved */
+	b	sys_fork
+
+	.globl	ppc_vfork
+ppc_vfork:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
+	stw	r0,TRAP(r1)		/* register set saved */
+	b	sys_vfork
+
+	.globl	ppc_clone
+ppc_clone:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
+	stw	r0,TRAP(r1)		/* register set saved */
+	b	sys_clone
 
 /*
  * This routine switches between two different tasks.  The process
@@ -290,25 +392,26 @@
 	stwu	r1,-INT_FRAME_SIZE(r1)
 	mflr	r0
 	stw	r0,INT_FRAME_SIZE+4(r1)
-	/* r3-r13 are caller saved -- Cort */
-	SAVE_8GPRS(14, r1)
-	SAVE_10GPRS(22, r1)
+	/* r3-r12 are caller saved -- Cort */
+	SAVE_NVGPRS(r1)
 	stw	r0,_NIP(r1)	/* Return to switch caller */
-	mfmsr	r22
+	mfmsr	r11
 	li	r0,MSR_FP	/* Disable floating-point */
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
 	oris	r0,r0,MSR_VEC@h	/* Disable altivec */
+	mfspr	r12,SPRN_VRSAVE	/* save vrsave register value */
+	stw	r12,THREAD+THREAD_VRSAVE(r2)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
-	and.	r0,r0,r22	/* FP or altivec enabled? */
+	and.	r0,r0,r11	/* FP or altivec enabled? */
 	beq+	1f
-	andc	r22,r22,r0
-	mtmsr	r22
+	andc	r11,r11,r0
+	MTMSRD(r11)
 	isync
-1:	stw	r22,_MSR(r1)
-	mfcr	r20
-	stw	r20,_CCR(r1)
+1:	stw	r11,_MSR(r1)
+	mfcr	r10
+	stw	r10,_CCR(r1)
 	stw	r1,KSP(r3)	/* Set old stack pointer */
 
 	tophys(r0,r4)
@@ -318,148 +421,247 @@
 	/* save the old current 'last' for return value */
 	mr	r3,r2
 	addi	r2,r4,-THREAD	/* Update current */
+
+#ifdef CONFIG_ALTIVEC
+BEGIN_FTR_SECTION
+	lwz	r0,THREAD+THREAD_VRSAVE(r2)
+	mtspr	SPRN_VRSAVE,r0		/* if G4, restore VRSAVE reg */
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+#endif /* CONFIG_ALTIVEC */
+
 	lwz	r0,_CCR(r1)
 	mtcrf	0xFF,r0
-	/* r3-r13 are destroyed -- Cort */
-	REST_2GPRS(14, r1)
-	REST_8GPRS(16, r1)
-	REST_8GPRS(24, r1)
+	/* r3-r12 are destroyed -- Cort */
+	REST_NVGPRS(r1)
 
 	lwz	r4,_NIP(r1)	/* Return to _switch caller in new task */
 	mtlr	r4
 	addi	r1,r1,INT_FRAME_SIZE
 	blr
 
-	.globl	ret_from_fork
-ret_from_fork:
-#if CONFIG_SMP || CONFIG_PREEMPT
-	bl	schedule_tail
-#endif
-	rlwinm	r3,r1,0,0,18
-	lwz	r3,TI_FLAGS(r3)
-	andi.	r0,r3,_TIF_SYSCALL_TRACE
+	.globl	sigreturn_exit
+sigreturn_exit:
+	subi	r1,r3,STACK_FRAME_OVERHEAD
+	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
+	lwz	r9,TI_FLAGS(r12)
+	andi.	r0,r9,_TIF_SYSCALL_TRACE
 	bnel-	do_syscall_trace
-	b	ret_from_except
+	/* fall through */
+
+	.globl	ret_from_except_full
+ret_from_except_full:
+	REST_NVGPRS(r1)
+	/* fall through */
 
-	.globl	ret_from_intercept
-ret_from_intercept:
-	/*
-	 * We may be returning from RTL and cannot do the normal checks
-	 * -- Cort
-	 */
-	cmpi	0,r3,0
-	beq	restore
 	.globl	ret_from_except
 ret_from_except:
-	REST_10GPRS(13,r1)
-	REST_8GPRS(23,r1)
-	REST_GPR(31,r1)
-
 	/* Hard-disable interrupts so that current_thread_info()->flags
 	 * can't change between when we test it and when we return
 	 * from the interrupt. */
-recheck:
-	mfmsr	r10
-	rlwinm	r0,r10,0,17,15	/* clear MSR_EE in r0 */
-#ifdef CONFIG_4xx
- 	rlwinm	r0,r0,0,23,21	/* clear MSR_DE in r0 */
-#endif
+	li	r10,MSR_KERNEL	/* doesn't include EE */
 	SYNC			/* Some chip revs have problems here... */
-	mtmsr	r0		/* Update machine state */
+	MTMSRD(r10)		/* disable interrupts */
 
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r3,r3,MSR_PR
-	beq+	restore		/* if not, just restore regs and return */
+	beq	resume_kernel
 
 	/* Check current_thread_info()->flags */
-	rlwinm	r3,r1,0,0,18
-	lwz	r3,TI_FLAGS(r3)
-	andi.	r0,r3,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+	rlwinm	r9,r1,0,0,18
+	lwz	r9,TI_FLAGS(r9)
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
 	bne	do_work
 
-	.globl ret_to_user_hook	
-ret_to_user_hook:
-	nop
+#ifdef CONFIG_PREEMPT
+	b	restore
 
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
-	lwz	r0,THREAD+THREAD_VRSAVE(r2)
-	mtspr	SPRN_VRSAVE,r0		/* if G4, restore VRSAVE reg */
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif /* CONFIG_ALTIVEC */
-
-	addi	r0,r1,INT_FRAME_SIZE	/* size of frame */
-	stw	r0,THREAD+KSP(r2)	/* save kernel stack pointer */
-
-#ifndef CONFIG_PPC_ISERIES
-	tophys(r8,r1)
-	CLR_TOP32(r8)
-	mtspr	SPRG2,r8		/* phys exception stack pointer */
-#else /* CONFIG_PPC_ISERIES */
-	mfspr	r2,SPRG1		/* Get Paca address */
-	stw	r1,PACAKSAVE(r2)	/* save exception stack pointer */
-#endif /* CONFIG_PPC_ISERIES */
+resume_kernel:
+	rlwinm	r9,r1,0,0,18	/* check current_thread_info->preempt_count */
+	lwz	r3,TI_PREEMPT(r9)
+	cmpwi	0,r0,0		/* if non-zero, just restore regs and return */
+	bne	restore
+	lwz	r9,TI_FLAGS(r9)
+	andi.	r0,r9,_TIF_NEED_RESCHED
+	bne	do_work
+#else
+resume_kernel:
+#endif /* CONFIG_PREEMPT */
 
 	/* interrupts are hard-disabled at this point */
 restore:
-	REST_8GPRS(4, r1)
-	REST_GPR(12, r1)
-	lwz	r3,_XER(r1)
-	mtspr	XER,r3
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	REST_4GPRS(3, r1)
+	REST_2GPRS(7, r1)
+
+	lwz	r10,_XER(r1)
+	lwz	r11,_CTR(r1)
+	mtspr	XER,r10
+	mtctr	r11
 
 	PPC405_ERR77(0,r1)
 	stwcx.	r0,0,r1			/* to clear the reservation */
 
-	lwz	r3,_CTR(r1)
-	lwz	r0,_LINK(r1)
-	mtctr	r3
-	mtlr	r0
-
-	lwz	r0,_MSR(r1)
-	lwz	r3,_CCR(r1)
-	FIX_SRR1(r0,r2)
-	lwz	r2,_NIP(r1)
-	mtcrf	0xFF,r3
+#ifndef CONFIG_4xx
+	lwz	r9,_MSR(r1)
+	andi.	r10,r9,MSR_RI		/* check if this exception occurred */
+	beql	nonrecoverable		/* at a bad place (MSR:RI = 0) */
+
+	lwz	r10,_CCR(r1)
+	lwz	r11,_LINK(r1)
+	mtcrf	0xFF,r10
+	mtlr	r11
 
 	/*
-	 * We can't afford to take an exception between setting SRR0/1
-	 * and the rfi.  Since GPR0(r1) .. GPR3(r1) are in the same cache
-	 * line, loading r3 here should mean that we should have a HPTE
-	 * (for classic PPC) or TLB entry (for 4xx/8xx) for that cache
-	 * line, even if it isn't covered by a BAT register.
-	 * In addition, the cache line itself will be in L1 cache.
-	 * There is still the possibility of the HPTE getting evicted
-	 * on SMP systems.
+	 * Once we put values in SRR0 and SRR1, we are in a state
+	 * where exceptions are not recoverable, since taking an
+	 * exception will trash SRR0 and SRR1.  Therefore we clear the
+	 * MSR:RI bit to indicate this.  If we do take an exception,
+	 * we can't return to the point of the exception but we
+	 * can restart the exception exit path at the label
+	 * exc_exit_restart below.  -- paulus
 	 */
-	lwz	r3,GPR3(r1)
-
-	mtspr	SRR1,r0
-	mtspr	SRR0,r2
-	lwz	r0,GPR0(r1)
-	lwz	r2,GPR2(r1)
+	li	r10,MSR_KERNEL & ~MSR_RI
+	SYNC
+	MTMSRD(r10)		/* clear the RI bit */
+	.globl exc_exit_restart
+exc_exit_restart:
+	lwz	r9,_MSR(r1)
+	lwz	r12,_NIP(r1)
+	FIX_SRR1(r9,r10)
+	mtspr	SRR0,r12
+	mtspr	SRR1,r9
+	REST_4GPRS(9, r1)
 	lwz	r1,GPR1(r1)
+	.globl exc_exit_restart_end
+exc_exit_restart_end:
 	SYNC
-	PPC405_ERR77_SYNC
 	RFI
 
+#else /* CONFIG_4xx */
+	/*
+	 * This is a bit different on 4xx because 4xx doesn't have
+	 * the RI bit in the MSR, and because we have critical
+	 * exceptions, for which we need to restore SRR0 and SRR1
+	 * and then use SRR2/SRR3 to return from the exception.
+	 * The TLB miss handler checks if we have interrupted
+	 * the exception exit path and restarts it if so.
+	 */
+	lwz	r10,TRAP(r1)		/* check for critical exception */
+	lwz	r11,_LINK(r1)
+	andi.	r10,r10,2
+	mtlr	r11
+	lwz	r10,_CCR(r1)
+	bne	crit_exc_exit
+	mtcrf	0xff,r10
+	REST_2GPRS(9, r1)
+	.globl exc_exit_restart
+exc_exit_restart:
+	lwz	r11,_NIP(r1)
+	lwz	r12,_MSR(r1)
+exc_exit_start:
+	mtspr	SRR0,r11
+	mtspr	SRR1,r12
+	REST_2GPRS(11, r1)
+	lwz	r1,GPR1(r1)
+	.globl exc_exit_restart_end
+exc_exit_restart_end:
+	PPC405_ERR77_SYNC
+	rfi
+crit_exc_exit:
+	mtcrf	0xff,r10
+	/* avoid any possible TLB misses here by turning off MSR.DR, we
+	 * assume the instructions here are mapped by a pinned TLB entry */
+	li	r10,MSR_IR
+	mtmsr	r10
+	isync
+	tophys(r1, r1)
+	lwz	r9,_SRR0(r1)
+	lwz	r10,_SRR1(r1)
+	mtspr	SRR0,r9
+	lwz	r11,_NIP(r1)
+	mtspr	SRR1,r10
+	lwz	r12,_MSR(r1)
+	mtspr	SRR2,r11
+	mtspr	SRR3,r12
+	REST_4GPRS(9, r1)
+	lwz	r1,GPR1(r1)
+	PPC405_ERR77_SYNC
+	rfci
+#endif /* CONFIG_4xx */
+
+recheck:
+	li	r10,MSR_KERNEL
+	SYNC
+	MTMSRD(r10)		/* disable interrupts */
+	rlwinm	r9,r1,0,0,18
+	lwz	r9,TI_FLAGS(r9)
+#ifdef CONFIG_PREEMPT
+	lwz	r0,_MSR(r1)
+	li	r11,_TIF_NEED_RESCHED
+	/* move MSR_PR bit down to TIF_SIGPENDING (0x4) bit */
+	rlwimi	r11,r0,18+TIF_SIGPENDING,31-TIF_SIGPENDING,31-TIF_SIGPENDING
+	and.	r0,r9,r11
+#else /* CONFIG_PREEMPT */
+	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
+#endif /* CONFIG_PREEMPT */
+	beq	restore
 do_work:
 	ori	r10,r10,MSR_EE
 	SYNC
-	mtmsr	r10		/* hard-enable interrupts */
-	andi.	r0,r3,_TIF_NEED_RESCHED
+	MTMSRD(r10)		/* hard-enable interrupts */
+	andi.	r0,r9,_TIF_NEED_RESCHED
 	beq	1f
 	bl	schedule
 	b	recheck
 1:
-	andi.	r0,r3,_TIF_SIGPENDING
+syscall_do_signal:
+	/* save r13-r31 in the exception frame, if not already done */
+	lwz	r3,TRAP(r1)
+	andi.	r0,r3,1
 	beq	2f
-	li	r3,0
+	SAVE_NVGPRS(r1)
+	rlwinm	r3,r3,0,0,30
+	stw	r3,TRAP(r1)
+2:	li	r3,0
 	addi	r4,r1,STACK_FRAME_OVERHEAD
 	bl	do_signal
+	REST_NVGPRS(r1)
 	b	recheck
-2:
-	/* nobody uses the TIF_NOTIFY_RESUME bit yet */
-	b	recheck
+
+/*
+ * We come here when we are at the end of handling an exception
+ * that occurred at a place where taking an exception will lose
+ * state information, such as the contents of SRR0 and SRR1.
+ */
+nonrecoverable:
+	lis	r10,exc_exit_restart_end@ha
+	addi	r10,r10,exc_exit_restart_end@l
+	cmplw	r12,r10
+	bge	3f
+	lis	r11,exc_exit_restart@ha
+	addi	r11,r11,exc_exit_restart@l
+	cmplw	r12,r11
+	blt	3f
+	lis	r10,ee_restarts@ha
+	lwz	r12,ee_restarts@l(r10)
+	addi	r12,r12,1
+	stw	r12,ee_restarts@l(r10)
+	mr	r12,r11		/* restart at exc_exit_restart */
+	blr
+3:	/* OK, we can't recover, kill this process */
+	lwz	r3,TRAP(r1)
+	andi.	r0,r3,1
+	beq	4f
+	SAVE_NVGPRS(r1)
+	rlwinm	r3,r3,0,0,30
+	stw	r3,TRAP(r1)
+4:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	nonrecoverable_exception
+	/* shouldn't return */
+	b	4b
+
+	.comm	ee_restarts,4
 
 /*
  * PROM code for specific machines follows.  Put it 
@@ -472,39 +674,43 @@
  * called with the MMU off.
  */
 _GLOBAL(enter_rtas)
+	stwu	r1,-INT_FRAME_SIZE(r1)
 	mflr	r0
-	stw	r0,20(r1)
+	stw	r0,INT_FRAME_SIZE+4(r1)
 	lis	r4,rtas_data@ha
 	lwz	r4,rtas_data@l(r4)
 	lis	r6,1f@ha	/* physical return address for rtas */
 	addi	r6,r6,1f@l
-	addis	r6,r6,-KERNELBASE@h
-	subi	r7,r1,INT_FRAME_SIZE
-	addis	r7,r7,-KERNELBASE@h
+	tophys(r6,r6)
+	tophys(r7,r1)
 	lis	r8,rtas_entry@ha
 	lwz	r8,rtas_entry@l(r8)
 	mfmsr	r9
 	stw	r9,8(r1)
-	li	r0,0
-	ori	r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_FE0|MSR_FE1
-	andc	r0,r9,r0
-	li	r10,MSR_IR|MSR_DR|MSR_FP
-	andc	r9,r0,r10
+	li	r0,MSR_KERNEL
 	SYNC			/* disable interrupts so SRR0/1 */
-	mtmsr	r0		/* don't get trashed */
+	MTMSRD(r0)		/* don't get trashed */
+	li	r9,MSR_
 	mtlr	r6
 	CLR_TOP32(r7)
 	mtspr	SPRG2,r7
 	mtspr	SRR0,r8
 	mtspr	SRR1,r9
 	RFI
-1:	addis	r9,r1,-KERNELBASE@h
-	lwz	r8,20(r9)	/* get return address */
+1:	tophys(r9,r1)
+	lwz	r8,INT_FRAME_SIZE+4(r9)	/* get return address */
 	lwz	r9,8(r9)	/* original msr value */
 	FIX_SRR1(r9,r0)
+	addi	r1,r1,INT_FRAME_SIZE
 	li	r0,0
 	mtspr	SPRG2,r0
 	mtspr	SRR0,r8
 	mtspr	SRR1,r9
 	RFI			/* return to caller */
+
+	.globl	machine_check_in_rtas
+machine_check_in_rtas:
+	twi	31,0,0
+	/* XXX load up BATs and panic */
+
 #endif /* CONFIG_ALL_PPC */
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/head.S	Thu May  9 15:21:01 2002
@@ -34,7 +34,7 @@
 #include <asm/cache.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 
 #ifdef CONFIG_APUS
 #include <asm/amigappc.h>
@@ -233,55 +233,92 @@
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG	\
-	mtspr	SPRG0,r20;	\
-	mtspr	SPRG1,r21;	\
-	mfcr	r20;		\
-	mfspr	r21,SPRG2;		/* exception stack to use from */ \
-	cmpwi	0,r21,0;		/* user mode or RTAS */ \
-	bne	1f;		\
-	tophys(r21,r1);			/* use tophys(kernel sp) otherwise */ \
-	subi	r21,r21,INT_FRAME_SIZE;	/* alloc exc. frame */\
-1:	CLR_TOP32(r21);		\
-	stw	r20,_CCR(r21);		/* save registers */ \
-	stw	r22,GPR22(r21);	\
-	stw	r23,GPR23(r21);	\
-	mfspr	r20,SPRG0;	\
-	stw	r20,GPR20(r21);	\
-	mfspr	r22,SPRG1;	\
-	stw	r22,GPR21(r21);	\
-	mflr	r20;		\
-	stw	r20,_LINK(r21);	\
-	mfctr	r22;		\
-	stw	r22,_CTR(r21);	\
-	mfspr	r20,XER;	\
-	stw	r20,_XER(r21);	\
-	mfspr	r22,SRR0;	\
-	mfspr	r23,SRR1;	\
-	stw	r0,GPR0(r21);	\
-	stw	r1,GPR1(r21);	\
-	stw	r2,GPR2(r21);	\
-	stw	r1,0(r21);	\
-	tovirt(r1,r21);			/* set new kernel sp */	\
-	SAVE_4GPRS(3, r21);	\
-	SAVE_GPR(7, r21);
+	mtspr	SPRG0,r10;	\
+	mtspr	SPRG1,r11;	\
+	mfcr	r10;		\
+	EXCEPTION_PROLOG_1;	\
+	EXCEPTION_PROLOG_2
+
+#define EXCEPTION_PROLOG_1	\
+	mfspr	r11,SRR1;		/* check whether user or kernel */ \
+	andi.	r11,r11,MSR_PR;	\
+	tophys(r11,r1);			/* use tophys(r1) if kernel */ \
+	beq	1f;		\
+	mfspr	r11,SPRG3;	\
+	lwz	r11,THREAD_INFO-THREAD(r11);	\
+	addi	r11,r11,THREAD_SIZE;	\
+	tophys(r11,r11);	\
+1:	subi	r11,r11,INT_FRAME_SIZE	/* alloc exc. frame */
+
+
+#define EXCEPTION_PROLOG_2	\
+	CLR_TOP32(r11);		\
+	stw	r10,_CCR(r11);		/* save registers */ \
+	stw	r12,GPR12(r11);	\
+	stw	r9,GPR9(r11);	\
+	mfspr	r10,SPRG0;	\
+	stw	r10,GPR10(r11);	\
+	mfspr	r12,SPRG1;	\
+	stw	r12,GPR11(r11);	\
+	mflr	r10;		\
+	stw	r10,_LINK(r11);	\
+	mfspr	r12,SRR0;	\
+	mfspr	r9,SRR1;	\
+	stw	r1,GPR1(r11);	\
+	stw	r1,0(r11);	\
+	tovirt(r1,r11);			/* set new kernel sp */	\
+	li	r10,MSR_;		/* can now take exceptions again */ \
+	MTMSRD(r10);			/* (except for mach check in rtas) */ \
+	stw	r0,GPR0(r11);	\
+	SAVE_4GPRS(3, r11);	\
+	SAVE_2GPRS(7, r11)
+
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
- * r21, r22 (SRR0), and r23 (SRR1).
+ * r11, r12 (SRR0), and r9 (SRR1).
+ *
+ * Note2: once we have set r1 we are in a position to take exceptions
+ * again, and we could thus set MSR:RI at that point.
  */
 
 /*
  * Exception vectors.
  */
-#define STD_EXCEPTION(n, label, hdlr)		\
+#define EXCEPTION(n, label, hdlr, xfer)		\
 	. = n;					\
 label:						\
 	EXCEPTION_PROLOG;			\
 	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
-	li	r20,MSR_KERNEL;			\
-	bl	transfer_to_handler; 		\
-i##n:						\
-	.long	hdlr;				\
-	.long	ret_from_except
+	xfer(n, hdlr)
+
+#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret)	\
+	li	r10,trap;					\
+	stw	r10,TRAP(r11);					\
+	li	r10,MSR_KERNEL;					\
+	copyee(r10, r9);					\
+	bl	tfer;						\
+i##n:								\
+	.long	hdlr;						\
+	.long	ret
+
+#define COPY_EE(d, s)		rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)		\
+	EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full,	\
+			  ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
+			  ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)	\
+	EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
+			  ret_from_except)
 
 /* System reset */
 /* core99 pmac starts the seconary here by changing the vector, and
@@ -290,11 +327,43 @@
 	. = 0x100
 	b	__secondary_start_gemini
 #else
-	STD_EXCEPTION(0x100, Reset, UnknownException)
+	EXCEPTION(0x100, Reset, UnknownException, EXC_XFER_STD)
 #endif
 
 /* Machine check */
-	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+/*
+ * On CHRP, this is complicated by the fact that we could get a
+ * machine check inside RTAS, and we have no guarantee that certain
+ * critical registers will have the values we expect.  The set of
+ * registers that might have bad values includes all the GPRs
+ * and all the BATs.  We indicate that we are in RTAS by putting
+ * a non-zero value, the address of the exception frame to use,
+ * in SPRG2.  The machine check handler checks SPRG2 and uses its
+ * value if it is non-zero.  If we ever needed to free up SPRG2,
+ * we could use a field in the thread_info or thread_struct instead.
+ * (Other exception handlers assume that r1 is a valid kernel stack
+ * pointer when we take an exception from supervisor mode.)
+ *	-- paulus.
+ */
+	. = 0x200
+MachineCheck:
+	mtspr	SPRG0,r10
+	mtspr	SPRG1,r11
+	mfcr	r10
+#ifdef CONFIG_ALL_PPC
+	mfspr	r11,SPRG2
+	cmpwi	0,r11,0
+	bne	7f
+#endif /* CONFIG_ALL_PPC */
+	EXCEPTION_PROLOG_1
+7:	EXCEPTION_PROLOG_2
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_ALL_PPC
+	mfspr	r4,SPRG2
+	cmpwi	cr1,r4,0
+	bne	cr1,machine_check_in_rtas
+#endif
+	EXC_XFER_STD(0x200, MachineCheckException)
 
 /* Data access exception. */
 	. = 0x300
@@ -305,37 +374,24 @@
 DataAccess:
 	EXCEPTION_PROLOG
 #endif /* CONFIG_PPC64BRIDGE */
-	mfspr	r20,DSISR
-	andis.	r0,r20,0xa470		/* weird error? */
+	mfspr	r10,DSISR
+	andis.	r0,r10,0xa470		/* weird error? */
 	bne	1f			/* if not, try to put a PTE */
 	mfspr	r4,DAR			/* into the hash table */
-	rlwinm	r3,r20,32-15,21,21	/* DSISR_STORE -> _PAGE_RW */
+	rlwinm	r3,r10,32-15,21,21	/* DSISR_STORE -> _PAGE_RW */
 	bl	hash_page
-1:	stw	r20,_DSISR(r21)
-	mr	r5,r20
+1:	stw	r10,_DSISR(r11)
+	mr	r5,r10
 	mfspr	r4,DAR
-	stw	r4,_DAR(r21)
+	stw	r4,_DAR(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-i0x300:
-	.long	do_page_fault
-	.long	ret_from_except
+	andi.	r0,r9,MSR_PR		/* set cr0.eq if from kernel */
+	EXC_XFER_EE_LITE(0x300, do_page_fault)
 
 #ifdef CONFIG_PPC64BRIDGE
 /* SLB fault on data access. */
 	. = 0x380
 	b	DataSegment
-DataSegmentCont:
-	mfspr	r4,DAR
-	stw	r4,_DAR(r21)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	UnknownException
-	.long	ret_from_except
 #endif /* CONFIG_PPC64BRIDGE */
 
 /* Instruction access exception. */
@@ -347,135 +403,79 @@
 InstructionAccess:
 	EXCEPTION_PROLOG
 #endif /* CONFIG_PPC64BRIDGE */
-	andis.	r0,r23,0x4000		/* no pte found? */
+	andis.	r0,r9,0x4000		/* no pte found? */
 	beq	1f			/* if so, try to put a PTE */
 	li	r3,0			/* into the hash table */
-	mr	r4,r22			/* SRR0 is fault address */
+	mr	r4,r12			/* SRR0 is fault address */
 	bl	hash_page
 1:	addi	r3,r1,STACK_FRAME_OVERHEAD
-	mr	r4,r22
-	mr	r5,r23
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-i0x400:
-	.long	do_page_fault
-	.long	ret_from_except
+	mr	r4,r12
+	mr	r5,r9
+	andi.	r0,r9,MSR_PR		/* set cr0.eq if from kernel */
+	EXC_XFER_EE_LITE(0x400, do_page_fault)
 
 #ifdef CONFIG_PPC64BRIDGE
 /* SLB fault on instruction access. */
 	. = 0x480
 	b	InstructionSegment
-InstructionSegmentCont:
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	UnknownException
-	.long	ret_from_except
 #endif /* CONFIG_PPC64BRIDGE */
 
 /* External interrupt */
-	. = 0x500;
-HardwareInterrupt:
-	EXCEPTION_PROLOG;
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	li	r4,0
-	bl	transfer_to_handler
-	.globl do_IRQ_intercept
-do_IRQ_intercept:
-	.long	do_IRQ;
-	.long	ret_from_intercept
+	EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
 
 /* Alignment exception */
 	. = 0x600
 Alignment:
 	EXCEPTION_PROLOG
 	mfspr	r4,DAR
-	stw	r4,_DAR(r21)
+	stw	r4,_DAR(r11)
 	mfspr	r5,DSISR
-	stw	r5,_DSISR(r21)
+	stw	r5,_DSISR(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-i0x600:
-	.long	AlignmentException
-	.long	ret_from_except
+	EXC_XFER_EE(0x600, AlignmentException)
 
 /* Program check exception */
-	. = 0x700
-ProgramCheck:
-	EXCEPTION_PROLOG
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-i0x700:
-	.long	ProgramCheckException
-	.long	ret_from_except
+	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE)
 
 /* Floating-point unavailable */
 	. = 0x800
 FPUnavailable:
 	EXCEPTION_PROLOG
 	bne	load_up_fpu		/* if from user, just load it up */
-	li	r20,MSR_KERNEL
-	bl	transfer_to_handler	/* if from kernel, take a trap */
-i0x800:
-	.long	KernelFP
-	.long	ret_from_except
-
-	. = 0x900
-Decrementer:
-	EXCEPTION_PROLOG
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	bl	transfer_to_handler
-	.globl timer_interrupt_intercept
-timer_interrupt_intercept:
-	.long	timer_interrupt
-	.long	ret_from_intercept
+	EXC_XFER_EE_LITE(0x800, KernelFP)
 
-	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
-	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+/* Decrementer */
+	EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
+
+	EXCEPTION(0xa00, Trap_0a, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0xb00, Trap_0b, UnknownException, EXC_XFER_EE)
 
 /* System call */
 	. = 0xc00
 SystemCall:
 	EXCEPTION_PROLOG
-	stw	r3,ORIG_GPR3(r21)
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
-	bl	transfer_to_handler
-	.long	DoSyscall
-	.long	ret_from_except
+	EXC_XFER_EE_LITE(0xc00, DoSyscall)
 
 /* Single step - not used on 601 */
-	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
-	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_EE)
+	EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE)
 
 /*
  * The Altivec unavailable trap is at 0x0f20.  Foo.
  * We effectively remap it to 0x3000.
  */
 	. = 0xf00
-	b	Trap_0f
-trap_0f_cont:
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r20,MSR_KERNEL
-	bl	transfer_to_handler
-	.long	UnknownException
-	.long	ret_from_except
 
-	. = 0xf20
 #ifdef CONFIG_ALTIVEC
+	b	Trap_0f
+	. = 0xf20
 	b	AltiVecUnavailable
-#endif
 Trap_0f:
+#endif
 	EXCEPTION_PROLOG
-	b	trap_0f_cont
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE(0xf00, UnknownException)
 
 /*
  * Handle TLB miss for instruction on 603/603e.
@@ -677,35 +677,35 @@
 	mtcrf	0x80,r3
 	rfi
 
-	STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
-	STD_EXCEPTION(0x1400, SMI, SMIException)
-	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
-	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
-	STD_EXCEPTION(0x1700, Trap_17, TAUException)
-	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
-	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
-	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
-	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
-	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
-	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
-	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
-	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
-	STD_EXCEPTION(0x2000, RunMode, RunModeException)
-	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
-	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
-	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
-	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
-	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
-	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
-	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
-	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
-	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
-	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
-	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
-	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
-	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
-	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
-	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+	EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, EXC_XFER_EE)
+	EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
+	EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
+	EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1c00, Trap_1c, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1d00, Trap_1d, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1e00, Trap_1e, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1f00, Trap_1f, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE)
+	EXCEPTION(0x2100, Trap_21, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2200, Trap_22, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2300, Trap_23, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2400, Trap_24, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2500, Trap_25, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2600, Trap_26, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2700, Trap_27, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2800, Trap_28, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2900, Trap_29, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2a00, Trap_2a, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2b00, Trap_2b, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2c00, Trap_2c, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2d00, Trap_2d, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2e00, Trap_2e, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x2f00, Trap_2f, UnknownException, EXC_XFER_EE)
 
 	. = 0x3000
 
@@ -713,25 +713,29 @@
 AltiVecUnavailable:
 	EXCEPTION_PROLOG
 	bne	load_up_altivec		/* if from user, just load it up */
-	li	r20,MSR_KERNEL
-	bl	transfer_to_handler	/* if from kernel, take a trap */
-	.long	KernelAltiVec
-	.long	ret_from_except
+	EXC_XFER_EE_LITE(0xf20, KernelAltiVec)
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef CONFIG_PPC64BRIDGE
 DataAccess:
 	EXCEPTION_PROLOG
 	b	DataAccessCont
+
 InstructionAccess:
 	EXCEPTION_PROLOG
 	b	InstructionAccessCont
+
 DataSegment:
 	EXCEPTION_PROLOG
-	b	DataSegmentCont
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	mfspr	r4,DAR
+	stw	r4,_DAR(r11)
+	EXC_XFER_STD(0x380, UnknownException)
+
 InstructionSegment:
 	EXCEPTION_PROLOG
-	b	InstructionSegmentCont
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_STD(0x480, UnknownException)
 #endif /* CONFIG_PPC64BRIDGE */
 
 /*
@@ -769,16 +773,16 @@
 	lwz	r5,PT_REGS(r4)
 	add	r5,r5,r6
 	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	li	r20,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r20		/* disable FP for previous task */
+	li	r10,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r10		/* disable FP for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
 	lwz	r4,THREAD_FPEXC_MODE(r5)
-	ori	r23,r23,MSR_FP		/* enable FP for current */
-	or	r23,r23,r4
+	ori	r9,r9,MSR_FP		/* enable FP for current */
+	or	r9,r9,r4
 	lfd	fr0,THREAD_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
@@ -788,21 +792,57 @@
 	stw	r4,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
-	lwz	r3,_CCR(r21)
-	lwz	r4,_LINK(r21)
-	mtcrf	0xff,r3
-	mtlr	r4
-	REST_GPR(1, r21)
-	REST_4GPRS(3, r21)
-	/* we haven't used ctr or xer */
-	mtspr	SRR1,r23
-	mtspr	SRR0,r22
-	REST_GPR(20, r21)
-	REST_2GPRS(22, r21)
-	lwz	r21,GPR21(r21)
+	/* we haven't used ctr or xer or lr */
+	/* fall through to fast_exception_return */
+
+	.globl	fast_exception_return
+fast_exception_return:
+	andi.	r10,r9,MSR_RI		/* check for recoverable interrupt */
+	beq	1f			/* if not, we've got problems */
+2:	REST_4GPRS(3, r11)
+	lwz	r10,_CCR(r11)
+	REST_GPR(1, r11)
+	mtcr	r10
+	lwz	r10,_LINK(r11)
+	mtlr	r10
+	REST_GPR(10, r11)
+	mtspr	SRR1,r9
+	mtspr	SRR0,r12
+	REST_GPR(9, r11)
+	REST_GPR(12, r11)
+	lwz	r11,GPR11(r11)
 	SYNC
 	RFI
 
+/* check if the exception happened in a restartable section */
+1:	lis	r3,exc_exit_restart_end@ha
+	addi	r3,r3,exc_exit_restart_end@l
+	cmplw	r12,r3
+	bge	3f
+	lis	r4,exc_exit_restart@ha
+	addi	r4,r4,exc_exit_restart@l
+	cmplw	r12,r4
+	blt	3f
+	lis	r3,fee_restarts@ha
+	tophys(r3,r3)
+	lwz	r5,fee_restarts@l(r3)
+	addi	r5,r5,1
+	stw	r5,fee_restarts@l(r3)
+	mr	r12,r4		/* restart at exc_exit_restart */
+	b	2b
+
+	.comm	fee_restarts,4
+
+/* aargh, a nonrecoverable interrupt, panic */
+/* aargh, we don't know which trap this is */
+3:	li	r10,0
+	stw	r10,TRAP(r11)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r10,MSR_KERNEL
+	bl	transfer_to_handler_full
+	.long	nonrecoverable_exception
+	.long	ret_from_except
+
 /*
  * FP unavailable trap from kernel - print a message, but let
  * the task use FP in the kernel until it returns to user mode.
@@ -818,7 +858,7 @@
 	bl	printk
 	b	ret_from_except
 86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
-	.align	4
+	.align	4,0
 
 #ifdef CONFIG_ALTIVEC
 /* Note that the AltiVec support is closely modeled after the FP
@@ -842,57 +882,40 @@
  * to another.  Instead we call giveup_altivec in switch_to.
  */
 #ifndef CONFIG_SMP
-#ifndef CONFIG_APUS
-	lis	r6,-KERNELBASE@h
-#else
-	lis	r6,CYBERBASEp@h
-	lwz	r6,0(r6)
-#endif
+	tophys(r6,0)
 	addis	r3,r6,last_task_used_altivec@ha
 	lwz	r4,last_task_used_altivec@l(r3)
 	cmpi	0,r4,0
 	beq	1f
 	add	r4,r4,r6
 	addi	r4,r4,THREAD	/* want THREAD of last_task_used_altivec */
-	SAVE_32VR(0,r20,r4)
+	SAVE_32VR(0,r10,r4)
 	MFVSCR(vr0)
-	li	r20,THREAD_VSCR
-	STVX(vr0,r20,r4)
+	li	r10,THREAD_VSCR
+	STVX(vr0,r10,r4)
 	lwz	r5,PT_REGS(r4)
 	add	r5,r5,r6
 	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-	lis	r20,MSR_VEC@h
-	andc	r4,r4,r20	/* disable altivec for previous task */
+	lis	r10,MSR_VEC@h
+	andc	r4,r4,r10	/* disable altivec for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of AltiVec after return */
-	oris	r23,r23,MSR_VEC@h
+	oris	r9,r9,MSR_VEC@h
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
-	li	r20,THREAD_VSCR
-	LVX(vr0,r20,r5)
+	li	r10,THREAD_VSCR
+	LVX(vr0,r10,r5)
 	MTVSCR(vr0)
-	REST_32VR(0,r20,r5)
+	REST_32VR(0,r10,r5)
 #ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
 	sub	r4,r4,r6
 	stw	r4,last_task_used_altivec@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
-	lwz	r3,_CCR(r21)
-	lwz	r4,_LINK(r21)
-	mtcrf	0xff,r3
-	mtlr	r4
-	REST_GPR(1, r21)
-	REST_4GPRS(3, r21)
-	/* we haven't used ctr or xer */
-	mtspr	SRR1,r23
-	mtspr	SRR0,r22
-	REST_GPR(20, r21)
-	REST_2GPRS(22, r21)
-	lwz	r21,GPR21(r21)
-	SYNC
-	RFI
+	/* we haven't used ctr or xer or lr */
+	b	fast_exception_return
 
 /*
  * AltiVec unavailable trap from kernel - print a message, but let
@@ -909,7 +932,7 @@
 	bl	printk
 	b	ret_from_except
 87:	.string	"AltiVec used in kernel  (task=%p, pc=%x)  \n"
-	.align	4
+	.align	4,0
 
 /*
  * giveup_altivec(tsk)
@@ -1180,7 +1203,7 @@
 	CLR_TOP32(r4)
 	mtspr	SPRG3,r4
 	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+	mtspr	SPRG2,r3	/* 0 => not in RTAS */
 
 	/* enable MMU and jump to start_secondary */
 	li	r4,MSR_KERNEL
@@ -1231,6 +1254,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_generic)
@@ -1298,21 +1333,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....
@@ -1384,7 +1451,7 @@
 	CLR_TOP32(r4)
 	mtspr	SPRG3,r4
 	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+	mtspr	SPRG2,r3	/* 0 => not in RTAS */
 
 	/* stack */
 	lis	r1,init_thread_union@ha
@@ -1481,6 +1548,10 @@
 	stw	r4, 0x4(r5)
 #endif
 	li	r4,0
+BEGIN_FTR_SECTION
+	dssall	0
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 3:
 #ifdef CONFIG_PPC64BRIDGE
 	slbie	r4
@@ -1490,7 +1561,7 @@
 	rlwinm	r3,r3,0,8,3	/* clear out any overflow from VSID field */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-	SYNC_601
+	sync
 	isync
 	blr
 
@@ -1503,35 +1574,35 @@
  *  -- Cort 
  */
 clear_bats:
-	li	r20,0
+	li	r10,0
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	r9, 1
 	beq	1f
 
-	mtspr	DBAT0U,r20
-	mtspr	DBAT0L,r20
-	mtspr	DBAT1U,r20
-	mtspr	DBAT1L,r20
-	mtspr	DBAT2U,r20
-	mtspr	DBAT2L,r20
-	mtspr	DBAT3U,r20
-	mtspr	DBAT3L,r20
+	mtspr	DBAT0U,r10
+	mtspr	DBAT0L,r10
+	mtspr	DBAT1U,r10
+	mtspr	DBAT1L,r10
+	mtspr	DBAT2U,r10
+	mtspr	DBAT2L,r10
+	mtspr	DBAT3U,r10
+	mtspr	DBAT3L,r10
 1:
-	mtspr	IBAT0U,r20
-	mtspr	IBAT0L,r20
-	mtspr	IBAT1U,r20
-	mtspr	IBAT1L,r20
-	mtspr	IBAT2U,r20
-	mtspr	IBAT2L,r20
-	mtspr	IBAT3U,r20
-	mtspr	IBAT3L,r20
+	mtspr	IBAT0U,r10
+	mtspr	IBAT0L,r10
+	mtspr	IBAT1U,r10
+	mtspr	IBAT1L,r10
+	mtspr	IBAT2U,r10
+	mtspr	IBAT2L,r10
+	mtspr	IBAT3U,r10
+	mtspr	IBAT3L,r10
 	blr
 
 flush_tlbs:
-	lis	r20, 0x40
-1:	addic.	r20, r20, -0x1000
-	tlbie	r20
+	lis	r10, 0x40
+1:	addic.	r10, r10, -0x1000
+	tlbie	r10
 	blt	1b
 	sync
 	blr
diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S	Thu May  9 15:21:06 2002
+++ b/arch/ppc/kernel/head_4xx.S	Thu May  9 15:21:06 2002
@@ -40,12 +40,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "ppc_defs.h"
-
-/* Preprocessor Defines */
-
-#define	STND_EXC	0
-#define	CRIT_EXC	1
+#include "asm-offsets.h"
 
 /* As with the other PowerPC ports, it is expected that when code
  * execution begins here, the following registers contain valid, yet
@@ -70,7 +65,6 @@
 	mr	r29,r5
 	mr	r28,r6
 	mr	r27,r7
-	li	r24,0		/* CPU number */
 
 	/* We have to turn on the MMU right away so we get cache modes
 	 * set correctly.
@@ -89,197 +83,231 @@
 	SYNC
 	rfi				/* enables MMU */
 
-/* Exception vector entry code. This code runs with address translation
+/*
+ * This area is used for temporarily saving registers during the
+ * critical exception prolog.
+ */
+	. = 0xc0
+crit_save:
+	.space	8
+
+/*
+ * Exception vector entry code. This code runs with address translation
  * turned off (i.e. using physical addresses). We assume SPRG3 has the
  * physical address of the current task thread_struct.
+ * Note that we have to have decremented r1 before we write to any fields
+ * of the exception frame, since a critical interrupt could occur at any
+ * time, and it will write to the area immediately below the current r1.
  */ 
+#define NORMAL_EXCEPTION_PROLOG						     \
+	mtspr	SPRN_SPRG0,r10;		/* save two registers to work with */\
+	mtspr	SPRN_SPRG1,r11;						     \
+	mtspr	SPRN_SPRG2,r1;						     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	beq	1f;							     \
+	mfspr	r1,SPRG3;		/* if from user, start at top of   */\
+	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
+	addi	r1,r1,THREAD_SIZE;					     \
+1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	tophys(r11,r1);							     \
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mfspr	r10,SPRG0;						     \
+	stw	r10,GPR10(r11);						     \
+	mfspr	r12,SPRG1;						     \
+	stw	r12,GPR11(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r10,SPRG2;						     \
+	mfspr	r12,SRR0;						     \
+	stw	r10,GPR1(r11);						     \
+	mfspr	r9,SRR1;						     \
+	stw	r10,0(r11);						     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
 
-#define COMMON_PROLOG(n)                                                     \
-0:	mtspr	SPRN_SPRG0,r20;         /* We need r20, move it to SPRG0   */\
-	mtspr	SPRN_SPRG1,r21;         /* We need r21, move it to SPRG1   */\
-	mfcr	r20;                    /* We need the CR, move it to r20  */\
-	mfspr	r21,SPRN_SPRG2;         /* Exception stack to use          */\
-	cmpwi	cr0,r21,0;              /* From user mode or RTAS?         */\
-	bne	1f;                     /* Not RTAS, branch                */\
-	tophys(r21, r1);                /* Convert vka in r1 to pka in r21 */\
-	subi	r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame     */\
-1:	stw	r20,_CCR(r21);          /* Save CR on the stack            */\
-	stw	r22,GPR22(r21);         /* Save r22 on the stack           */\
-	stw	r23,GPR23(r21);         /* r23 Save on the stack           */\
-	mfspr	r20,SPRN_SPRG0;         /* Get r20 back out of SPRG0       */\
-	stw	r20,GPR20(r21);         /* Save r20 on the stack           */\
-	mfspr	r22,SPRN_SPRG1;         /* Get r21 back out of SPRG0       */\
-	stw	r22,GPR21(r21);         /* Save r21 on the stack           */\
-	mflr	r20;                                                         \
-	stw	r20,_LINK(r21);         /* Save LR on the stack            */\
-	mfctr	r22;                                                         \
-	stw	r22,_CTR(r21);          /* Save CTR on the stack           */\
-	mfspr	r20,XER;                                                     \
-	stw	r20,_XER(r21);          /* Save XER on the stack           */\
-	mfspr	r20,SPRN_DBCR0;                                              \
-	stw	r20,_DBCR0(r21);        /* Save Debug Control on the stack */
-
-#define	COMMON_EPILOG							     \
-	stw	r0,GPR0(r21);		/* Save r0 on the stack		   */\
-	stw	r1,GPR1(r21);		/* Save r1 on the stack		   */\
-	stw	r2,GPR2(r21);		/* Save r2 on the stack		   */\
-	stw	r1,0(r21);						     \
-	tovirt(r1,r21);			/* Set-up new kernel stack pointer */\
-	SAVE_4GPRS(3, r21);		/* Save r3 through r6 on the stack */\
-	SAVE_GPR(7, r21);		/* Save r7 on the stack		   */
-
-#define	STND_EXCEPTION_PROLOG(n)					     \
-	COMMON_PROLOG(n);						     \
-	mfspr	r22,SPRN_SRR0;		/* Faulting instruction address	   */\
-	lis	r20,MSR_WE@h;						     \
-	mfspr	r23,SPRN_SRR1;		/* MSR at the time of fault	   */\
-	andc	r23,r23,r20;		/* disable processor wait state    */\
-	COMMON_EPILOG;
-
-#define	CRIT_EXCEPTION_PROLOG(n)					     \
-	COMMON_PROLOG(n);						     \
-	mfspr	r22,SPRN_SRR2;		/* Faulting instruction address	   */\
-	lis	r20,MSR_WE@h;						     \
-	mfspr	r23,SPRN_SRR3;		/* MSR at the time of fault	   */\
-	andc	r23,r23,r20;		/* disable processor wait state    */\
-	COMMON_EPILOG;
-
+/*
+ * Exception prolog for critical exceptions.  This is a little different
+ * from the normal exception prolog above since a critical exception
+ * can potentially occur at any point during normal exception processing.
+ * Thus we cannot use the same SPRG registers as the normal prolog above.
+ * Instead we use a couple of words of memory at low physical addresses.
+ * This is OK since we don't support SMP on these processors.
+ */
+#define CRITICAL_EXCEPTION_PROLOG					     \
+	stw	r10,crit_save@l(0);	/* save two registers to work with */\
+	stw	r11,4+crit_save@l(0);					     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_SRR3;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	mr	r11,r1;							     \
+	beq	1f;							     \
+	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+	addi	r11,r11,THREAD_SIZE;					     \
+1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	tophys(r11,r11);						     \
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	lwz	r10,crit_save@l(0);					     \
+	stw	r10,GPR10(r11);						     \
+	lwz	r12,4+crit_save@l(0);					     \
+	stw	r12,GPR11(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r12,SRR0;		/* save SRR0 and SRR1 in the frame */\
+	stw	r12,_SRR0(r11);		/* since they may have had stuff   */\
+	mfspr	r9,SRR1;		/* in them at the point where the  */\
+	stw	r9,_SRR1(r11);		/* exception was taken		   */\
+	mfspr	r12,SRR2;						     \
+	stw	r1,GPR1(r11);						     \
+	mfspr	r9,SRR3;						     \
+	stw	r1,0(r11);						     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
 
+/*
+ * Exception vectors.
+ */
 #define	START_EXCEPTION(n, label)					     \
 	. = n;								     \
 label:
 
+#define FINISH_EXCEPTION(func)					\
+	bl	transfer_to_handler_full;			\
+	.long	func;						\
+	.long	ret_from_except_full
+
+
+#define EXCEPTION(n, label, hdlr, xfer)				\
+	START_EXCEPTION(n, label);				\
+	NORMAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr)			\
+	START_EXCEPTION(n, label);				\
+	CRITICAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	EXC_XFER_TEMPLATE(hdlr, n+2, NOCOPY, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, copyee, tfer, ret)	\
+	li	r10,trap;					\
+	stw	r10,TRAP(r11);					\
+	li	r10,MSR_KERNEL;					\
+	copyee(r10, r9);					\
+	bl	tfer;		 				\
+	.long	hdlr;						\
+	.long	ret
+
+#define COPY_EE(d, s)		rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, NOCOPY, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n+1, NOCOPY, transfer_to_handler, \
+			  ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, COPY_EE, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)	\
+	EXC_XFER_TEMPLATE(hdlr, n+1, COPY_EE, transfer_to_handler, \
+			  ret_from_except)
 
-#define FINISH_EXCEPTION(func)						     \
-	bl	transfer_to_handler;					     \
-	.long	func;							     \
-	.long	ret_from_except
-
-
-#define STND_EXCEPTION(n, label, func)					     \
-	START_EXCEPTION(n, label);					     \
-	STND_EXCEPTION_PROLOG(n);					     \
-	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
-	li	r7,STND_EXC;						     \
-	li	r20,MSR_KERNEL;						     \
-	FINISH_EXCEPTION(func)
-
-
-#define	CRIT_EXCEPTION(n, label, func)					     \
-	START_EXCEPTION(n, label);					     \
-	CRIT_EXCEPTION_PROLOG(n);					     \
-	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
-	li	r7,CRIT_EXC;						     \
-	li	r20,MSR_KERNEL;						     \
-	FINISH_EXCEPTION(func)
-
-
-/* Exception vectors.
-*/ 
-
-/* 0x0100 - Critical Interrupt Exception
-*/
-	CRIT_EXCEPTION(0x0100,	CriticalInterrupt,	UnknownException)
-
-/* 0x0200 - Machine Check Exception
-*/
-#if 0
-	CRIT_EXCEPTION(0x0200,	MachineCheck,		MachineCheckException)
-#else
-	START_EXCEPTION(0x0200, MachineCheck)
-	CRIT_EXCEPTION_PROLOG(0x0200)
-
-	/*
-	lis	r4,0x0400
-	mtdcr	DCRN_POB0_BESR0,r4
-	*/
-#ifdef DCRN_POB0_BEAR
-	mfdcr	r4,DCRN_POB0_BEAR
-	mfdcr	r4,DCRN_POB0_BESR0
-	mfdcr	r4,DCRN_POB0_BESR1
-#endif
 
-#ifdef DCRN_PLB0_BEAR
-	mfdcr	r4,DCRN_PLB0_ACR
-	mfdcr	r4,DCRN_PLB0_BEAR
-	mfdcr	r4,DCRN_PLB0_BESR
-#endif
+/*
+ * 0x0100 - Critical Interrupt Exception
+ */
+	CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, UnknownException)
 
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,CRIT_EXC
-	li	r20,MSR_KERNEL
-	FINISH_EXCEPTION(MachineCheckException)
-#endif
+/*
+ * 0x0200 - Machine Check Exception
+ */
+	CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
 
-/* 0x0300 - Data Storage Exception
+/*
+ * 0x0300 - Data Storage Exception
  * This happens for just a few reasons.  U0 set (but we don't do that),
  * or zone protection fault (user violation, write to protected page).
  * If this is just an update of modified status, we do that quickly
  * and exit.  Otherwise, we call heavywight functions to do the work.
  */
-	START_EXCEPTION(0x0300,	DataStore)
-	mtspr	SPRG0, r20		/* Save some working registers */
-	mtspr	SPRG1, r21
+	START_EXCEPTION(0x0300,	DataStorage)
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
 #ifdef CONFIG_403GCX
-	stw     r22, 0(r0)
-	stw     r23, 4(r0)
-	mfcr    r21
-	mfspr   r22, SPRN_PID
-	stw     r21, 8(r0)
-	stw     r22, 12(r0)
-#else
-	mtspr	SPRG4, r22
-	mtspr	SPRG5, r23
-	mfcr	r21
-	mfspr	r22, SPRN_PID
-	mtspr	SPRG7, r21
-	mtspr	SPRG6, r22
+	stw     r12, 0(r0)
+	stw     r9, 4(r0)
+	mfcr    r11
+	mfspr   r12, SPRN_PID
+	stw     r11, 8(r0)
+	stw     r12, 12(r0)
+#else
+	mtspr	SPRG4, r12
+	mtspr	SPRG5, r9
+	mfcr	r11
+	mfspr	r12, SPRN_PID
+	mtspr	SPRG7, r11
+	mtspr	SPRG6, r12
 #endif
 
 	/* First, check if it was a zone fault (which means a user
 	* tried to access a kernel or read-protected page - always
 	* a SEGV).  All other faults here must be stores, so no
 	* need to check ESR_DST as well. */
-	mfspr	r20, SPRN_ESR
-	andis.	r20, r20, ESR_DIZ@h
+	mfspr	r10, SPRN_ESR
+	andis.	r10, r10, ESR_DIZ@h
 	bne	2f
 
-	mfspr	r20, SPRN_DEAR		/* Get faulting address */
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r21, r20, 0x8000
+	andis.	r11, r10, 0x8000
 	beq	3f
-	lis	r21, swapper_pg_dir@h
-	ori	r21, r21, swapper_pg_dir@l
-	li	r23, 0
-	mtspr	SPRN_PID, r23		/* TLB will have 0 TID */
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+	li	r9, 0
+	mtspr	SPRN_PID, r9		/* TLB will have 0 TID */
 	b	4f
 
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r21,SPRG3
-	lwz	r21,PGDIR(r21)
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
 4:
-	tophys(r21, r21)
-	rlwimi	r21, r20, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r21, 0(r21)		/* Get L1 entry */
-	rlwinm.	r22, r21, 0, 0, 19	/* Extract L2 (pte) base address */
+	tophys(r11, r11)
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
 	beq	2f			/* Bail if no table */
 
-	tophys(r22, r22)
-	rlwimi	r22, r20, 22, 20, 29	/* Compute PTE address */
-	lwz	r21, 0(r22)		/* Get Linux PTE */
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
 
-	andi.	r23, r21, _PAGE_RW	/* Is it writeable? */
+	andi.	r9, r11, _PAGE_RW	/* Is it writeable? */
 	beq	2f			/* Bail if not */
 
 	/* Update 'changed'.
 	*/
-	ori	r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
-	stw	r21, 0(r22)		/* Update Linux page table */
+	ori	r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+	stw	r11, 0(r12)		/* Update Linux page table */
 
 	/* Most of the Linux PTE is ready to load into the TLB LO.
 	 * We set ZSEL, where only the LS-bit determines user access.
@@ -289,34 +317,34 @@
 	 * Many of these bits are software only.  Bits we don't set
 	 * here we (properly should) assume have the appropriate value.
 	 */
-	li	r22, 0x0ce2
-	andc	r21, r21, r22		/* Make sure 20, 21 are zero */
+	li	r12, 0x0ce2
+	andc	r11, r11, r12		/* Make sure 20, 21 are zero */
 
 	/* find the TLB index that caused the fault.  It has to be here.
 	*/
-	tlbsx	r23, 0, r20
+	tlbsx	r9, 0, r10
 
-	tlbwe	r21, r23, TLB_DATA		/* Load TLB LO */
+	tlbwe	r11, r9, TLB_DATA		/* Load TLB LO */
 
 	/* Done...restore registers and get out of here.
 	*/
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
 
@@ -325,120 +353,70 @@
 	 * and call the heavyweights to help us out.
 	 */
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	b	DataAccess
 
-/* 0x0400 - Instruction Storage Exception
- * I don't know why it is called "Storage"....This is caused by a fetch
- * from non-execute or guarded pages.
+/*
+ * 0x0400 - Instruction Storage Exception
+ * This is caused by a fetch from non-execute or guarded pages.
  */
 	START_EXCEPTION(0x0400, InstructionAccess)
-	STND_EXCEPTION_PROLOG(0x0400)
-	mr	r4,r22			/* Pass SRR0 as arg2 */
+	NORMAL_EXCEPTION_PROLOG
+	mr	r4,r12			/* Pass SRR0 as arg2 */
 	li	r5,0			/* Pass zero as arg3 */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
-	FINISH_EXCEPTION(do_page_fault)	/* do_page_fault(regs, SRR0, SRR1) */
+	EXC_XFER_EE_LITE(0x400, do_page_fault)
 
-/* 0x0500 - External Interrupt Exception
-*/
-	START_EXCEPTION(0x0500, HardwareInterrupt)
-	STND_EXCEPTION_PROLOG(0x0500)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	li	r4,0
-	bl	transfer_to_handler
-_GLOBAL(do_IRQ_intercept)
-	.long	do_IRQ
-	.long	ret_from_intercept
+/* 0x0500 - External Interrupt Exception */
+	EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
 
-/* 0x0600 - Alignment Exception
-*/
+/* 0x0600 - Alignment Exception */
 	START_EXCEPTION(0x0600, Alignment)
-	STND_EXCEPTION_PROLOG(0x0600)
+	NORMAL_EXCEPTION_PROLOG
 	mfspr	r4,SPRN_DEAR		/* Grab the DEAR and save it */
-	stw	r4,_DEAR(r21)
+	stw	r4,_DEAR(r11)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
-	FINISH_EXCEPTION(AlignmentException)
+	EXC_XFER_EE(0x600, AlignmentException)
 
-/* 0x0700 - Program Exception
-*/
-	START_EXCEPTION(0x0700,	ProgramCheck)
-	STND_EXCEPTION_PROLOG(0x0700)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
-	FINISH_EXCEPTION(ProgramCheckException)
+/* 0x0700 - Program Exception */
+	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE)
 
+	EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x0A00, Trap_0A, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x0B00, Trap_0B, UnknownException, EXC_XFER_EE)
 
-/* I'm stealing this unused vector location to build a standard exception
- * frame for Data TLB Access errors.  The other Data TLB exceptions will bail
- * out to this point if they can't resolve the lightweight TLB fault.
- */
-	START_EXCEPTION(0x0800,	DataAccess)
-	STND_EXCEPTION_PROLOG(0x0800)
-	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
-	stw	r5,_ESR(r21)
-	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
-	stw	r4,_DEAR(r21)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
-	FINISH_EXCEPTION(do_page_fault)	/* do_page_fault(regs, ESR, DEAR) */
-
-	STND_EXCEPTION(0x0900,	Trap_09,		UnknownException)
-	STND_EXCEPTION(0x0A00,	Trap_0A,		UnknownException)
-	STND_EXCEPTION(0x0B00,	Trap_0B,		UnknownException)
-/* 0x0C00 - System Call Exception
-*/
+/* 0x0C00 - System Call Exception */
 	START_EXCEPTION(0x0C00,	SystemCall)
-	STND_EXCEPTION_PROLOG(0x0C00)
-	stw	r3,ORIG_GPR3(r21)
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
-	FINISH_EXCEPTION(DoSyscall)
-
-	STND_EXCEPTION(0x0D00,	Trap_0D,		UnknownException)
-	STND_EXCEPTION(0x0E00,	Trap_0E,		UnknownException)
-	STND_EXCEPTION(0x0F00,	Trap_0F,		UnknownException)
+	NORMAL_EXCEPTION_PROLOG
+	EXC_XFER_EE_LITE(0xc00, DoSyscall)
 
-/* 0x1000 - Programmable Interval Timer (PIT) Exception
-*/
-	START_EXCEPTION(0x1000,	Decrementer)
-	STND_EXCEPTION_PROLOG(0x1000)
-	lis	r0,TSR_PIS@h		/* Set-up the PIT exception mask */
+	EXCEPTION(0x0D00, Trap_0D, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x0E00, Trap_0E, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x0F00, Trap_0F, UnknownException, EXC_XFER_EE)
+
+/* 0x1000 - Programmable Interval Timer (PIT) Exception */
+	START_EXCEPTION(0x1000, Decrementer)
+	NORMAL_EXCEPTION_PROLOG
+	lis	r0,TSR_PIS@h
 	mtspr	SPRN_TSR,r0		/* Clear the PIT exception */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,STND_EXC
-	li	r20,MSR_KERNEL
-	bl	transfer_to_handler
-_GLOBAL(timer_interrupt_intercept)
-	.long	timer_interrupt
-	.long	ret_from_intercept
+	EXC_XFER_EE(0x1000, timer_interrupt)
 
 #if 0
 /* NOTE:
@@ -452,7 +430,7 @@
 /* 0x1020 - Watchdog Timer (WDT) Exception
 */
 
-	CRIT_EXCEPTION(0x1020,	WDTException,		UnknownException)
+	CRITICAL_EXCEPTION(0x1020, WDTException, UnknownException)
 #endif
 
 /* 0x1100 - Data TLB Miss Exception
@@ -461,56 +439,55 @@
  * load TLB entries from the page table if they exist.
  */
 	START_EXCEPTION(0x1100,	DTLBMiss)
-	mtspr	SPRG0, r20		/* Save some working registers */
-	mtspr	SPRG1, r21
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
 #ifdef CONFIG_403GCX
-	stw     r22, 0(r0)
-	stw     r23, 4(r0)
-	mfcr    r21
-	mfspr   r22, SPRN_PID
-	stw     r21, 8(r0)
-	stw     r22, 12(r0)
-#else
-	mtspr	SPRG4, r22
-	mtspr	SPRG5, r23
-	mfcr	r21
-	mfspr	r22, SPRN_PID
-	mtspr	SPRG7, r21
-	mtspr	SPRG6, r22
+	stw     r12, 0(r0)
+	stw     r9, 4(r0)
+	mfcr    r11
+	mfspr   r12, SPRN_PID
+	stw     r11, 8(r0)
+	stw     r12, 12(r0)
+#else
+	mtspr	SPRG4, r12
+	mtspr	SPRG5, r9
+	mfcr	r11
+	mfspr	r12, SPRN_PID
+	mtspr	SPRG7, r11
+	mtspr	SPRG6, r12
 #endif
-	mfspr	r20, SPRN_DEAR		/* Get faulting address */
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r21, r20, 0x8000
+	andis.	r11, r10, 0x8000
 	beq	3f
-	lis	r21, swapper_pg_dir@h
-	ori	r21, r21, swapper_pg_dir@l
-	li	r23, 0
-	mtspr	SPRN_PID, r23		/* TLB will have 0 TID */
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+	li	r9, 0
+	mtspr	SPRN_PID, r9		/* TLB will have 0 TID */
 	b	4f
 
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r21,SPRG3
-	lwz	r21,PGDIR(r21)
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
 4:
-	tophys(r21, r21)
-	rlwimi	r21, r20, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r21, 0(r21)		/* Get L1 entry */
-	rlwinm.	r22, r21, 0, 0, 19	/* Extract L2 (pte) base address */
+	tophys(r11, r11)
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
 	beq	2f			/* Bail if no table */
 
-	tophys(r22, r22)
-	rlwimi	r22, r20, 22, 20, 29	/* Compute PTE address */
-	lwz	r21, 0(r22)		/* Get Linux PTE */
-	andi.	r23, r21, _PAGE_PRESENT
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
+	andi.	r9, r11, _PAGE_PRESENT
 	beq	2f
 
-	ori	r21, r21, _PAGE_ACCESSED
-	stw	r21, 0(r22)
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, 0(r12)
 
 	/* Most of the Linux PTE is ready to load into the TLB LO.
 	 * We set ZSEL, where only the LS-bit determines user access.
@@ -520,8 +497,8 @@
 	 * Many of these bits are software only.  Bits we don't set
 	 * here we (properly should) assume have the appropriate value.
 	 */
-	li	r22, 0x0ce2
-	andc	r21, r21, r22		/* Make sure 20, 21 are zero */
+	li	r12, 0x0ce2
+	andc	r11, r11, r12		/* Make sure 20, 21 are zero */
 
 	b	finish_tlb_load
 
@@ -531,22 +508,22 @@
 	 * and call the heavyweights to help us out.
 	 */
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	b	DataAccess
 
 /* 0x1200 - Instruction TLB Miss Exception
@@ -554,56 +531,55 @@
  * registers and bailout to a different point.
  */
 	START_EXCEPTION(0x1200,	ITLBMiss)
-	mtspr	SPRG0, r20		/* Save some working registers */
-	mtspr	SPRG1, r21
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
 #ifdef CONFIG_403GCX
-	stw     r22, 0(r0)
-	stw     r23, 4(r0)
-	mfcr    r21
-	mfspr   r22, SPRN_PID
-	stw     r21, 8(r0)
-	stw     r22, 12(r0)
-#else
-	mtspr	SPRG4, r22
-	mtspr	SPRG5, r23
-	mfcr	r21
-	mfspr	r22, SPRN_PID
-	mtspr	SPRG7, r21
-	mtspr	SPRG6, r22
+	stw     r12, 0(r0)
+	stw     r9, 4(r0)
+	mfcr    r11
+	mfspr   r12, SPRN_PID
+	stw     r11, 8(r0)
+	stw     r12, 12(r0)
+#else
+	mtspr	SPRG4, r12
+	mtspr	SPRG5, r9
+	mfcr	r11
+	mfspr	r12, SPRN_PID
+	mtspr	SPRG7, r11
+	mtspr	SPRG6, r12
 #endif
-	mfspr	r20, SRR0		/* Get faulting address */
+	mfspr	r10, SRR0		/* Get faulting address */
 
 	/* If we are faulting a kernel address, we have to use the
 	 * kernel page tables.
 	 */
-	andis.	r21, r20, 0x8000
+	andis.	r11, r10, 0x8000
 	beq	3f
-	lis	r21, swapper_pg_dir@h
-	ori	r21, r21, swapper_pg_dir@l
-	li	r23, 0
-	mtspr	SPRN_PID, r23		/* TLB will have 0 TID */
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+	li	r9, 0
+	mtspr	SPRN_PID, r9		/* TLB will have 0 TID */
 	b	4f
 
 	/* Get the PGD for the current thread.
 	 */
 3:
-	mfspr	r21,SPRG3
-	lwz	r21,PGDIR(r21)
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
 4:
-	tophys(r21, r21)
-	rlwimi	r21, r20, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
-	lwz	r21, 0(r21)		/* Get L1 entry */
-	rlwinm.	r22, r21, 0, 0, 19	/* Extract L2 (pte) base address */
+	tophys(r11, r11)
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
 	beq	2f			/* Bail if no table */
 
-	tophys(r22, r22)
-	rlwimi	r22, r20, 22, 20, 29	/* Compute PTE address */
-	lwz	r21, 0(r22)		/* Get Linux PTE */
-	andi.	r23, r21, _PAGE_PRESENT
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
+	andi.	r9, r11, _PAGE_PRESENT
 	beq	2f
 
-	ori	r21, r21, _PAGE_ACCESSED
-	stw	r21, 0(r22)
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, 0(r12)
 
 	/* Most of the Linux PTE is ready to load into the TLB LO.
 	 * We set ZSEL, where only the LS-bit determines user access.
@@ -613,30 +589,30 @@
 	 * Many of these bits are software only.  Bits we don't set
 	 * here we (properly should) assume have the appropriate value.
 	 */
-	li	r22, 0x0ce2
-	andc	r21, r21, r22		/* Make sure 20, 21 are zero */
+	li	r12, 0x0ce2
+	andc	r11, r11, r12		/* Make sure 20, 21 are zero */
 
 	b	finish_tlb_load
 
 	/* Done...restore registers and get out of here.
 	*/
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
 
@@ -645,60 +621,62 @@
 	 * and call the heavyweights to help us out.
 	 */
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	b	InstructionAccess
 
-	STND_EXCEPTION(0x1300,	Trap_13,		UnknownException)
-	STND_EXCEPTION(0x1400,	Trap_14,		UnknownException)
-	STND_EXCEPTION(0x1500,	Trap_15,		UnknownException)
-	STND_EXCEPTION(0x1600,	Trap_16,		UnknownException)
+	EXCEPTION(0x1300, Trap_13, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1400, Trap_14, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE)
 #ifdef CONFIG_IBM405_ERR51
 	/* 405GP errata 51 */
 	START_EXCEPTION(0x1700, Trap_17)
 	b DTLBMiss
 #else
-	STND_EXCEPTION(0x1700,	Trap_17,		UnknownException)
+	EXCEPTION(0x1700, Trap_17, UnknownException, EXC_XFER_EE)
 #endif
-	STND_EXCEPTION(0x1800,	Trap_18,		UnknownException)
-	STND_EXCEPTION(0x1900,	Trap_19,		UnknownException)
-	STND_EXCEPTION(0x1A00,	Trap_1A,		UnknownException)
-	STND_EXCEPTION(0x1B00,	Trap_1B,		UnknownException)
-	STND_EXCEPTION(0x1C00,	Trap_1C,		UnknownException)
-	STND_EXCEPTION(0x1D00,	Trap_1D,		UnknownException)
-	STND_EXCEPTION(0x1E00,	Trap_1E,		UnknownException)
-	STND_EXCEPTION(0x1F00,	Trap_1F,		UnknownException)
+	EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1A00, Trap_1A, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1B00, Trap_1B, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1C00, Trap_1C, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1D00, Trap_1D, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE)
+	EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE)
 
 /* 0x2000 - Debug Exception
 */
-	START_EXCEPTION(0x2000, DebugTrap)
-	b	check_single_step_in_exception
-ret_to_debug_exception:
-	CRIT_EXCEPTION_PROLOG(0x2000)
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r7,CRIT_EXC;
-        li      r20,MSR_KERNEL
-	FINISH_EXCEPTION(DebugException)
+	CRITICAL_EXCEPTION(0x2000, DebugTrap, DebugException)
 
-/* Make sure the final interrupt handler has not spilled past the
- * end of its allotted space.
+/*
+ * The other Data TLB exceptions bail out to this point
+ * if they can't resolve the lightweight TLB fault.
  */
-        .=0x2100
+DataAccess:
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
+	stw	r5,_ESR(r11)
+	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
+	stw	r4,_DEAR(r11)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE_LITE(0x300, do_page_fault)
 
+#if 0
 /* Check for a single step debug exception while in an exception
  * handler before state has been saved.  This is to catch the case
  * where an instruction that we are trying to single step causes
@@ -718,37 +696,38 @@
 	 * handler and must be the first instruction of every exception
 	 * handler.
 	 */
-	mtspr	SPRN_SPRG0,r20		/* Save some working registers... */
-	mtspr	SPRN_SPRG1,r21
-	mfcr	r20			/* ..and the cr because we change it */
+	mtspr	SPRN_SPRG0,r10		/* Save some working registers... */
+	mtspr	SPRN_SPRG1,r11
+	mfcr	r10			/* ..and the cr because we change it */
 
-	mfspr   r21,SPRN_SRR3		/* MSR at the time of fault */
-	andi.   r21,r21,MSR_PR
+	mfspr   r11,SPRN_SRR3		/* MSR at the time of fault */
+	andi.   r11,r11,MSR_PR
 	bne+    2f			/* trapped from problem state */
 
-	mfspr   r21,SPRN_SRR2		/* Faulting instruction address */
-	cmplwi  r21,0x2100
+	mfspr   r11,SPRN_SRR2		/* Faulting instruction address */
+	cmplwi  r11,0x2100
 	bgt+    2f			/* address above exception vectors */
 
-	lis     r21,DBSR_IC@h           /* Remove the trap status */
-	mtspr   SPRN_DBSR,r21
+	lis     r11,DBSR_IC@h           /* Remove the trap status */
+	mtspr   SPRN_DBSR,r11
 
-	mfspr	r21,SPRN_SRR3
-	rlwinm	r21,r21,0,23,21		/* clear MSR_DE */
-	mtspr	SPRN_SRR3, r21		/* restore MSR at rcfi without DE */
-
-	mtcrf   0xff,r20                /* restore registers */
-	mfspr   r21,SPRN_SPRG1
-	mfspr   r20,SPRN_SPRG0
+	mfspr	r11,SPRN_SRR3
+	rlwinm	r11,r11,0,23,21		/* clear MSR_DE */
+	mtspr	SPRN_SRR3, r11		/* restore MSR at rcfi without DE */
+
+	mtcrf   0xff,r10                /* restore registers */
+	mfspr   r11,SPRN_SPRG1
+	mfspr   r10,SPRN_SPRG0
 
 	sync
 	rfci                            /* return to the exception handler  */
 
 2:
-	mtcrf   0xff,r20                /* restore registers */
-	mfspr   r21,SPRN_SPRG1
-	mfspr   r20,SPRN_SPRG0
+	mtcrf   0xff,r10                /* restore registers */
+	mfspr   r11,SPRN_SPRG1
+	mfspr   r10,SPRN_SPRG0
 	b       ret_to_debug_exception
+#endif 0
 
 /* Other PowerPC processors, namely those derived from the 6xx-series
  * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved.
@@ -759,9 +738,9 @@
 	/* Damn, I came up one instruction too many to fit into the
 	 * exception space :-).  Both the instruction and data TLB
 	 * miss get to this point to load the TLB.
-	 * 	r20 - EA of fault
-	 * 	r21 - TLB LO (info from Linux PTE)
-	 *	r22, r23 - avilable to use
+	 * 	r10 - EA of fault
+	 * 	r11 - TLB LO (info from Linux PTE)
+	 *	r12, r9 - avilable to use
 	 *	PID - loaded with proper value when we get here
 	 *	Upon exit, we reload everything and RFI.
 	 * Actually, it will fit now, but oh well.....a common place
@@ -773,67 +752,59 @@
 	 * instruction pages by copying data, we have to check if the
 	 * EPN is already in the TLB.
 	 */
-	tlbsx.	r23, 0, r20
+	tlbsx.	r9, 0, r10
 	beq	6f
 
 	/* load the next available TLB index.
 	*/
-	lis	r22, tlb_4xx_index@h
-	ori	r22, r22, tlb_4xx_index@l
-	tophys(r22, r22)
-	lwz	r23, 0(r22)
-	addi	r23, r23, 1
+	lis	r12, tlb_4xx_index@h
+	ori	r12, r12, tlb_4xx_index@l
+	tophys(r12, r12)
+	lwz	r9, 0(r12)
+	addi	r9, r9, 1
 #ifdef CONFIG_PIN_TLB
-	cmpwi	0, r23, 61		/* reserve entries 62, 63 for kernel */
+	cmpwi	0, r9, 61		/* reserve entries 62, 63 for kernel */
 	ble	7f
-	li	r23, 0
+	li	r9, 0
 7:
 #else
-	andi.	r23, r23, (PPC4XX_TLB_SIZE-1)
+	andi.	r9, r9, (PPC4XX_TLB_SIZE-1)
 #endif
-	stw	r23, 0(r22)
+	stw	r9, 0(r12)
 
 6:
-	tlbwe	r21, r23, TLB_DATA		/* Load TLB LO */
+	tlbwe	r11, r9, TLB_DATA		/* Load TLB LO */
 
 	/* Create EPN.  This is the faulting address plus a static
 	 * set of bits.  These are size, valid, E, U0, and ensure
 	 * bits 20 and 21 are zero.
 	 */
-	li	r22, 0x00c0
-	rlwimi	r20, r22, 0, 20, 31
-	tlbwe	r20, r23, TLB_TAG		/* Load TLB HI */
+	li	r12, 0x00c0
+	rlwimi	r10, r12, 0, 20, 31
+	tlbwe	r10, r9, TLB_TAG		/* Load TLB HI */
 
 	/* Done...restore registers and get out of here.
 	*/
 #ifdef CONFIG_403GCX
-	lwz     r22, 12(r0)
-	lwz     r21, 8(r0)
-	mtspr   SPRN_PID, r22
-	mtcr    r21
-	lwz     r23, 4(r0)
-	lwz     r22, 0(r0)
-#else
-	mfspr	r22, SPRG6
-	mfspr	r21, SPRG7
-	mtspr	SPRN_PID, r22
-	mtcr	r21
-	mfspr	r23, SPRG5
-	mfspr	r22, SPRG4
+	lwz     r12, 12(r0)
+	lwz     r11, 8(r0)
+	mtspr   SPRN_PID, r12
+	mtcr    r11
+	lwz     r9, 4(r0)
+	lwz     r12, 0(r0)
+#else
+	mfspr	r12, SPRG6
+	mfspr	r11, SPRG7
+	mtspr	SPRN_PID, r12
+	mtcr	r11
+	mfspr	r9, SPRG5
+	mfspr	r12, SPRG4
 #endif
-	mfspr	r21, SPRG1
-	mfspr	r20, SPRG0
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
 	PPC405_ERR77_SYNC
 	rfi			/* Should sync shadow TLBs */
 
-/* extern void giveup_altivec(struct task_struct *prev)
- *
- * The PowerPC 4xx family of processors do not have AltiVec capabilities, so
- * this just returns.
- */
-_GLOBAL(giveup_altivec)
-	blr
-
 /* extern void giveup_fpu(struct task_struct *prev)
  *
  * The PowerPC 4xx family of processors do not have an FPU, so this just
@@ -842,16 +813,6 @@
 _GLOBAL(giveup_fpu)
 	blr
 
-/* extern void abort(void)
- *
- * At present, this routine just applies a system reset.
- */ 
-_GLOBAL(abort)
-        mfspr   r13,SPRN_DBCR0
-        oris    r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h
-        mtspr   SPRN_DBCR0,r13
-
-
 /* This is where the main kernel code starts.
  */ 
 start_here:
@@ -864,8 +825,6 @@
 	tophys(r4,r2)
 	addi	r4,r4,THREAD	/* init task's THREAD */
 	mtspr	SPRG3,r4
-	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
 
 	/* stack */
 	lis	r1,init_thread_union@ha
@@ -982,6 +941,10 @@
 
 	blr
 
+_GLOBAL(abort)
+        mfspr   r13,SPRN_DBCR0
+        oris    r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h
+        mtspr   SPRN_DBCR0,r13
 
 _GLOBAL(set_context)
 
diff -Nru a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
--- a/arch/ppc/kernel/head_8xx.S	Thu May  9 15:21:07 2002
+++ b/arch/ppc/kernel/head_8xx.S	Thu May  9 15:21:07 2002
@@ -33,7 +33,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 
 	.text
 	.globl	_stext
diff -Nru a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
--- a/arch/ppc/kernel/i8259.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc/kernel/i8259.c	Thu May  9 15:21:07 2002
@@ -11,7 +11,7 @@
 #include <asm/io.h>
 #include <asm/i8259.h>
 
-static volatile char *pci_intack; /* RO, gives us the irq vector */
+static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
 
 unsigned char cached_8259[2] = { 0xff, 0xff };
 #define cached_A1 (cached_8259[0])
@@ -24,13 +24,13 @@
 /* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
  * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
  */
-int i8259_irq(void)
+int i8259_irq(struct pt_regs *regs)
 {
 	int irq;
 
 	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
 
-	irq = *pci_intack & 0xff;
+	irq = *pci_intack;
 	if (irq==7) {
 		/*
 		 * This may be a spurious interrupt.
@@ -171,6 +171,10 @@
 	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
 };
 
+/* i8259_init()
+ * intack_addr - PCI interrupt acknowledge (real) address which will return
+ *               the active irq from the 8259
+ */
 void __init i8259_init(long intack_addr)
 {
 	unsigned long flags;
@@ -205,6 +209,9 @@
 	request_resource(&ioport_resource, &pic2_iores);
 	request_resource(&ioport_resource, &pic_edgectrl_iores);
 
-	if (intack_addr)
-		pci_intack = ioremap(intack_addr, 1);
+	/* XXX remove me after board maintainers fix their i8259_init calls */
+	if (intack_addr == 0)
+		panic("You must supply a PCI interrupt acknowledge address to i8259_init()\n");
+
+	pci_intack = ioremap(intack_addr, 1);
 }
diff -Nru a/arch/ppc/kernel/iSeries_head.S b/arch/ppc/kernel/iSeries_head.S
--- a/arch/ppc/kernel/iSeries_head.S	Thu May  9 15:21:04 2002
+++ b/arch/ppc/kernel/iSeries_head.S	Thu May  9 15:21:04 2002
@@ -32,7 +32,7 @@
 #include <asm/pgtable.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 #include "iSeries_asm.h"
 
 
diff -Nru a/arch/ppc/kernel/iSeries_misc.S b/arch/ppc/kernel/iSeries_misc.S
--- a/arch/ppc/kernel/iSeries_misc.S	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/iSeries_misc.S	Thu May  9 15:21:01 2002
@@ -22,7 +22,7 @@
 #include <asm/page.h>
 #include <asm/cache.h>
 #include <asm/ppc_asm.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 #include "iSeries_asm.h"
 
 	.text
diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
--- a/arch/ppc/kernel/idle.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/idle.c	Thu May  9 15:21:01 2002
@@ -56,7 +56,9 @@
 {
 	int do_power_save = 0;
 
-	if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)
+	/* Check if CPU can powersave */
+	if (cur_cpu_spec[smp_processor_id()]->cpu_features &
+		(CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP))
 		do_power_save = 1;
 
 #ifdef CONFIG_PPC_ISERIES
@@ -112,7 +114,7 @@
 	/* 7450 has no DOZE mode mode, we return if powersave_nap
 	 * isn't enabled
 	 */
-	if (!nap &&  cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450)
+	if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)))
 		return;
 	/*
 	 * Disable interrupts to prevent a lost wakeup
diff -Nru a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S
--- a/arch/ppc/kernel/l2cr.S	Thu May  9 15:21:08 2002
+++ b/arch/ppc/kernel/l2cr.S	Thu May  9 15:21:08 2002
@@ -134,6 +134,8 @@
 	       The bit moved on the 7450.....
 	  ****/
 
+	/* TODO: use HW flush assist when available */
+
 	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
@@ -154,10 +156,18 @@
 
 2:
 	/* Set up the L2CR configuration bits (and switch L2 off) */
+	/* CPU errata: Make sure the mtspr below is already in the
+	 * L1 icache
+	 */
+	b	20f
+21:
 	sync
 	mtspr	L2CR,r3
 	sync
-
+	b	22f
+20:
+	b	21b
+22:
 	/* Before we perform the global invalidation, we must disable dynamic
 	 * power management via HID0[DPM] to work around a processor bug where
 	 * DPM can possibly interfere with the state machine in the processor
@@ -221,6 +231,148 @@
 BEGIN_FTR_SECTION
 	mfspr	r3,L2CR
 END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
+	blr
+
+
+/*
+ * Here is a similar routine for dealing with the L3 cache
+ * on the 745x family of chips
+ */
+ 
+_GLOBAL(_set_L3CR)
+	/* Make sure this is a 745x chip */
+BEGIN_FTR_SECTION
+	li	r3,-1
+	blr
+END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
+
+	/* Turn off interrupts and data relocation. */
+	mfmsr	r7		/* Save MSR in r7 */
+	rlwinm	r4,r7,0,17,15
+	rlwinm	r4,r4,0,28,26	/* Turn off DR bit */
+	sync
+	mtmsr	r4
+	isync
+
+	/* Stop DST streams */
+	dssall	0
+	
+	/* Get the current enable bit of the L3CR into r4 */
+	mfspr	r4,SPRN_L3CR
+	
+	/* Tweak some bits */
+	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
+	rlwinm	r3,r3,0,22,20		/* Turn off the invalidate bit */
+	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
+	rlwinm	r3,r3,0,5,3		/* Turn off the clken bit */
+	/* Check to see if we need to flush */
+	rlwinm.	r4,r4,0,0,0
+	beq	2f
+
+	/* Flush the cache. First, read the first 4MB of memory (physical) to
+	 * put new data in the cache.  (Actually we only need
+	 * the size of the L3 cache plus the size of the L1+L2 cache, but 4MB will
+	 * cover everything just to be safe).
+	 */
+		
+	/* TODO: use HW flush assist */
+
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+1:
+	lwzx	r0,r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+	
+	/* Now, flush the first 4MB of memory */
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+	sync
+1:
+	dcbf	r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+
+2:
+	/* Set up the L3CR configuration bits (and switch L3 off) */
+	sync
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L3 cache tags. Hrm... This is necessary for L2,
+	 * is it for L3 as well ? --BenH.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
+	sync
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
+	oris	r3,r3,L3CR_L3RES@h		/* Set reserved bit 5 */
+	mtspr	SPRN_L3CR,r3
+	sync
+	oris	r3,r3,L3CR_L3CLKEN@h		/* Set clken */
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Wait for stabilize */
+	li	r0,128
+	mtctr	r0
+1:	bdnz	1b
+	
+	/* Perform a global invalidation */
+	ori	r3,r3,0x0400
+	sync
+	mtspr	SPRN_L3CR,r3
+	sync
+	isync
+
+	/* We wait for the L3I bit to clear...... */
+10:	mfspr	r3,SPRN_L3CR
+	andi.	r4,r3,0x0400
+	bne	10b
+
+	/* Clear CLKEN */
+	rlwinm	r3,r3,0,5,3		/* Turn off the clken bit */
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Wait for stabilize */
+	li	r0,128
+	mtctr	r0
+1:	bdnz	1b
+	
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
+	/* See if we need to enable the cache */
+	cmplwi	r5,0
+	beq	4f
+
+	/* Enable the cache */
+	oris	r3,r3,(L3CR_L3E | L3CR_L3CLKEN)@h
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Restore MSR (restores EE and DR bits to original state) */
+4:	SYNC
+	mtmsr	r7
+	isync
+	blr
+
+_GLOBAL(_get_L3CR)
+	/* Return the L3CR contents */
+	li	r3,0
+BEGIN_FTR_SECTION
+	mfspr	r3,SPRN_L3CR
+END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
 	blr
 
 /* --- End of PowerLogix code ---
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Thu May  9 15:21:05 2002
+++ b/arch/ppc/kernel/misc.S	Thu May  9 15:21:05 2002
@@ -26,7 +26,7 @@
 #include <asm/mmu.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include "ppc_defs.h"
+#include "asm-offsets.h"
 
 	.text
 
@@ -1017,20 +1017,28 @@
  *   kernel_thread(fn, arg, flags)
  */
 _GLOBAL(kernel_thread)
-	mr	r6,r3		/* function */
+	stwu	r1,-16(r1)
+	stw	r30,8(r1)
+	stw	r31,12(r1)
+	mr	r30,r3		/* function */
+	mr	r31,r4		/* argument */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
-	bnelr			/* return if parent */
+	bne	1f		/* return if parent */
 	li	r0,0		/* make top-level stack frame */
 	stwu	r0,-16(r1)
-	mtlr	r6              /* fn addr in lr */
-	mr	r3,r4	        /* load arg and call fn */
+	mtlr	r30		/* fn addr in lr */
+	mr	r3,r31		/* load arg and call fn */
 	blrl
-	li	r0,__NR_exit	/* exit after child exits */
+	li	r0,__NR_exit	/* exit if function returns */
 	li	r3,0
 	sc
+1:	lwz	r30,8(r1)
+	lwz	r31,12(r1)
+	addi	r1,r1,16
+	blr
 
 /*
  * This routine is just here to keep GCC happy - sigh...
@@ -1050,19 +1058,15 @@
 
 #define __NR__exit __NR_exit
 
-SYSCALL(sync)
 SYSCALL(setsid)
+SYSCALL(open)
+SYSCALL(read)
 SYSCALL(write)
+SYSCALL(lseek)
+SYSCALL(close)
 SYSCALL(dup)
 SYSCALL(execve)
-SYSCALL(open)
-SYSCALL(close)
 SYSCALL(waitpid)
-SYSCALL(fork)
-SYSCALL(delete_module)
-SYSCALL(_exit)
-SYSCALL(lseek)
-SYSCALL(read)
 
 /* Why isn't this a) automatic, b) written in 'C'? */	
 	.data
@@ -1070,7 +1074,7 @@
 _GLOBAL(sys_call_table)
 	.long sys_ni_syscall	/* 0  -  old "setup()" system call */
 	.long sys_exit
-	.long sys_fork
+	.long ppc_fork
 	.long sys_read
 	.long sys_write
 	.long sys_open		/* 5 */
@@ -1140,7 +1144,7 @@
 	.long sys_ssetmask
 	.long sys_setreuid	/* 70 */
 	.long sys_setregid
-	.long sys_sigsuspend
+	.long ppc_sigsuspend
 	.long sys_sigpending
 	.long sys_sethostname
 	.long sys_setrlimit	/* 75 */
@@ -1188,7 +1192,7 @@
 	.long sys_ipc
 	.long sys_fsync
 	.long sys_sigreturn
-	.long sys_clone		/* 120 */
+	.long ppc_clone		/* 120 */
 	.long sys_setdomainname
 	.long sys_newuname
 	.long sys_modify_ldt
@@ -1246,7 +1250,7 @@
 	.long sys_rt_sigpending	/* 175 */
 	.long sys_rt_sigtimedwait
 	.long sys_rt_sigqueueinfo
-	.long sys_rt_sigsuspend
+	.long ppc_rt_sigsuspend
 	.long sys_pread
 	.long sys_pwrite	/* 180 */
 	.long sys_chown
@@ -1257,7 +1261,7 @@
 	.long sys_sendfile
 	.long sys_ni_syscall		/* streams1 */
 	.long sys_ni_syscall		/* streams2 */
-	.long sys_vfork
+	.long ppc_vfork
 	.long sys_getrlimit	/* 190 */
 	.long sys_readahead
 	.long sys_mmap2	
diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
--- a/arch/ppc/kernel/mk_defs.c	Thu May  9 15:21:08 2002
+++ b/arch/ppc/kernel/mk_defs.c	Thu May  9 15:21:08 2002
@@ -107,10 +107,13 @@
 	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
 	/* The PowerPC 400-class processors have neither the DAR nor the DSISR
 	 * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
-	 * for such processors.
+	 * for such processors.  For critical interrupts we use them to
+	 * hold SRR0 and SRR1.
 	 */
 	DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
 	DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
 	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
 	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Thu May  9 15:21:08 2002
+++ b/arch/ppc/kernel/open_pic.c	Thu May  9 15:21:08 2002
@@ -34,6 +34,11 @@
 
 void* OpenPIC_Addr;
 static volatile struct OpenPIC *OpenPIC = NULL;
+/*
+ * We define OpenPIC_InitSenses table thusly:
+ * bit 0x1: sense, 0 for edge and 1 for level.
+ * bit 0x2: polarity, 0 for negative, 1 for positive.
+ */
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
 extern int use_of_interrupt_tree;
@@ -41,16 +46,12 @@
 static u_int NumProcessors;
 static u_int NumSources;
 static int open_pic_irq_offset;
-static volatile unsigned char* chrp_int_ack_special;
 static volatile OpenPIC_Source *ISR[NR_IRQS];
 
 /* Global Operations */
 static void openpic_disable_8259_pass_through(void);
 static void openpic_set_priority(u_int pri);
 static void openpic_set_spurious(u_int vector);
-static void openpic_enable_sie(void);
-static void openpic_eicr_set_clk(u_int clkval);
-static void openpic_eicr_set_clk(u_int clkval);
 
 #ifdef CONFIG_SMP
 /* Interprocessor Interrupts */
@@ -73,7 +74,6 @@
  * These functions are not used but the code is kept here
  * for completeness and future reference.
  */
-static void openpic_reset(void);
 #ifdef notused
 static void openpic_enable_8259_pass_through(void);
 static u_int openpic_get_priority(void);
@@ -263,6 +263,31 @@
 }
 #endif /* CONFIG_SMP */
 
+#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK)
+static void openpic_reset(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
+}
+#endif
+
+#ifdef CONFIG_EPIC_SERIAL_MODE
+static void openpic_enable_sie(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
+			 OPENPIC_EICR_SIE);
+}
+
+static void openpic_eicr_set_clk(u_int clkval)
+{
+	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
+			 OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
+}
+#endif
+
 void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
 {
 	volatile OpenPIC_Source *src = first_ISR;
@@ -277,8 +302,7 @@
 		ISR[i] = src;
 }
 
-void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
-			 int programmer_switch_irq)
+void __init openpic_init(int main_pic, int offset, int programmer_switch_irq)
 {
 	u_int t, i;
 	u_int timerfreq;
@@ -331,7 +355,6 @@
 		return;
 
 	open_pic_irq_offset = offset;
-	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
 
 	/* Initialize timer interrupts */
 	if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
@@ -359,14 +382,8 @@
 
 	openpic_set_priority(0xf);
 
-	/* SIOint (8259 cascade) is special */
-	if (offset) {
-		openpic_initirq(0, 8, offset, 1, 1);
-		openpic_mapirq(0, 1<<0, 0);
-	}
-
-	/* Init all external sources */
-	for (i = 1; i < NumSources; i++) {
+	/* Init all external sources, including possibly the cascade. */
+	for (i = 0; i < NumSources; i++) {
 		int pri, sense;
 
 		if (ISR[i] == 0)
@@ -376,12 +393,18 @@
 		openpic_disable_irq(i+offset);
 
 		pri = (i == programmer_switch_irq)? 9: 8;
+		/*
+		 * We find the vale from either the InitSenses table
+		 * or assume a negative polarity level interrupt.
+		 */
 		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
-		if (sense)
+
+		if ((sense & IRQ_SENSE_MASK) == 1)
 			irq_desc[i+offset].status = IRQ_LEVEL;
 
 		/* Enabled, Priority 8 or 9 */
-		openpic_initirq(i, pri, i+offset, !sense, sense);
+		openpic_initirq(i, pri, i+offset, (sense & IRQ_POLARITY_MASK),
+				(sense & IRQ_SENSE_MASK));
 		/* Processor 0 */
 		openpic_mapirq(i, 1<<0, 0);
 	}
@@ -400,40 +423,16 @@
 				"82c59 cascade", NULL))
 			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
 	}
-#ifdef CONFIG_EPIC_SERIAL_MODE
  	openpic_disable_8259_pass_through();
+#ifdef CONFIG_EPIC_SERIAL_MODE
 	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
 	openpic_enable_sie();
-	openpic_set_priority(0);
-#else
- 	openpic_disable_8259_pass_through();
- 	openpic_set_priority(0);
 #endif
+	openpic_set_priority(0);
 
 	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
 }
 
-static void openpic_reset(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-			 OPENPIC_CONFIG_RESET);
-	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
-				 OPENPIC_CONFIG_RESET))
-		mb();
-}
-
-static void openpic_enable_sie(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
-			 OPENPIC_EICR_SIE);
-}
-
-static void openpic_eicr_set_clk(u_int clkval)
-{
-	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
-			 OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
-}
-
 #ifdef notused
 static void openpic_enable_8259_pass_through(void)
 {
@@ -533,7 +532,9 @@
 	openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
 }
 
+#if defined(CONFIG_SMP) || defined(CONFIG_PMAC_PBOOK)
 static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 #ifdef CONFIG_SMP
 /*
@@ -810,19 +811,13 @@
 	/* Management of the cascade should be moved out of here */
 
 	/* Yep - because openpic !=> i8259, for one thing. -VAL */
-        if (open_pic_irq_offset && irq == open_pic_irq_offset)
-        {
-                /*
-                 * This magic address generates a PCI IACK cycle.
-                 */
-		if ( chrp_int_ack_special )
-			irq = *chrp_int_ack_special;
+	if (open_pic_irq_offset && irq == open_pic_irq_offset)
+	{
 #ifndef CONFIG_GEMINI
-		else
-			irq = i8259_poll();
+		irq = i8259_irq(regs); /* get IRQ from cascade */
 #endif
 		openpic_eoi();
-        }
+	}
 	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
 		irq = -1;
 	return irq;
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc/kernel/pci.c	Thu May  9 15:21:07 2002
@@ -189,14 +189,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 */
@@ -223,7 +233,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+		       unsigned long align)
 {
 	struct pci_dev *dev = data;
 
@@ -1014,7 +1025,7 @@
 }
 #endif /* CONFIG_ALL_PPC */
 
-void __init
+static int __init
 pcibios_init(void)
 {
 	struct pci_controller *hose;
@@ -1059,8 +1070,12 @@
 	/* Call machine dependent post-init code */
 	if (ppc_md.pcibios_after_init)
 		ppc_md.pcibios_after_init();
+
+	return 0;
 }
 
+subsys_initcall(pcibios_init);
+
 unsigned char __init
 common_swizzle(struct pci_dev *dev, unsigned char *pinp)
 {
@@ -1083,10 +1098,6 @@
 void __init
 pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
 }
 
 unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
diff -Nru a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c
--- a/arch/ppc/kernel/ppc4xx_setup.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/kernel/ppc4xx_setup.c	Thu May  9 15:21:01 2002
@@ -256,7 +256,7 @@
  * IDE stuff.
  * should be generic for every IDE PCI chipset
  */
-#if defined(CONFIG_BLK_DEV_IDEPCI)
+#ifdef  CONFIG_PCI
 static void
 ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
 			   ide_ioreg_t ctrl_port, int *irq)
@@ -376,7 +376,7 @@
 **     defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 */
 #ifdef CONFIG_IDE
-# if defined(CONFIG_BLK_DEV_IDEPCI)
+# if defined(CONFIG_PCI)
 	ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
 # elif defined (CONFIG_DMA_NONPCI)	/* ON board IDE */
 	ppc_ide_md.default_irq = nonpci_ide_default_irq;
diff -Nru a/arch/ppc/kernel/ppc_defs.head b/arch/ppc/kernel/ppc_defs.head
--- a/arch/ppc/kernel/ppc_defs.head	Thu May  9 15:21:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Thu May  9 15:21:09 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Thu May  9 15:21:09 2002
@@ -57,7 +57,6 @@
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 extern void transfer_to_handler(void);
 extern void do_syscall_trace(void);
 extern void do_IRQ(struct pt_regs *regs);
@@ -76,7 +75,6 @@
 
 extern unsigned char __res[];
 
-extern unsigned long ret_to_user_hook;
 extern unsigned long mm_ptov (unsigned long paddr);
 
 extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
@@ -173,7 +171,6 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
-EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
 #endif
 
 #ifdef CONFIG_PCI
@@ -315,9 +312,7 @@
 EXPORT_SYMBOL(__restore_flags);
 EXPORT_SYMBOL(__restore_flags_end);
 #endif
-EXPORT_SYMBOL(timer_interrupt_intercept);
 EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(do_IRQ_intercept);
 EXPORT_SYMBOL(irq_desc);
 void ppc_irq_dispatch_handler(struct pt_regs *, int);
 EXPORT_SYMBOL(ppc_irq_dispatch_handler);
@@ -358,7 +353,6 @@
 EXPORT_SYMBOL(request_8xxirq);
 #endif
 
-EXPORT_SYMBOL(ret_to_user_hook);
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
 EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
@@ -368,8 +362,6 @@
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
 #endif
-extern long *ret_from_intercept;
-EXPORT_SYMBOL(ret_from_intercept);
 EXPORT_SYMBOL(cur_cpu_spec);
 #if defined(CONFIG_ALL_PPC)
 extern unsigned long agp_special_page;
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc/kernel/process.c	Thu May  9 15:21:07 2002
@@ -251,16 +251,18 @@
 
 void show_regs(struct pt_regs * regs)
 {
-	int i;
+	int i, trap;
 
-	printk("NIP: %08lX XER: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx    %s\n",
-	       regs->nip, regs->xer, regs->link, regs->gpr[1], regs,regs->trap, print_tainted());
+	printk("NIP: %08lX LR: %08lX SP: %08lX REGS: %p TRAP: %04lx    %s\n",
+	       regs->nip, regs->link, regs->gpr[1], regs, regs->trap,
+	       print_tainted());
 	printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
 	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
 	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
 	       regs->msr&MSR_IR ? 1 : 0,
 	       regs->msr&MSR_DR ? 1 : 0);
-	if (regs->trap == 0x300 || regs->trap == 0x600)
+	trap = TRAP(regs);
+	if (trap == 0x300 || trap == 0x600)
 		printk("DAR: %08lX, DSISR: %08lX\n", regs->dar, regs->dsisr);
 	printk("TASK = %p[%d] '%s' ",
 	       current, current->pid, current->comm);
@@ -280,25 +282,18 @@
 #ifdef CONFIG_SMP
 	printk(" CPU: %d", smp_processor_id());
 #endif /* CONFIG_SMP */
-	
-	printk("\n");
-	for (i = 0;  i < 32;  i++)
-	{
+
+	for (i = 0;  i < 32;  i++) {
 		long r;
 		if ((i % 8) == 0)
-		{
-			printk("GPR%02d: ", i);
-		}
-
-		if ( __get_user(r, &(regs->gpr[i])) )
-		    goto out;
+			printk("\n" KERN_INFO "GPR%02d: ", i);
+		if (__get_user(r, &regs->gpr[i]))
+			break;
 		printk("%08lX ", r);
-		if ((i % 8) == 7)
-		{
-			printk("\n");
-		}
+		if (i == 12 && !FULL_REGS(regs))
+			break;
 	}
-out:
+	printk("\n");
 	print_backtrace((unsigned long *)regs->gpr[1]);
 }
 
@@ -336,6 +331,7 @@
 	unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE;
 	unsigned long childframe;
 
+	CHECK_FULL_REGS(regs);
 	/* Copy registers */
 	sp -= sizeof(struct pt_regs);
 	childregs = (struct pt_regs *) sp;
@@ -441,18 +437,21 @@
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
+	CHECK_FULL_REGS(regs);
 	return do_fork(p1, regs->gpr[1], regs, 0);
 }
 
 int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
 	     struct pt_regs *regs)
 {
+	CHECK_FULL_REGS(regs);
 	return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
 }
 
 int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
+	CHECK_FULL_REGS(regs);
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
 }
 
diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
--- a/arch/ppc/kernel/prom.c	Thu May  9 15:21:02 2002
+++ b/arch/ppc/kernel/prom.c	Thu May  9 15:21:02 2002
@@ -773,7 +773,12 @@
 		for (j = 0; j < np->n_intrs; j++) {
 			i = np->intrs[j].line;
 			if (i >= off && i < max)
-				senses[i-off] = np->intrs[j].sense;
+				if (np->intrs[j].sense == 1)
+					senses[i-off] = (IRQ_SENSE_LEVEL
+						| IRQ_POLARITY_NEGATIVE);
+				else
+					senses[i-off] = (IRQ_SENSE_EDGE 
+						| IRQ_POLARITY_POSITIVE);
 		}
 	}
 }
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c	Thu May  9 15:21:04 2002
+++ b/arch/ppc/kernel/ptrace.c	Thu May  9 15:21:04 2002
@@ -218,14 +218,15 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR)
+		if ((addr & 3) || index > PT_FPSCR
+		    || child->thread.regs == NULL)
 			break;
 
+		CHECK_FULL_REGS(child->thread.regs);
 		if (index < PT_FPR0) {
 			tmp = get_reg(child, (int) index);
 		} else {
-			if (child->thread.regs != NULL
-			    && child->thread.regs->msr & MSR_FP)
+			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
 		}
@@ -243,23 +244,23 @@
 		break;
 
 	/* write the word at location addr in the USER area */
-	/* XXX this will need fixing for 64-bit */
 	case PTRACE_POKEUSR: {
 		unsigned long index;
 
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
-		if ((addr & 3) || index > PT_FPSCR)
+		if ((addr & 3) || index > PT_FPSCR
+		    || child->thread.regs == NULL)
 			break;
 
+		CHECK_FULL_REGS(child->thread.regs);
 		if (index == PT_ORIG_R3)
 			break;
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
-			if (child->thread.regs != NULL
-			    && child->thread.regs->msr & MSR_FP)
+			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
 			ret = 0;
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Thu May  9 15:21:09 2002
+++ b/arch/ppc/kernel/setup.c	Thu May  9 15:21:09 2002
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/pmac_feature.h>
+#include <asm/sections.h>
 
 #if defined CONFIG_KGDB
 #include <asm/kgdb.h>
@@ -230,7 +231,6 @@
 	return 0;
 }
 
-
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
 	int i = *pos;
@@ -309,6 +309,27 @@
 }
 
 #ifdef CONFIG_ALL_PPC
+/*
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int __openfirmware
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+	struct device_node *cpu_node;
+	int *fp, s;
+			
+	cpu_node = find_type_devices("cpu");
+	if (!cpu_node)
+		return 0;
+	for (s = 0; s < i && cpu_node->next; s++)
+		cpu_node = cpu_node->next;
+	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
+	if (fp)
+		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+	return 0;
+}
+
 void __init
 intuit_machine_type(void)
 {
@@ -521,13 +542,34 @@
 	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
 		unsigned long val = simple_strtoul(str, NULL, 0);
 		printk(KERN_INFO "l2cr set to %lx\n", val);
-                _set_L2CR(0);           /* force invalidate by disable cache */
-                _set_L2CR(val);         /* and enable it */
+		_set_L2CR(0);		/* force invalidate by disable cache */
+		_set_L2CR(val);		/* and enable it */
 	}
 	return 1;
 }
 __setup("l2cr=", ppc_setup_l2cr);
 
+#ifdef CONFIG_NVRAM
+/* Generic nvram hooks we now look into ppc_md.nvram_read_val
+ * on pmac too ;)
+ * //XX Those 2 could be moved to headers
+ */
+unsigned char
+nvram_read_byte(int addr)
+{
+	if (ppc_md.nvram_read_val)
+		return ppc_md.nvram_read_val(addr);
+	return 0xff;
+}
+
+void
+nvram_write_byte(unsigned char val, int addr)
+{
+	if (ppc_md.nvram_write_val)
+		ppc_md.nvram_write_val(val, addr);
+}
+#endif /* CONFIG_NVRAM */
+
 int __init ppc_init(void)
 {
 	/* clear the progress line */
@@ -616,100 +658,3 @@
 	/* this is for modules since _machine can be a define -- Cort */
 	ppc_md.ppc_machine = _machine;
 }
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-#endif
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Thu May  9 15:21:06 2002
+++ b/arch/ppc/kernel/signal.c	Thu May  9 15:21:06 2002
@@ -44,6 +44,8 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
+extern void sigreturn_exit(struct pt_regs *);
+
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 
 /* 
@@ -111,20 +113,14 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->ccr |= 0x10000000;
+	regs->gpr[3] = EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(&saveset, regs))
-			/*
-			 * If a signal handler needs to be called,
-			 * do_signal() has set R3 to the signal number (the
-			 * first argument of the signal handler), so don't
-			 * overwrite that with EINTR !
-			 * In the other cases, do_signal() doesn't touch 
-			 * R3, so it's still set to -EINTR (see above).
-			 */
-			return regs->gpr[3];
+			sigreturn_exit(regs);
 	}
 }
 
@@ -148,20 +144,22 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->ccr |= 0x10000000;
+	regs->gpr[3] = EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(&saveset, regs))
-			return regs->gpr[3];
+			sigreturn_exit(regs);
 	}
 }
 
 
 int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, int r5, int r6,
+		int r7, int r8, struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *) &uss;
 	return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
@@ -236,16 +234,15 @@
  *  Each of these things must be a multiple of 16 bytes in size.
  *
  */
-int sys_rt_sigreturn(struct pt_regs *regs)
+int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
+		     struct pt_regs *regs)
 {
 	struct rt_sigframe *rt_sf;
 	struct sigcontext_struct sigctx;
 	struct sigregs *sr;
-	int ret;
 	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 	sigset_t set;
 	stack_t st;
-	unsigned long prevsp;
 
 	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
 	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
@@ -260,50 +257,26 @@
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	rt_sf++;			/* Look at next rt_sigframe */
-	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers -
-		 * sigctx is initialized to point to the 
-		 * preamble frame (where registers are stored) 
-		 * see handle_signal()
-		 */
-		sr = (struct sigregs *) sigctx.regs;
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-		/* This function sets back the stack flags into
-		   the current task structure.  */
-		sys_sigaltstack(&st, NULL);
+	/* restore registers -
+	 * sigctx is initialized to point to the 
+	 * preamble frame (where registers are stored) 
+	 * see handle_signal()
+	 */
+	sr = (struct sigregs *) sigctx.regs;
+	if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
+		goto badframe;
+	saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+		| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+	memcpy(regs, saved_regs, GP_REGS_SIZE);
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
+		goto badframe;
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
 
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		/* Set up registers for next signal handler */
-		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		/* Get the siginfo   */
-		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
-		/* Get the ucontext */
-		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
-		regs->gpr[6] = (unsigned long) rt_sf;
-
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-		current->thread.fpscr = 0;
-	}
-	return ret;
+	sigreturn_exit(regs);		/* doesn't return here */
+	return 0;
 
 badframe:
 	do_exit(SIGSEGV);
@@ -318,6 +291,7 @@
 	/* Set up preamble frame */
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
+	CHECK_FULL_REGS(regs);
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
@@ -327,7 +301,7 @@
 	   It calls the sc exception at offset 0x9999 
 	   for sys_rt_sigreturn().
 	*/
-	    || __put_user(0x38006666UL, &frame->tramp[0])	/* li r0,0x6666 */
+	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])
 	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
 		goto badframe;
 	flush_icache_range((unsigned long) &frame->tramp[0],
@@ -362,14 +336,13 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-int sys_sigreturn(struct pt_regs *regs)
+int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
+		  struct pt_regs *regs)
 {
 	struct sigcontext_struct *sc, sigctx;
 	struct sigregs *sr;
-	int ret;
 	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 	sigset_t set;
-	unsigned long prevsp;
 
 	sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
@@ -387,40 +360,20 @@
 	if (regs->msr & MSR_FP )
 		giveup_fpu(current);
 
-	sc++;			/* Look at next sigcontext */
-	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs *) sigctx.regs;
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-
-		ret = regs->result;
+	/* restore registers */
+	sr = (struct sigregs *) sigctx.regs;
+	if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
+		goto badframe;
+	saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+		| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+	memcpy(regs, saved_regs, GP_REGS_SIZE);
 
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
+		goto badframe;
 
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-		current->thread.fpscr = 0;
-	}
-	return ret;
+	sigreturn_exit(regs);		/* doesn't return here */
+	return 0;
 
 badframe:
 	do_exit(SIGSEGV);
@@ -437,12 +390,13 @@
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
+	CHECK_FULL_REGS(regs);
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
 	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
 			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38007777UL, &frame->tramp[0])    /* li r0,0x7777 */
+	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])
 	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
 		goto badframe;
 	flush_icache_range((unsigned long) &frame->tramp[0],
@@ -479,11 +433,14 @@
 	struct sigcontext_struct *sc;
 	struct rt_sigframe *rt_sf;
 
-	if (regs->trap == 0x0C00 /* System Call! */
+	if (TRAP(regs) == 0x0C00 /* System Call! */
 	    && ((int)regs->result == -ERESTARTNOHAND ||
 		((int)regs->result == -ERESTARTSYS &&
-		 !(ka->sa.sa_flags & SA_RESTART))))
+		 !(ka->sa.sa_flags & SA_RESTART)))) {
 		regs->result = -EINTR;
+		regs->gpr[3] = EINTR;
+		regs->ccr |= 0x10000000;
+	}
 
 	/* Set up Signal Frame */
 	if (ka->sa.sa_flags & SA_SIGINFO) {
@@ -511,7 +468,7 @@
 		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
 			goto badframe;
 	} else {
-		/* Put another sigcontext on the stack */
+		/* Put a sigcontext on the stack */
 		*newspp -= sizeof(*sc);
 		sc = (struct sigcontext_struct *) *newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
@@ -624,7 +581,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -665,7 +622,7 @@
 		break;
 	}
 
-	if (regs->trap == 0x0C00 /* System Call! */ &&
+	if (TRAP(regs) == 0x0C00 /* System Call! */ &&
 	    ((int)regs->result == -ERESTARTNOHAND ||
 	     (int)regs->result == -ERESTARTSYS ||
 	     (int)regs->result == -ERESTARTNOINTR)) {
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Thu May  9 15:21:03 2002
+++ b/arch/ppc/kernel/traps.c	Thu May  9 15:21:03 2002
@@ -172,6 +172,7 @@
 			printk(KERN_DEBUG "%s bad port %lx at %p\n",
 			       (*nip & 0x100)? "OUT to": "IN from",
 			       regs->gpr[rb] - _IO_BASE, nip);
+			regs->msr |= MSR_RI;
 			regs->nip = fixup;
 			return;
 		}
@@ -223,7 +224,7 @@
 void
 UnknownException(struct pt_regs *regs)
 {
-	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
+	printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
 	_exception(SIGTRAP, regs);
 }
@@ -266,6 +267,7 @@
 
 	if (!user_mode(regs))
 		return retval;
+	CHECK_FULL_REGS(regs);
 
 	if (get_user(instword, (uint *)(regs->nip)))
 		return -EFAULT;
@@ -366,6 +368,14 @@
 	panic("kernel stack overflow");
 }
 
+void nonrecoverable_exception(struct pt_regs *regs)
+{
+	printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n",
+	       regs->nip, regs->msr);
+	debugger(regs);
+	die("nonrecoverable exception", regs, SIGKILL);
+}
+
 void
 trace_syscall(struct pt_regs *regs)
 {
@@ -382,6 +392,8 @@
 	extern int Soft_emulate_8xx(struct pt_regs *);
 	int errcode;
 
+	CHECK_FULL_REGS(regs);
+
 	if (!user_mode(regs)) {
 		debugger(regs);
 		die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
@@ -423,7 +435,7 @@
 	} else if (debug_status & DBSR_IC) {	/* instruction completion */
 
 		mtspr(SPRN_DBSR, DBSR_IC);
-		regs->dbcr0 &=  ~DBCR0_IC;
+		mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
 
 		if (!user_mode(regs) && debugger_sstep(regs))
 			return;
@@ -436,7 +448,7 @@
 void
 TAUException(struct pt_regs *regs)
 {
-	printk("TAU trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
+	printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
 }
 #endif /* CONFIG_INT_TAU */
diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
--- a/arch/ppc/mm/Makefile	Thu May  9 15:21:04 2002
+++ b/arch/ppc/mm/Makefile	Thu May  9 15:21:04 2002
@@ -15,6 +15,8 @@
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
 
+AFLAGS_hashtable.o	+= -I$(TOPDIR)/arch/$(ARCH)/kernel
+
 O_TARGET			:= mm.o
 obj-y				:= fault.o init.o mem_pieces.o extable.o \
 					mmu_context.o pgtable.o
diff -Nru a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
--- a/arch/ppc/mm/fault.c	Thu May  9 15:21:04 2002
+++ b/arch/ppc/mm/fault.c	Thu May  9 15:21:04 2002
@@ -37,6 +37,7 @@
 #include <asm/mmu_context.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/tlbflush.h>
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 extern void (*debugger)(struct pt_regs *);
@@ -81,14 +82,14 @@
 	 * bits we are interested in.  But there are some bits which
 	 * indicate errors in DSISR but can validly be set in SRR1.
 	 */
-	if (regs->trap == 0x400)
+	if (TRAP(regs) == 0x400)
 		error_code &= 0x48200000;
 	else
 		is_write = error_code & 0x02000000;
 #endif /* CONFIG_4xx */
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-	if (debugger_fault_handler && regs->trap == 0x300) {
+	if (debugger_fault_handler && TRAP(regs) == 0x300) {
 		debugger_fault_handler(regs);
 		return;
 	}
@@ -140,7 +141,7 @@
 			goto bad_area;
 #if defined(CONFIG_4xx)
 	/* an exec  - 4xx allows for per-page execute permission */
-	} else if (regs->trap == 0x400) {
+	} else if (TRAP(regs) == 0x400) {
 		pte_t *ptep;
 
 #if 0
@@ -159,8 +160,8 @@
 			struct page *page = pte_page(*ptep);
 
 			if (! test_bit(PG_arch_1, &page->flags)) {
-				__flush_dcache_icache((unsigned long)kmap(page));
-				kunmap(page);
+				unsigned long phys = page_to_pfn(page) << PAGE_SHIFT;
+				__flush_dcache_icache_phys(phys);
 				set_bit(PG_arch_1, &page->flags);
 			}
 			pte_update(ptep, 0, _PAGE_HWEXEC);
diff -Nru a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
--- a/arch/ppc/mm/hashtable.S	Thu May  9 15:21:04 2002
+++ b/arch/ppc/mm/hashtable.S	Thu May  9 15:21:04 2002
@@ -33,7 +33,7 @@
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include <kernel/ppc_defs.h>
+#include "asm-offsets.h"
 
 #ifdef CONFIG_SMP
 	.comm	mmu_hash_lock,4
@@ -43,13 +43,13 @@
  * Load a PTE into the hash table, if possible.
  * The address is in r4, and r3 contains an access flag:
  * _PAGE_RW (0x400) if a write.
- * r23 contains the SRR1 value, from which we use the MSR_PR bit.
+ * r9 contains the SRR1 value, from which we use the MSR_PR bit.
  * SPRG3 contains the physical address of the current task's thread.
  *
  * Returns to the caller if the access is illegal or there is no
  * mapping for the address.  Otherwise it places an appropriate PTE
  * in the hash table and returns from the exception.
- * Uses r0, r2 - r7, ctr, lr.
+ * Uses r0, r3 - r8, ctr, lr.
  */
 	.text
 	.globl	hash_page
@@ -62,34 +62,34 @@
 #endif
 	tophys(r7,0)			/* gets -KERNELBASE into r7 */
 #ifdef CONFIG_SMP
-	addis	r2,r7,mmu_hash_lock@h
-	ori	r2,r2,mmu_hash_lock@l
+	addis	r8,r7,mmu_hash_lock@h
+	ori	r8,r8,mmu_hash_lock@l
 	lis	r0,0x0fff
 	b	10f
-11:	lwz	r6,0(r2)
+11:	lwz	r6,0(r8)
 	cmpwi	0,r6,0
 	bne	11b
-10:	lwarx	r6,0,r2
+10:	lwarx	r6,0,r8
 	cmpwi	0,r6,0
 	bne-	11b
-	stwcx.	r0,0,r2
+	stwcx.	r0,0,r8
 	bne-	10b
 	isync
 #endif
 	/* Get PTE (linux-style) and check access */
 	lis	r0,KERNELBASE@h		/* check if kernel address */
 	cmplw	0,r4,r0
-	mfspr	r2,SPRG3		/* current task's THREAD (phys) */
+	mfspr	r8,SPRG3		/* current task's THREAD (phys) */
 	ori	r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
-	lwz	r5,PGDIR(r2)		/* virt page-table root */
+	lwz	r5,PGDIR(r8)		/* virt page-table root */
 	blt+	112f			/* assume user more likely */
 	lis	r5,swapper_pg_dir@ha	/* if kernel address, use */
 	addi	r5,r5,swapper_pg_dir@l	/* kernel page table */
-	rlwimi	r3,r23,32-12,29,29	/* MSR_PR -> _PAGE_USER */
+	rlwimi	r3,r9,32-12,29,29	/* MSR_PR -> _PAGE_USER */
 112:	add	r5,r5,r7		/* convert to phys addr */
 	rlwimi	r5,r4,12,20,29		/* insert top 10 bits of address */
-	lwz	r2,0(r5)		/* get pmd entry */
-	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
+	lwz	r8,0(r5)		/* get pmd entry */
+	rlwinm.	r8,r8,0,0,19		/* extract address of pte page */
 #ifdef CONFIG_SMP
 	beq-	hash_page_out		/* return if no mapping */
 #else
@@ -99,7 +99,7 @@
 	   to the address following the rfi. */
 	beqlr-
 #endif
-	rlwimi	r2,r4,22,20,29		/* insert next 10 bits of address */
+	rlwimi	r8,r4,22,20,29		/* insert next 10 bits of address */
 	rlwinm	r0,r3,32-3,24,24	/* _PAGE_RW access -> _PAGE_DIRTY */
 	ori	r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
 
@@ -110,7 +110,7 @@
 	 * to update the PTE to set _PAGE_HASHPTE.  -- paulus.
 	 */
 retry:
-	lwarx	r6,0,r2			/* get linux-style pte */
+	lwarx	r6,0,r8			/* get linux-style pte */
 	andc.	r5,r3,r6		/* check access & ~permission */
 #ifdef CONFIG_SMP
 	bne-	hash_page_out		/* return if access not permitted */
@@ -118,13 +118,13 @@
 	bnelr-
 #endif
 	or	r5,r0,r6		/* set accessed/dirty bits */
-	stwcx.	r5,0,r2			/* attempt to update PTE */
+	stwcx.	r5,0,r8			/* attempt to update PTE */
 	bne-	retry			/* retry if someone got there first */
 
 	mfsrin	r3,r4			/* get segment reg for segment */
-	mr	r2,r8			/* we have saved r2 but not r8 */
+	mfctr	r0
+	stw	r0,_CTR(r11)
 	bl	create_hpte		/* add the hash table entry */
-	mr	r8,r2
 
 /*
  * htab_reloads counts the number of times we have to fault an
@@ -134,48 +134,34 @@
  * update_mmu_cache gets called to put the HPTE into the hash table
  * and those are counted as preloads rather than reloads.
  */
-	addis	r2,r7,htab_reloads@ha
-	lwz	r3,htab_reloads@l(r2)
+	addis	r8,r7,htab_reloads@ha
+	lwz	r3,htab_reloads@l(r8)
 	addi	r3,r3,1
-	stw	r3,htab_reloads@l(r2)
+	stw	r3,htab_reloads@l(r8)
 
 #ifdef CONFIG_SMP
 	eieio
-	addis	r2,r7,mmu_hash_lock@ha
+	addis	r8,r7,mmu_hash_lock@ha
 	li	r0,0
-	stw	r0,mmu_hash_lock@l(r2)
+	stw	r0,mmu_hash_lock@l(r8)
 #endif
 
 	/* Return from the exception */
-	lwz	r3,_CCR(r21)
-	lwz	r4,_LINK(r21)
-	lwz	r5,_CTR(r21)
-	mtcrf	0xff,r3
+	lwz	r4,_LINK(r11)
+	lwz	r5,_CTR(r11)
 	mtlr	r4
 	mtctr	r5
-	lwz	r0,GPR0(r21)
-	lwz	r1,GPR1(r21)
-	lwz	r2,GPR2(r21)
-	lwz	r3,GPR3(r21)
-	lwz	r4,GPR4(r21)
-	lwz	r5,GPR5(r21)
-	lwz	r6,GPR6(r21)
-	lwz	r7,GPR7(r21)
-	/* we haven't used xer */
-	mtspr	SRR1,r23
-	mtspr	SRR0,r22
-	lwz	r20,GPR20(r21)
-	lwz	r22,GPR22(r21)
-	lwz	r23,GPR23(r21)
-	lwz	r21,GPR21(r21)
-	RFI
+	lwz	r0,GPR0(r11)
+	lwz	r7,GPR7(r11)
+	lwz	r8,GPR8(r11)
+	b	fast_exception_return
 	
 #ifdef CONFIG_SMP
 hash_page_out:
 	eieio
-	addis	r2,r7,mmu_hash_lock@ha
+	addis	r8,r7,mmu_hash_lock@ha
 	li	r0,0
-	stw	r0,mmu_hash_lock@l(r2)
+	stw	r0,mmu_hash_lock@l(r8)
 	blr
 #endif /* CONFIG_SMP */
 
diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c	Thu May  9 15:21:04 2002
+++ b/arch/ppc/mm/init.c	Thu May  9 15:21:04 2002
@@ -288,8 +288,6 @@
 		ppc_md.progress("MMU:exit", 0x211);
 
 #ifdef CONFIG_BOOTX_TEXT
-	/* By default, we are no longer mapped */
-	boot_text_mapped = 0;	
 	/* Must be done last, or ppc_md.progress will die. */
 	map_boot_text();
 #endif
diff -Nru a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c
--- a/arch/ppc/mm/mmu_context.c	Thu May  9 15:21:08 2002
+++ b/arch/ppc/mm/mmu_context.c	Thu May  9 15:21:08 2002
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 
 #include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
 
 mm_context_t next_mmu_context;
 unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
@@ -46,7 +47,8 @@
 /*
  * Initialize the context management stuff.
  */
-void __init mmu_context_init(void)
+void __init
+mmu_context_init(void)
 {
 	/*
 	 * Some processors have too few contexts to reserve one for
@@ -74,7 +76,8 @@
  * place to implement an LRU scheme if anyone was motivated to do it.
  *  -- paulus
  */
-void steal_context(void)
+void
+steal_context(void)
 {
 	struct mm_struct *mm;
 
diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c	Thu May  9 15:21:04 2002
+++ b/arch/ppc/platforms/chrp_setup.c	Thu May  9 15:21:04 2002
@@ -386,7 +386,7 @@
 {
 	struct device_node *np;
 	int i;
-	unsigned char* chrp_int_ack_special = 0;
+	unsigned long chrp_int_ack;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
 	int nmi_irq = -1;
 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)	
@@ -396,14 +396,14 @@
 	for (np = find_devices("pci"); np != NULL; np = np->next) {
 		unsigned int *addrp = (unsigned int *)
 			get_property(np, "8259-interrupt-acknowledge", NULL);
+
 		if (addrp == NULL)
 			continue;
-		chrp_int_ack_special = (unsigned char *)
-			ioremap(addrp[prom_n_addr_cells(np)-1], 1);
+		chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
 		break;
 	}
 	if (np == NULL)
-		printk("Cannot find pci to get ack address\n");
+		printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n");
 
 	chrp_find_openpic();
 
@@ -411,11 +411,11 @@
 	OpenPIC_InitSenses = init_senses;
 	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
 
-	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
+	openpic_init(1, NUM_8259_INTERRUPTS, nmi_irq);
 
 	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0);
+	i8259_init(chrp_int_ack);
 
 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
 	/* see if there is a keyboard in the device tree
@@ -433,7 +433,8 @@
 chrp_init2(void)
 {
 #ifdef CONFIG_NVRAM  
-	pmac_nvram_init();
+// XX replace this in a more saner way
+//	pmac_nvram_init();
 #endif
 
 	request_region(0x20,0x20,"pic1");
diff -Nru a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec_setup.c
--- a/arch/ppc/platforms/lopec_setup.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/platforms/lopec_setup.c	Thu May  9 15:21:01 2002
@@ -6,7 +6,7 @@
  * Author: Dan Cox
  *         danc@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2002 MontaVista Software Inc.
  *
  * 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
@@ -44,21 +44,35 @@
 #include <asm/bootinfo.h>
 #include <asm/mpc10x.h>
 
-#define LOPEC_SIO_IRQ  16
-#define LOPEC_SYSSTAT1 0xffe00000
-
 extern void lopec_find_bridges(void);
 
-static u_char lopec_openpic_initsenses[32] __initdata = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1
+/*
+ * Define all of the IRQ senses and polarities.  Taken from the
+ * LoPEC Programmer's Reference Guide.
+ */
+static u_char lopec_openpic_initsenses[16] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 6 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 7 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 8 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 9 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 10 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 11 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 12 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 13 */
+	(IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),	/* IRQ 14 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE)	/* IRQ 15 */
 };
 
-
 static int
 lopec_show_cpuinfo(struct seq_file *m)
 {
-	seq_printf(m, "machine\t\t: Motorola LoPec\n");
+	seq_printf(m, "machine\t\t: Motorola LoPEC\n");
 	return 0;
 }
 
@@ -74,6 +88,7 @@
 static void
 lopec_restart(char *cmd)
 {
+#define LOPEC_SYSSTAT1 0xffe00000
 	/* force a hard reset, if possible */
 	unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1);
 	reg |= 0x80;
@@ -81,6 +96,7 @@
 
 	__cli();
 	while(1);
+#undef LOPEC_SYSSTAT1
 }
 
 static void
@@ -96,27 +112,6 @@
 	lopec_halt();
 }
 
-static int
-lopec_get_irq(struct pt_regs *regs)
-{
-	int irq, cascade_irq;
-
-	irq = openpic_irq();
-
-	if (irq == LOPEC_SIO_IRQ) {
-		cascade_irq = i8259_poll();
-
-		if (cascade_irq != -1) {
-			irq = cascade_irq;
-			openpic_eoi();
-		}
-	}
-	else if (irq == OPENPIC_VEC_SPURIOUS)
-		irq = -1;
-
-	return irq;
-}
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 int lopec_ide_ports_known = 0;
 static ide_ioreg_t lopec_ide_regbase[MAX_HWIFS];
@@ -202,24 +197,41 @@
 {
 	int i;
 
+	/*
+	 * Provide the open_pic code with the correct table of interrupts.
+	 */
 	OpenPIC_InitSenses = lopec_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses);
-	openpic_init(1, 0, NULL, -1);
 
+	/*
+	 * We need to tell openpic_set_sources where things actually are.
+	 * mpc10x_common will setup OpenPIC_Addr at ioremap(EUMB phys base +
+	 * EPIC offset (0x40000));  The EPIC IRQ Register Address Map -
+	 * Interrupt Source Configuration Registers gives these numbers
+	 * as offsets starting at 0x50200, we need to adjust occordinly.
+	 */
+	/* Map serial interrupts 0-15 */
+	openpic_set_sources(0, 16, OpenPIC_Addr + 0x10200);
+	/* Skip reserved space and map i2c and DMA Ch[01] */
+	openpic_set_sources(16, 3, OpenPIC_Addr + 0x11020);
+	/* Skip reserved space and map Message Unit Interrupt (I2O) */
+	openpic_set_sources(19, 1, OpenPIC_Addr + 0x110C0);
+
+	openpic_init(1, NUM_8259_INTERRUPTS, -1);
+
+	/* Map i8259 interrupts */
 	for(i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
 
-	if (request_irq(LOPEC_SIO_IRQ, no_action, SA_INTERRUPT,
-			"8259 cascade to EPIC", NULL)) {
-		printk("Unable to get EPIC %d for cascade.\n",
-		       LOPEC_SIO_IRQ);
-	}
-
-	i8259_init(NULL);
+	/*
+	 * The EPIC allows for a read in the range of 0xFEF00000 ->
+	 * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction.
+	 */
+	i8259_init(0xfef00000);
 }
 
-static void __init
-lopec_init2(void)
+void __init
+lopec_request_io(void)
 {
 	outb(0x00, 0x4d0);
 	outb(0xc0, 0x4d1);
@@ -232,6 +244,8 @@
 	request_region(0xc0, 0x20, "dma2");
 }
 
+arch_initcall(lopec_request_io);
+
 static void __init
 lopec_map_io(void)
 {
@@ -255,10 +269,47 @@
 		: "=r" (batu), "=r" (batl));
 }
 
+#ifdef  CONFIG_SERIAL_TEXT_DEBUG
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
+	SERIAL_PORT_DFNS	/* Defined in <asm/serial.h> */
+};
+
+volatile unsigned char *com_port;
+volatile unsigned char *com_port_lsr;
+
+static void
+serial_writechar(char c)
+{
+	while ((*com_port_lsr & UART_LSR_THRE) == 0)
+		;
+	*com_port = c;
+}
+
+void
+lopec_progress(char *s, unsigned short hex)
+{
+	volatile char c;
+
+	com_port = (volatile unsigned char *) rs_table[0].port;
+	com_port_lsr = com_port + UART_LSR;
+
+	while ((c = *s++) != 0)
+		serial_writechar(c);
+
+	/* Most messages don't have a newline in them */
+	serial_writechar('\n');
+	serial_writechar('\r');
+}
+#endif	/* CONFIG_SERIAL_TEXT_DEBUG */
+
 static unsigned long __init
 lopec_find_end_of_memory(void)
 {
-	lopec_set_bat();
 	return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
 }
 
@@ -281,7 +332,7 @@
 	else
 #elif defined(CONFIG_ROOT_NFS)
         	ROOT_DEV = to_kdev_t(0x00ff);
-#elif defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_ID_MODULE)
+#elif defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	        ROOT_DEV = to_kdev_t(0x0301);
 #else
         	ROOT_DEV = to_kdev_t(0x0801);
@@ -297,6 +348,7 @@
 	      unsigned long r6, unsigned long r7)
 {
 	parse_bootinfo(find_bootinfo());
+	lopec_set_bat();
 
 	isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
 	isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
@@ -309,8 +361,7 @@
 	ppc_md.show_cpuinfo = lopec_show_cpuinfo;
 	ppc_md.irq_cannonicalize = lopec_irq_cannonicalize;
 	ppc_md.init_IRQ = lopec_init_IRQ;
-	ppc_md.get_irq = lopec_get_irq;
-	ppc_md.init = lopec_init2;
+	ppc_md.get_irq = openpic_get_irq;
 
 	ppc_md.restart = lopec_restart;
 	ppc_md.power_off = lopec_power_off;
@@ -331,5 +382,8 @@
 	ppc_ide_md.default_irq = lopec_ide_default_irq;
 	ppc_ide_md.default_io_base = lopec_ide_default_io_base;
 	ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = lopec_progress;
 #endif
 }
diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
--- a/arch/ppc/platforms/pmac_feature.c	Thu May  9 15:21:05 2002
+++ b/arch/ppc/platforms/pmac_feature.c	Thu May  9 15:21:05 2002
@@ -193,13 +193,14 @@
 }
 
 static int __pmac
-generic_scc_enable(struct device_node* node, u32 enable_mask, u32 reset_mask,
-	int param, int value)
+ohare_htw_scc_enable(struct device_node* node, int param, int value)
 {
 	struct macio_chip*	macio;
 	unsigned long		chan_mask;
 	unsigned long		fcr;
 	unsigned long		flags;
+	int			htw;
+	unsigned long		rmask;
 	
 	macio = macio_find(node, 0);
 	if (!macio)
@@ -211,20 +212,32 @@
 	else
 		return -ENODEV;
 
+	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+		|| macio->type == macio_gatwick);
 	if (value) {
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */		
 		LOCK(flags);
 		fcr = MACIO_IN32(OHARE_FCR);
 		/* Check if scc cell need enabling */
 		if (!(fcr & OH_SCC_ENABLE)) {
-			fcr |= enable_mask;
-			MACIO_OUT32(OHARE_FCR, fcr);
-			fcr |= reset_mask;
-			MACIO_OUT32(OHARE_FCR, fcr);
+			fcr |= OH_SCC_ENABLE;
+			if (htw) {
+				fcr &= ~HRW_SCC_TRANS_EN_N;
+				MACIO_OUT32(OHARE_FCR, fcr);
+				fcr |= (rmask = HRW_RESET_SCC);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			} else {
+				fcr |= (rmask = OH_SCC_RESET);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			}
 			UNLOCK(flags);
 			(void)MACIO_IN32(OHARE_FCR);
 			mdelay(15);
 			LOCK(flags);
-			fcr &= ~reset_mask;
+			fcr &= ~rmask;
 			MACIO_OUT32(OHARE_FCR, fcr);
 		}
 		if (chan_mask & MACIO_FLAG_SCCA_ON)
@@ -247,31 +260,20 @@
 			fcr &= ~OH_SCCB_IO;
 		MACIO_OUT32(OHARE_FCR, fcr);
 		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-			fcr &= ~enable_mask;
+			fcr &= ~OH_SCC_ENABLE;
+			if (htw)
+				fcr |= HRW_SCC_TRANS_EN_N;
 			MACIO_OUT32(OHARE_FCR, fcr);
 		}
 		macio->flags &= ~(chan_mask);
 		UNLOCK(flags);
 		mdelay(10);
-	}
-	return 0;
-}
-
-static int __pmac
-ohare_scc_enable(struct device_node* node, int param, int value)
-{
-	int rc;
-
 #ifdef CONFIG_ADB_PMU
-	if (value && (param & 0xfff) == PMAC_SCC_IRDA)
-		pmu_enable_irled(1);
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(0);
 #endif /* CONFIG_ADB_PMU */		
-	rc = generic_scc_enable(node, OH_SCC_ENABLE, OH_SCC_RESET, param, value);
-#ifdef CONFIG_ADB_PMU
-	if ((param & 0xfff) == PMAC_SCC_IRDA && (rc || !value))
-		pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	return rc;
+	}
+	return 0;
 }
 
 static int __pmac
@@ -341,27 +343,6 @@
 }
 
 static int __pmac
-heathrow_scc_enable(struct device_node* node, int param, int value)
-{
-	int rc;
-	
-#ifdef CONFIG_ADB_PMU
-	if (value && param == PMAC_SCC_IRDA)
-		pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */		
-	/* Fixme: It's possible that wallstreet (heathrow) is different
-	 * than other paddington machines. I still have to figure that
-	 * out exactly, for now, the paddington values are used
-	 */
-	rc = generic_scc_enable(node, HRW_SCC_ENABLE, PADD_RESET_SCC, param, value);
-#ifdef CONFIG_ADB_PMU
-	if (param == PMAC_SCC_IRDA && (rc || !value))
-		pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	return rc;
-}
-
-static int __pmac
 heathrow_modem_enable(struct device_node* node, int param, int value)
 {
 	struct macio_chip*	macio;
@@ -382,16 +363,10 @@
 	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
 	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
 	    	LOCK(flags);
-	    	/* We use the paddington values as they seem to work properly
-	    	 * on the wallstreet (heathrow) as well. I can't tell why we
-	    	 * had to flip them on older feature.c, the fact is that new
-	    	 * code uses the paddington values which are also the ones used
-	    	 * in Darwin, and that works on wallstreet !
-	    	 */
 	    	if (value)
-	    		MACIO_BIC(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	    	else
-	    		MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	    	UNLOCK(flags);
 	    	(void)MACIO_IN32(HEATHROW_FCR);
 		mdelay(250);
@@ -400,17 +375,13 @@
 		LOCK(flags);
 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags);
-		mdelay(250);
-		LOCK(flags);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags);
-		mdelay(250);
-		LOCK(flags);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -618,11 +589,14 @@
 		/* This seems to be necessary as well or the fan
 		 * keeps coming up and battery drains fast */
 		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+		/* Make sure eth is down even if module or sleep
+		 * won't work properly */
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
 	}
 	/* Make sure modem is shut down */
 	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
 		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-	MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
 
 	/* Let things settle */
@@ -814,7 +788,7 @@
 	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -1471,7 +1445,7 @@
 	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -1487,7 +1461,8 @@
 			return pmac_mb.board_flags;
 		case PMAC_MB_INFO_NAME:	
 			/* hack hack hack... but should work */
-			return (int)pmac_mb.model_name;
+			*((const char **)value) = pmac_mb.model_name;
+			break;
 	}
 	return 0;
 }
@@ -1509,7 +1484,7 @@
  * to have issues with turning on/off those asic cells
  */
 static struct feature_table_entry ohare_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
 	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
@@ -1535,7 +1510,7 @@
  * powerbooks.
  */
 static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		heathrow_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
@@ -1551,7 +1526,7 @@
  * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
  */
 static struct feature_table_entry paddington_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		heathrow_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
@@ -1625,6 +1600,10 @@
 		PMAC_TYPE_PSURGE,		NULL,
 		0
 	},
+	{	"AAPL,ShinerESB",		"Apple Network Server",
+		PMAC_TYPE_ANS,			NULL,
+		0
+	},
 	{	"AAPL,e407",			"Alchemy",
 		PMAC_TYPE_ALCHEMY,		NULL,
 		0
@@ -1665,6 +1644,10 @@
 		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
 		PMAC_MB_CAN_SLEEP
 	},
+	{	"PowerBook4,2",			"iBook 2 with 14\" LCD",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
 	{	"PowerBook4,1",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
 		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
@@ -1732,6 +1715,10 @@
 		PMAC_TYPE_TITANIUM2,		core99_features,
 		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
+	{	"PowerBook3,4",			"PowerBook Titanium III",
+		PMAC_TYPE_TITANIUM3,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
 };
 
 /*
@@ -1745,13 +1732,12 @@
 	feature_call func = NULL;
 	va_list args;
 	
-	if (!pmac_mb.features)
-		return -ENODEV;
-	for (i=0; pmac_mb.features[i].function; i++)
-		if (pmac_mb.features[i].selector == selector) {
-			func = pmac_mb.features[i].function;
-			break;
-		}
+	if (pmac_mb.features)
+		for (i=0; pmac_mb.features[i].function; i++)
+			if (pmac_mb.features[i].selector == selector) {
+				func = pmac_mb.features[i].function;
+				break;
+			}
 	if (!func)
 		for (i=0; any_features[i].function; i++)
 			if (any_features[i].selector == selector) {
@@ -2070,11 +2056,21 @@
 		}
 	}
 
-	/* On all machines, switch sound off */
+	/* On all machines that support sound PM, switch sound off */
 	if (macio_chips[0].of_node)
 		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
 			macio_chips[0].of_node, 0, 0);
 
+	/* While on some desktop G3s, we turn it back on */
+	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+	}
+
+
 	/* On all machines, switch modem & serial ports off */
 	np = find_devices("ch-a");
 	while(np) {
@@ -2113,7 +2109,7 @@
 	set_initial_features();
 }
 
-void __init
+int __init
 pmac_feature_late_init(void)
 {
 	struct device_node* np;
@@ -2127,4 +2123,7 @@
 	np = find_devices("interrupt-controller");
 	if (np)
 		request_OF_resource(np, 0, NULL);
+	return 0;
 }
+
+device_initcall(pmac_feature_late_init);
diff -Nru a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c
--- a/arch/ppc/platforms/pmac_nvram.c	Thu May  9 15:21:06 2002
+++ b/arch/ppc/platforms/pmac_nvram.c	Thu May  9 15:21:06 2002
@@ -2,7 +2,17 @@
  * BK Id: %F% %I% %G% %U% %#%
  */
 /*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
+ *  arch/ppc/platforms/pmac_nvram.c
+ *
+ *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *  
+ *  Todo: - cleanup some coding horrors in the flash code
+ *        - add support for the OF persistent properties
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -75,7 +85,7 @@
 
 extern int pmac_newworld;
 
-static u8 __openfirmware
+static u8 __pmac
 chrp_checksum(struct chrp_header* hdr)
 {
 	u8 *ptr;
@@ -314,8 +324,8 @@
 		printk("nvram: Error writing bank %d\n", core99_bank);
 }
 
-unsigned char __openfirmware
-nvram_read_byte(int addr)
+unsigned char __pmac
+pmac_nvram_read_byte(int addr)
 {
 	switch (nvram_naddrs) {
 #ifdef CONFIG_ADB_PMU
@@ -342,8 +352,8 @@
 	return 0;
 }
 
-void __openfirmware
-nvram_write_byte(unsigned char val, int addr)
+void __pmac
+pmac_nvram_write_byte(int addr, unsigned char val)
 {
 	switch (nvram_naddrs) {
 #ifdef CONFIG_ADB_PMU
@@ -388,7 +398,7 @@
 	if (offset < 0)
 		return 0;
 		
-	return nvram_read_byte(xpaddr + offset);
+	return pmac_nvram_read_byte(xpaddr + offset);
 }
 
 void __pmac
@@ -399,5 +409,5 @@
 	if (offset < 0)
 		return;
 		
-	nvram_write_byte(xpaddr + offset, data);
+	pmac_nvram_write_byte(data, xpaddr + offset);
 }
diff -Nru a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c
--- a/arch/ppc/platforms/pmac_pci.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc/platforms/pmac_pci.c	Thu May  9 15:21:07 2002
@@ -3,12 +3,14 @@
  */
 /*
  * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
+ * 
+ * This includes support for bandit, chaos, grackle (motorola
+ * MPC106), and uninorth
  *
  * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
  *
+ * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
  * 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
@@ -256,21 +258,12 @@
 		rev = in_8(bp->cfg_data);
 		if (rev != BANDIT_REVID)
 			printk(KERN_WARNING
-			       "Unknown revision %d for bandit at %08lx\n",
-			       rev, bp->io_base_phys);
+			       "Unknown revision %d for bandit\n", rev);
 	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
 		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
 		return;
 	}
 
-	/* read the revision id */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-	udelay(2);
-	rev = in_8(bp->cfg_data);
-	if (rev != BANDIT_REVID)
-		printk(KERN_WARNING "Unknown revision %d for bandit at %08lx\n",
-		       rev, bp->io_base_phys);
-
 	/* read the word at offset 0x50 */
 	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
 	udelay(2);
@@ -280,8 +273,7 @@
 	magic |= BANDIT_COHERENT;
 	udelay(2);
 	out_le32((volatile unsigned int *)bp->cfg_data, magic);
-	printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %08lx\n",
-	       bp->io_base_phys);
+	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
 }
 
 
@@ -490,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 -Nru a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
--- a/arch/ppc/platforms/pmac_pic.c	Thu May  9 15:21:05 2002
+++ b/arch/ppc/platforms/pmac_pic.c	Thu May  9 15:21:05 2002
@@ -1,6 +1,23 @@
 /*
  * BK Id: %F% %I% %G% %U% %#%
  */
+/*
+ *  Support for the interrupt controllers found on Power Macintosh,
+ *  currently Apple's "Grand Central" interrupt controller in all
+ *  it's incarnations. OpenPIC support used on newer machines is
+ *  in a separate file
+ *
+ *  Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  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.
+ *
+ */
+
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -373,7 +390,7 @@
 			ppc_md.get_irq = openpic_get_irq;
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, 0, nmi_irq);
+			openpic_init(1, 0, nmi_irq);
 #ifdef CONFIG_XMON
 			if (nmi_irq >= 0)
 				request_irq(nmi_irq, xmon_irq, 0,
diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c	Thu May  9 15:21:02 2002
+++ b/arch/ppc/platforms/pmac_setup.c	Thu May  9 15:21:02 2002
@@ -13,6 +13,8 @@
  *  Derived from "arch/alpha/kernel/setup.c"
  *    Copyright (C) 1995 Linus Torvalds
  *
+ *  Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
  *  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
@@ -106,9 +108,11 @@
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern int keyboard_sends_linux_keycodes;
 extern void pmac_nvram_update(void);
-
+extern unsigned char pmac_nvram_read_byte(int addr);
+extern void pmac_nvram_write_byte(int addr, unsigned char val);
 extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
 extern void pmac_pcibios_after_init(void);
+extern int of_show_percpuinfo(struct seq_file *m, int i);
 
 extern kdev_t sd_find_target(void *host, int tgt);
 
@@ -139,56 +143,23 @@
 #ifdef CONFIG_SMP
 extern struct smp_ops_t psurge_smp_ops;
 extern struct smp_ops_t core99_smp_ops;
-
-volatile static long int core99_l2_cache;
-void __init
-core99_init_l2(void)
-{
-	int cpu = smp_processor_id();
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
-		return;
-
-	if (cpu == 0){
-		core99_l2_cache = _get_L2CR();
-		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-	} else {
-		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-		_set_L2CR(0);
-		_set_L2CR(core99_l2_cache);
-		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-	}
-}
 #endif /* CONFIG_SMP */
 
-/*
- * Assume here that all clock rates are the same in a
- * smp system.  -- Cort
- */
-int __openfirmware
-of_show_percpuinfo(struct seq_file *m, int i)
-{
-	struct device_node *cpu_node;
-	int *fp, s;
-			
-	cpu_node = find_type_devices("cpu");
-	if (!cpu_node)
-		return 0;
-	for (s = 0; s < i && cpu_node->next; s++)
-		cpu_node = cpu_node->next;
-	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
-	if (fp)
-		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
-	return 0;
-}
-
 int __pmac
 pmac_show_cpuinfo(struct seq_file *m)
 {
 	struct device_node *np;
 	char *pp;
 	int plen;
+	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_MODEL, 0);
+	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_FLAGS, 0);
+	char* mbname;
 
+	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+		mbname = "Unknown";
+		
 	/* find motherboard type */
 	seq_printf(m, "machine\t\t: ");
 	np = find_devices("device-tree");
@@ -212,6 +183,10 @@
 	} else
 		seq_printf(m, "PowerMac\n");
 
+	/* print parsed model */
+	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+	
 	/* find l2 cache info */
 	np = find_devices("l2-cache");
 	if (np == 0)
@@ -341,11 +316,6 @@
 		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
 			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
 				? "enabled" : "disabled");
-
-#ifdef CONFIG_SMP
-	/* somewhat of a hack */
-	core99_init_l2();
-#endif
 	
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
@@ -420,21 +390,6 @@
 int boot_part;
 extern kdev_t boot_dev;
 
-void __init
-pmac_init2(void)
-{
-#ifdef CONFIG_ADB_PMU
-	via_pmu_start();
-#endif
-#ifdef CONFIG_ADB_CUDA
-	via_cuda_start();
-#endif
-#ifdef CONFIG_PMAC_PBOOK
-	media_bay_init();
-#endif
-	pmac_feature_late_init();
-}
-
 #ifdef CONFIG_SCSI
 void __init
 note_scsi_host(struct device_node *node, void *host)
@@ -736,7 +691,6 @@
 	ppc_md.irq_cannonicalize = NULL;
 	ppc_md.init_IRQ       = pmac_pic_init;
 	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-	ppc_md.init           = pmac_init2;
 	
 	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
 	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
@@ -750,6 +704,11 @@
 	ppc_md.set_rtc_time   = pmac_set_rtc_time;
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+#ifdef CONFIG_NVRAM
+	ppc_md.nvram_read_val	= pmac_nvram_read_byte;
+	ppc_md.nvram_write_val	= pmac_nvram_write_byte;
+#endif
 
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
 
diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
--- a/arch/ppc/platforms/pmac_smp.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc/platforms/pmac_smp.c	Thu May  9 15:21:07 2002
@@ -105,8 +105,140 @@
 #define PSURGE_QUAD_COTTON	2
 #define PSURGE_QUAD_ICEGRASS	3
 
-/* l2 cache stuff for dual G4 macs */
-extern void core99_init_l2(void);
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+static void __init
+core99_init_caches(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+		return;
+
+	if (cpu == 0){
+		core99_l2_cache = _get_L2CR();
+		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+	} else {
+		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+		_set_L2CR(0);
+		_set_L2CR(core99_l2_cache);
+		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+	}
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+		return;
+
+	if (cpu == 0){
+		core99_l3_cache = _get_L3CR();
+		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+	} else {
+		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+		_set_L3CR(0);
+		_set_L3CR(core99_l3_cache);
+		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+	}
+}
+
+/* Some CPU registers have to be saved from the first CPU and
+ * applied to others. Note that we override what is setup by
+ * the cputable intentionally.
+ */
+
+#define	reg_hid0	0
+#define	reg_hid1	1
+#define	reg_msscr0	2
+#define	reg_msssr0	3
+#define	reg_ictrl	4
+#define	reg_ldstcr	5
+#define	reg_ldstdb	6
+#define	reg_count	7
+
+static unsigned long cpu_regs[reg_count];
+
+static void __pmac
+cpu_setup_grab(void)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Read cache setting of CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
+		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
+		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
+		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
+		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
+		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
+	}
+	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
+}
+
+static void __pmac
+cpu_setup_apply(int cpu_nr)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Apply cache setting from CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID0)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
+			"isync;sync\n"
+//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
+//			"sync\n"
+//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
+//			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));			
+	}
+	/* 7410 only */
+	if (pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"li	%0, 0\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp));		
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID1)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));		
+	}
+}
 
 /*
  * Set and clear IPIs for powersurge.
@@ -383,6 +515,7 @@
 {
 	struct device_node *cpus;
 	int i, ncpus = 1;
+	extern int powersave_nap;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
 	cpus = find_type_devices("cpu");
@@ -394,6 +527,8 @@
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
 			smp_hw_index[i] = i;
+		powersave_nap = 0;
+		cpu_setup_grab();
 	}
 
 	return ncpus;
@@ -404,17 +539,11 @@
 {
 	unsigned long save_vector, new_vector;
 	unsigned long flags;
-#if 1 /* New way... */
+
 	volatile unsigned long *vector
 		 = ((volatile unsigned long *)(KERNELBASE+0x100));
 	if (nr < 1 || nr > 3)
 		return;
-#else
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x500));
-	if (nr != 1)
-		return;
-#endif
 	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
 	local_irq_save(flags);
@@ -463,13 +592,15 @@
 static void __init
 smp_core99_setup_cpu(int cpu_nr)
 {
+	/* Setup some registers */
+	if (cpu_nr != 0)
+		cpu_setup_apply(cpu_nr);
+	
 	/* Setup openpic */
 	do_openpic_setup_cpu();
 
-	/* Setup L2 */
-	if (cpu_nr != 0)
-		core99_init_l2();
-	else
+	/* Setup L2/L3 */
+	if (cpu_nr == 0)
 		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
 }
 
diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c	Thu May  9 15:21:09 2002
+++ b/arch/ppc/platforms/prep_pci.c	Thu May  9 15:21:09 2002
@@ -666,21 +666,21 @@
 #define	MOT_PROC2_BIT		0x800
 
 static u_char mvme2600_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_SIO */
+    (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_FALCN_ECC_ERR */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
 };
 
 #define MOT_RAVEN_PRESENT	0x1
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Thu May  9 15:21:09 2002
+++ b/arch/ppc/platforms/prep_setup.c	Thu May  9 15:21:09 2002
@@ -57,6 +57,7 @@
 #include <asm/keyboard.h>
 #include <asm/vga.h>
 #include <asm/time.h>
+#include <asm/mpc10x.h>
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
 
@@ -685,22 +686,16 @@
 	}
 }
 
-static int __prep
-prep_get_irq(struct pt_regs *regs)
-{
-	return i8259_irq();
-}		
-
 static void __init
 prep_init_IRQ(void)
 {
 	int i;
 
 	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
+		openpic_init(1, NUM_8259_INTERRUPTS, -1);
 	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+	i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR);
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -867,7 +862,7 @@
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
 	/* this gets changed later on if we have an OpenPIC -- Cort */
-	ppc_md.get_irq        = prep_get_irq;
+	ppc_md.get_irq        = i8259_irq;
 	ppc_md.init           = prep_init2;
 
 	ppc_md.restart        = prep_restart;
diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
--- a/arch/ppc/xmon/start.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/xmon/start.c	Thu May  9 15:21:01 2002
@@ -32,6 +32,7 @@
 extern void xmon_printf(const char *fmt, ...);
 static int xmon_expect(const char *str, unsigned int timeout);
 
+static int use_serial;
 static int use_screen;
 static int via_modem;
 static int xmon_use_sccb;
@@ -95,6 +96,7 @@
 }
 #endif /* CONFIG_ALL_PPC */
 
+#ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
 			      struct kbd_struct *kbd, struct tty_struct *tty)
 {
@@ -107,20 +109,20 @@
 	help_msg:	"Xmon",
 	action_msg:	"Entering xmon\n",
 };
+#endif
 
 void
 xmon_map_scc(void)
 {
 #ifdef CONFIG_ALL_PPC
 	volatile unsigned char *base;
-
-	use_screen = 0;
 	
 	if (_machine == _MACH_Pmac) {
 		struct device_node *np;
 		unsigned long addr;
 #ifdef CONFIG_BOOTX_TEXT
-		if (!machine_is_compatible("iMac")) {
+		if (!use_screen && !use_serial
+		    && !machine_is_compatible("iMac")) {
 			/* see if there is a keyboard in the device tree
 			   with a parent of type "adb" */
 			for (np = find_devices("keyboard"); np; np = np->next)
@@ -218,7 +220,9 @@
 	DLAB = 0x80;
 #endif /* platform */
 
+#ifdef CONFIG_MAGIC_SYSRQ
 	__sysrq_put_key_op('x', &sysrq_xmon_op);
+#endif
 }
 
 static int scc_initialized = 0;
diff -Nru a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
--- a/arch/ppc/xmon/xmon.c	Thu May  9 15:21:01 2002
+++ b/arch/ppc/xmon/xmon.c	Thu May  9 15:21:01 2002
@@ -15,6 +15,7 @@
 #include <asm/prom.h>
 #include <asm/bitops.h>
 #include <asm/bootx.h>
+#include <asm/machdep.h>
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -105,6 +106,7 @@
 #endif /* CONFIG_SMP */
 static int pretty_print_addr(unsigned long addr);
 static void csum(void);
+static void bootcmds(void);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
 extern void printf(const char *fmt, ...);
@@ -482,10 +484,26 @@
 			cpu_cmd();
 			break;
 #endif /* CONFIG_SMP */
+		case 'z':
+			bootcmds();
+			break;
 		}
 	}
 }
 
+static void bootcmds(void)
+{
+	int cmd;
+
+	cmd = inchar();
+	if (cmd == 'r')
+		ppc_md.restart(NULL);
+	else if (cmd == 'h')
+		ppc_md.halt();
+	else if (cmd == 'p')
+		ppc_md.power_off();
+}
+
 #ifdef CONFIG_SMP
 static void cpu_cmd(void)
 {
@@ -670,7 +688,7 @@
 					printf("r");
 				if (dabr.address & 2)
 					printf("w");
-				if (dabr.address & 4)
+				if (!(dabr.address & 4))
 					printf("p");
 				printf("]\n");
 			}
@@ -707,8 +725,7 @@
 	unsigned sp;
 	unsigned stack[2];
 	struct pt_regs regs;
-	extern char ret_from_intercept, ret_from_syscall_1, ret_from_syscall_2;
-	extern char ret_from_except;
+	extern char ret_from_except, ret_from_except_full, ret_from_syscall;
 
 	printf("backtrace:\n");
 	
@@ -723,10 +740,9 @@
 			break;
 		pretty_print_addr(stack[1]);
 		printf(" ");
-		if (stack[1] == (unsigned) &ret_from_intercept
-		    || stack[1] == (unsigned) &ret_from_except
-		    || stack[1] == (unsigned) &ret_from_syscall_1
-		    || stack[1] == (unsigned) &ret_from_syscall_2) {
+		if (stack[1] == (unsigned) &ret_from_except
+		    || stack[1] == (unsigned) &ret_from_except_full
+		    || stack[1] == (unsigned) &ret_from_syscall) {
 			if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
 				break;
 			printf("\nexception:%x [%x] %x ", regs.trap, sp+16,
@@ -751,6 +767,8 @@
 void
 excprint(struct pt_regs *fp)
 {
+	int trap;
+
 #ifdef CONFIG_SMP
 	printf("cpu %d: ", smp_processor_id());
 #endif /* CONFIG_SMP */
@@ -759,7 +777,8 @@
 	printf(", lr = ");
 	pretty_print_addr(fp->link);
 	printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
-	if (fp->trap == 0x300 || fp->trap == 0x600)
+	trap = TRAP(fp);
+	if (trap == 0x300 || trap == 0x600)
 		printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
 	if (current)
 		printf("current = %x, pid = %d, comm = %s\n",
@@ -774,9 +793,14 @@
 
 	if (scanhex(&base))
 		fp = (struct pt_regs *) base;
-	for (n = 0; n < 32; ++n)
+	for (n = 0; n < 32; ++n) {
 		printf("R%.2d = %.8x%s", n, fp->gpr[n],
 		       (n & 3) == 3? "\n": "   ");
+		if (n == 12 && !FULL_REGS(fp)) {
+			printf("\n");
+			break;
+		}
+	}
 	printf("pc  = %.8x   msr = %.8x   lr  = %.8x   cr  = %.8x\n",
 	       fp->nip, fp->msr, fp->link, fp->ccr);
 	printf("ctr = %.8x   xer = %.8x   trap = %4x\n",
@@ -1160,7 +1184,7 @@
 static void
 handle_fault(struct pt_regs *regs)
 {
-	fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+	fault_type = TRAP(regs) == 0x200? 0: TRAP(regs) == 0x300? 1: 2;
 	longjmp(bus_error_jmp, 1);
 }
 
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Thu May  9 15:21:10 2002
+++ b/arch/ppc64/kernel/ioctl32.c	Thu May  9 15:21:10 2002
@@ -1779,9 +1779,9 @@
 	
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or super-user.
+	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	if (current->tty == tty || suser())
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		return 1;
 	return 0;                                                    
 }
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Thu May  9 15:21:04 2002
+++ b/arch/ppc64/kernel/pci.c	Thu May  9 15:21:04 2002
@@ -180,7 +180,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	struct pci_dev *dev = data;
 
diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Thu May  9 15:21:07 2002
+++ b/arch/ppc64/kernel/setup.c	Thu May  9 15:21:07 2002
@@ -543,95 +543,6 @@
 	ppc_md.progress("setup_arch: exit", 0x3eab);
 }
 
-#ifdef CONFIG_IDE
-
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc64_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	for (i = 0; i < 32; i++)
-		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	for (i = 0; i < 96; i++)
-		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
-}
-#endif
-
-
 void exception_trace(unsigned long trap)
 {
 	unsigned long x, srr0, srr1, reg20, reg1, reg21;
diff -Nru a/arch/sh/kernel/pci_st40.c b/arch/sh/kernel/pci_st40.c
--- a/arch/sh/kernel/pci_st40.c	Thu May  9 15:21:09 2002
+++ b/arch/sh/kernel/pci_st40.c	Thu May  9 15:21:09 2002
@@ -414,10 +414,6 @@
 pcibios_fixup_pbus_ranges(struct pci_bus *bus,
 			  struct pbus_set_ranges_data *ranges)
 {
-	ranges->io_start -= bus->resource[0]->start;
-	ranges->io_end -= bus->resource[0]->start;
-	ranges->mem_start -= bus->resource[1]->start;
-	ranges->mem_end -= bus->resource[1]->start;
 }
 
 void __init pcibios_init(void)
diff -Nru a/arch/sh/kernel/pcibios.c b/arch/sh/kernel/pcibios.c
--- a/arch/sh/kernel/pcibios.c	Thu May  9 15:21:05 2002
+++ b/arch/sh/kernel/pcibios.c	Thu May  9 15:21:05 2002
@@ -60,7 +60,8 @@
  * addresses to be allocated in the 0x000-0x0ff region
  * modulo 0x400.
  */
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
--- a/arch/sparc/kernel/pcic.c	Thu May  9 15:21:01 2002
+++ b/arch/sparc/kernel/pcic.c	Thu May  9 15:21:01 2002
@@ -865,7 +865,8 @@
 {
 }
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c	Thu May  9 15:21:06 2002
+++ b/arch/sparc/kernel/sys_sunos.c	Thu May  9 15:21:06 2002
@@ -192,8 +192,7 @@
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
 	 */
-	freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
-	freepages += get_page_cache_size();
+	freepages = get_page_cache_size();
 	freepages >>= 1;
 	freepages += nr_free_pages();
 	freepages += nr_swap_pages;
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Thu May  9 15:21:03 2002
+++ b/arch/sparc/mm/sun4c.c	Thu May  9 15:21:03 2002
@@ -1906,19 +1906,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)
 {
@@ -2097,6 +2084,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);
@@ -2512,6 +2513,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);
@@ -2572,5 +2574,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 -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Thu May  9 15:21:05 2002
+++ b/arch/sparc64/defconfig	Thu May  9 15:21:05 2002
@@ -204,6 +204,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
@@ -276,19 +281,20 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 
 #
-# IDE chipset support
+# ATA host chipset support
 #
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_IDE_TCQ is not set
+# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
@@ -312,6 +318,7 @@
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -415,8 +422,11 @@
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 CONFIG_IEEE1394_SBP2=m
+CONFIG_IEEE1394_ETH1394=m
 CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
 #
@@ -428,14 +438,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
@@ -684,6 +686,7 @@
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
@@ -730,6 +733,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ISO8859_1 is not set
 # CONFIG_NLS_ISO8859_2 is not set
@@ -771,8 +775,9 @@
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_LONG_TIMEOUT is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
 
 #
 # USB Host Controller Drivers
@@ -787,8 +792,9 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
-# CONFIG_USB_EMI26 is not set
-CONFIG_USB_BLUETOOTH=m
+CONFIG_USB_BLUETOOTH_TTY=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -798,20 +804,18 @@
 CONFIG_USB_STORAGE_HP8200e=y
 CONFIG_USB_STORAGE_SDDR09=y
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
 
 #
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
 CONFIG_USB_WACOM=m
 
 #
 # USB Imaging devices
 #
-CONFIG_USB_DC2XX=m
 CONFIG_USB_MDC800=m
 CONFIG_USB_SCANNER=m
 CONFIG_USB_MICROTEK=m
@@ -820,23 +824,24 @@
 #
 # USB Multimedia devices
 #
+CONFIG_USB_DABUSB=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
 CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
 CONFIG_USB_OV511=m
 CONFIG_USB_PWC=m
 CONFIG_USB_SE401=m
 CONFIG_USB_STV680=m
-CONFIG_USB_VICAM=m
-CONFIG_USB_DSBR=m
-CONFIG_USB_DABUSB=m
-CONFIG_USB_KONICAWC=m
 
 #
 # USB Network adaptors
 #
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_KAWETH=m
 CONFIG_USB_CATC=m
 CONFIG_USB_CDCETHER=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
 CONFIG_USB_USBNET=m
 
 #
@@ -867,10 +872,14 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
 CONFIG_USB_SERIAL_OMNINET=m
@@ -878,20 +887,29 @@
 #
 # USB Miscellaneous drivers
 #
-CONFIG_USB_RIO500=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
 CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+# CONFIG_USB_BRLVGER is not set
 
 #
 # Bluetooth support
 #
 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_HCIBLUECARD is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
--- a/arch/sparc64/kernel/Makefile	Thu May  9 15:21:03 2002
+++ b/arch/sparc64/kernel/Makefile	Thu May  9 15:21:03 2002
@@ -1,19 +1,11 @@
 # $Id: Makefile,v 1.70 2002/02/09 19:49:30 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 -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Thu May  9 15:21:05 2002
+++ b/arch/sparc64/kernel/ioctl32.c	Thu May  9 15:21:05 2002
@@ -2059,9 +2059,9 @@
 	
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or super-user.
+	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	if (current->tty == tty || suser())
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		return 1;
 	return 0;                                                    
 }
@@ -4553,12 +4553,20 @@
 COMPATIBLE_IOCTL(HCIDEVUP)
 COMPATIBLE_IOCTL(HCIDEVDOWN)
 COMPATIBLE_IOCTL(HCIDEVRESET)
-COMPATIBLE_IOCTL(HCIRESETSTAT)
-COMPATIBLE_IOCTL(HCIGETINFO)
+COMPATIBLE_IOCTL(HCIDEVRESTAT)
 COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
 COMPATIBLE_IOCTL(HCISETRAW)
 COMPATIBLE_IOCTL(HCISETSCAN)
 COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
 COMPATIBLE_IOCTL(HCIINQUIRY)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Thu May  9 15:21:00 2002
+++ b/arch/sparc64/kernel/pci.c	Thu May  9 15:21:00 2002
@@ -181,7 +181,7 @@
 extern void clock_probe(void);
 extern void power_init(void);
 
-void __init pcibios_init(void)
+static void __init pcibios_init(void)
 {
 	pci_controller_probe();
 	if (pci_controller_root == NULL)
@@ -199,6 +199,8 @@
 	power_init();
 }
 
+subsys_initcall(pcibios_init);
+
 struct pci_fixup pcibios_fixups[] = {
 	{ 0 }
 };
@@ -311,7 +313,8 @@
 {
 }
 
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
 {
 }
 
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Thu May  9 15:21:05 2002
+++ b/arch/sparc64/kernel/setup.c	Thu May  9 15:21:05 2002
@@ -465,8 +465,6 @@
 char saved_command_line[256];
 char reboot_command[256];
 
-extern unsigned long phys_base;
-
 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
 void register_prom_callbacks(void)
@@ -535,6 +533,7 @@
 		if (highest_paddr < top)
 			highest_paddr = top;
 	}
+	pfn_base = phys_base >> PAGE_SHIFT;
 
 	if (!root_flags)
 		root_mountflags &= ~MS_RDONLY;
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Thu May  9 15:21:08 2002
+++ b/arch/sparc64/kernel/signal.c	Thu May  9 15:21:08 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 -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Thu May  9 15:21:01 2002
+++ b/arch/sparc64/kernel/signal32.c	Thu May  9 15:21:01 2002
@@ -396,6 +396,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;
@@ -453,7 +454,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);
@@ -1031,6 +1035,7 @@
 asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
 {
 	svr4_gregset_t  *gr;
+	mm_segment_t old_fs;
 	u32 pc, npc, psr;
 	sigset_t set;
 	svr4_sigset_t setv;
@@ -1086,7 +1091,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 -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Thu May  9 15:21:04 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Thu May  9 15:21:04 2002
@@ -116,6 +116,7 @@
 #endif
 
 extern unsigned long phys_base;
+extern unsigned long pfn_base;
 
 /* used by various drivers */
 #ifdef CONFIG_SMP
@@ -353,6 +354,7 @@
 
 /* Various address conversion macros use this. */
 EXPORT_SYMBOL(phys_base);
+EXPORT_SYMBOL(pfn_base);
 EXPORT_SYMBOL(sparc64_valid_addr_bitmap);
 
 /* No version information on this, heavily used in inline asm,
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Thu May  9 15:21:08 2002
+++ b/arch/sparc64/kernel/sys_sunos32.c	Thu May  9 15:21:08 2002
@@ -156,8 +156,7 @@
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
 	 */
-	freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
-	freepages += get_page_cache_size();
+	freepages = get_page_cache_size();
 	freepages >>= 1;
 	freepages += nr_free_pages();
 	freepages += nr_swap_pages;
diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
--- a/arch/sparc64/lib/Makefile	Thu May  9 15:21:02 2002
+++ b/arch/sparc64/lib/Makefile	Thu May  9 15:21:02 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 -Nru a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
--- a/arch/sparc64/mm/Makefile	Thu May  9 15:21:09 2002
+++ b/arch/sparc64/mm/Makefile	Thu May  9 15:21:09 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 -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Thu May  9 15:21:05 2002
+++ b/arch/sparc64/mm/init.c	Thu May  9 15:21:05 2002
@@ -45,6 +45,7 @@
 
 /* Ugly, but necessary... -DaveM */
 unsigned long phys_base;
+unsigned long pfn_base;
 
 enum ultra_tlb_layout tlb_type = spitfire;
 
@@ -1341,7 +1342,7 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
-	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn);
+	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base, end_pfn);
 
 	/* Now register the available physical memory with the
 	 * allocator.
@@ -1529,7 +1530,7 @@
 		for (znum = 0; znum < MAX_NR_ZONES; znum++)
 			zones_size[znum] = zholes_size[znum] = 0;
 
-		npages = end_pfn - (phys_base >> PAGE_SHIFT);
+		npages = end_pfn - pfn_base;
 		zones_size[ZONE_DMA] = npages;
 		zholes_size[ZONE_DMA] = npages - pages_avail;
 
@@ -1700,10 +1701,10 @@
 
 	taint_real_pages();
 
-	max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT);
+	max_mapnr = last_valid_pfn - pfn_base;
 	high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
-	num_physpages = free_all_bootmem() - 1;
+	totalram_pages = num_physpages = free_all_bootmem() - 1;
 
 	/*
 	 * Set up the zero page, mark it reserved, so that page count
@@ -1736,6 +1737,7 @@
 		addr += alias_base;
 		free_pgd_fast((pgd_t *)addr);
 		num_physpages++;
+		totalram_pages++;
 	}
 #endif
 
@@ -1772,6 +1774,7 @@
 		set_page_count(p, 1);
 		__free_page(p);
 		num_physpages++;
+		totalram_pages++;
 	}
 }
 
@@ -1787,6 +1790,7 @@
 		set_page_count(p, 1);
 		__free_page(p);
 		num_physpages++;
+		totalram_pages++;
 	}
 }
 #endif
diff -Nru a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
--- a/arch/sparc64/prom/Makefile	Thu May  9 15:21:04 2002
+++ b/arch/sparc64/prom/Makefile	Thu May  9 15:21:04 2002
@@ -2,21 +2,13 @@
 # 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
 
diff -Nru a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
--- a/arch/sparc64/solaris/Makefile	Thu May  9 15:21:01 2002
+++ b/arch/sparc64/solaris/Makefile	Thu May  9 15:21:01 2002
@@ -2,15 +2,12 @@
 # Makefile for the Solaris binary emulation.
 #
 
+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
 
 solaris-objs := entry64.o fs.o misc.o signal.o systbl.o socket.o \
 		ioctl.o ipc.o socksys.o timod.o
diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig	Thu May  9 15:21:08 2002
+++ b/arch/x86_64/defconfig	Thu May  9 15:21:08 2002
@@ -205,7 +205,6 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
--- a/arch/x86_64/ia32/ia32_ioctl.c	Thu May  9 15:21:00 2002
+++ b/arch/x86_64/ia32/ia32_ioctl.c	Thu May  9 15:21:00 2002
@@ -1648,9 +1648,9 @@
 	
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or super-user.
+	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	if (current->tty == tty || suser())
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		return 1;
 	return 0;                                                    
 }
diff -Nru a/arch/x86_64/kernel/mtrr.c b/arch/x86_64/kernel/mtrr.c
--- a/arch/x86_64/kernel/mtrr.c	Thu May  9 15:21:05 2002
+++ b/arch/x86_64/kernel/mtrr.c	Thu May  9 15:21:05 2002
@@ -983,7 +983,7 @@
     char *ptr;
     char line[LINE_SIZE];
 
-	if (!suser ())
+	if (!capable (CAP_SYS_ADMIN))
 		return -EPERM;
 
     /*  Can't seek (pwrite) on this device  */
@@ -1071,7 +1071,7 @@
 	return -ENOIOCTLCMD;
 
       case MTRRIOC_ADD_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1083,7 +1083,7 @@
 	break;
 
       case MTRRIOC_SET_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1093,7 +1093,7 @@
 	break;
 
       case MTRRIOC_DEL_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1103,7 +1103,7 @@
 	break;
 
       case MTRRIOC_KILL_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1134,7 +1134,7 @@
 	break;
 
       case MTRRIOC_ADD_PAGE_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1146,7 +1146,7 @@
 	break;
 
       case MTRRIOC_SET_PAGE_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1156,7 +1156,7 @@
 	break;
 
       case MTRRIOC_DEL_PAGE_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
@@ -1166,7 +1166,7 @@
 	break;
 
       case MTRRIOC_KILL_PAGE_ENTRY:
-		if (!suser ())
+		if (!capable (CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
diff -Nru a/arch/x86_64/kernel/pci-x86_64.c b/arch/x86_64/kernel/pci-x86_64.c
--- a/arch/x86_64/kernel/pci-x86_64.c	Thu May  9 15:21:09 2002
+++ b/arch/x86_64/kernel/pci-x86_64.c	Thu May  9 15:21:09 2002
@@ -136,7 +136,8 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+pcibios_align_resource(void *data, struct resource *res,
+		       unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
diff -Nru a/arch/x86_64/lib/mmx.c b/arch/x86_64/lib/mmx.c
--- a/arch/x86_64/lib/mmx.c	Thu May  9 15:21:10 2002
+++ b/arch/x86_64/lib/mmx.c	Thu May  9 15:21:10 2002
@@ -62,11 +62,34 @@
 		"\n"
 		: : "r" (from) );
 		
-	
-	for(; i>0; i--)
+	for(; i>5; i--)
 	{
 		__asm__ __volatile__ (
 		"  prefetch 320(%0)\n"
+		"  movq (%0), %%mm0\n"
+		"  movq 8(%0), %%mm1\n"
+		"  movq 16(%0), %%mm2\n"
+		"  movq 24(%0), %%mm3\n"
+		"  movq %%mm0, (%1)\n"
+		"  movq %%mm1, 8(%1)\n"
+		"  movq %%mm2, 16(%1)\n"
+		"  movq %%mm3, 24(%1)\n"
+		"  movq 32(%0), %%mm0\n"
+		"  movq 40(%0), %%mm1\n"
+		"  movq 48(%0), %%mm2\n"
+		"  movq 56(%0), %%mm3\n"
+		"  movq %%mm0, 32(%1)\n"
+		"  movq %%mm1, 40(%1)\n"
+		"  movq %%mm2, 48(%1)\n"
+		"  movq %%mm3, 56(%1)\n"
+		: : "r" (from), "r" (to) : "memory");
+		from+=64;
+		to+=64;
+	}
+
+	for(; i>0; i--)
+	{
+		__asm__ __volatile__ (
 		"  movq (%0), %%mm0\n"
 		"  movq 8(%0), %%mm1\n"
 		"  movq 16(%0), %%mm2\n"
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Thu May  9 15:21:04 2002
+++ b/drivers/Makefile	Thu May  9 15:21:04 2002
@@ -7,8 +7,8 @@
 
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
-		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
-		fc4 net/hamradio i2c acpi bluetooth input/serio \
+		message scsi md ieee1394 pnp isdn atm \
+		fc4 i2c acpi bluetooth input/serio \
 		input/gameport parport hotplug
 
 subdir-y :=	base char block net misc media cdrom
@@ -35,17 +35,14 @@
 subdir-$(CONFIG_SGI)		+= sgi
 subdir-$(CONFIG_IDE)		+= ide
 subdir-$(CONFIG_SCSI)		+= scsi
-subdir-$(CONFIG_I2O)		+= message/i2o
-subdir-$(CONFIG_FUSION)		+= message/fusion
+subdir-$(CONFIG_I2O)		+= message
+subdir-$(CONFIG_FUSION)		+= message
 subdir-$(CONFIG_MD)		+= md
 subdir-$(CONFIG_IEEE1394)	+= ieee1394
 subdir-$(CONFIG_PNP)		+= pnp
 subdir-$(CONFIG_ISDN)		+= isdn
 subdir-$(CONFIG_ATM)		+= atm
 subdir-$(CONFIG_FC4)		+= fc4
-
-# CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set  -- ch
-subdir-$(CONFIG_HAMRADIO)	+= net/hamradio
 subdir-$(CONFIG_I2C)		+= i2c
 subdir-$(CONFIG_ACPI)		+= acpi
 
diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
--- a/drivers/acorn/block/mfmhd.c	Thu May  9 15:21:03 2002
+++ b/drivers/acorn/block/mfmhd.c	Thu May  9 15:21:03 2002
@@ -1346,9 +1346,6 @@
  */
 static int mfm_probecontroller (unsigned int mfm_addr)
 {
-	if (check_region (mfm_addr, 10))
-		return 0;
-
 	if (inw (MFM_STATUS) & STAT_BSY) {
 		outw (CMD_ABT, MFM_COMMAND);
 		udelay (50);
@@ -1406,14 +1403,18 @@
 		ecard_claim(ecs);
 	}
 
+	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
+	if (!request_region (mfm_addr, 10, "mfm")) {
+		ecard_release(ecs);
+		return -1;
+	}
+
 	if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
 		printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
 		ecard_release(ecs);
+		release_region(mfm_addr, 10);
 		return -1;
 	}
-
-	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
-	request_region (mfm_addr, 10, "mfm");
 
 	/* Stuff for the assembler routines to get to */
 	hdc63463_baseaddress	= ioaddr(mfm_addr);
diff -Nru a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
--- a/drivers/acorn/scsi/arxescsi.c	Thu May  9 15:21:00 2002
+++ b/drivers/acorn/scsi/arxescsi.c	Thu May  9 15:21:00 2002
@@ -304,8 +304,18 @@
 		ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port);
 		ecs[count]->irqmask = CSTATUS_IRQ;
 
-		request_region(host->io_port      , 120, "arxescsi-fas");
-		request_region(host->io_port + 128, 384, "arxescsi-dma");
+		if (!request_region(host->io_port, 120, "arxescsi-fas")) {
+			ecard_release(ecs[count]);
+			scsi_unregister(host);
+			break;
+		}
+			
+		if (!request_region(host->io_port + 128, 384, "arxescsi-dma")) {
+			ecard_release(ecs[count]);
+			release_region(host->io_port, 120);
+			scsi_unregister(host);
+			break;
+		}
 
 		printk("scsi%d: Has no interrupts - using polling mode\n",
 		       host->host_no);
diff -Nru a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
--- a/drivers/acorn/scsi/cumana_2.c	Thu May  9 15:21:09 2002
+++ b/drivers/acorn/scsi/cumana_2.c	Thu May  9 15:21:09 2002
@@ -382,8 +382,13 @@
 		ecs[count]->irq_data	= (void *)info->alatch;
 		ecs[count]->ops		= (expansioncard_ops_t *)&cumanascsi_2_ops;
 
-		request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET,
-			       16 << CUMANASCSI2_FAS216_SHIFT, "cumanascsi2-fas");
+		if (!request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET,
+			       16 << CUMANASCSI2_FAS216_SHIFT, "cumanascsi2-fas")) {
+			scsi_unregister(host);
+			ecard_release(ecs[count]);
+			break;
+		}
+			
 
 		if (host->irq != NO_IRQ &&
 		    request_irq(host->irq, cumanascsi_2_intr,
diff -Nru a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c
--- a/drivers/acorn/scsi/oak.c	Thu May  9 15:21:00 2002
+++ b/drivers/acorn/scsi/oak.c	Thu May  9 15:21:00 2002
@@ -134,7 +134,8 @@
 	ecard_claim(ecs[count]);
 
 	instance->n_io_port = 255;
-	request_region (instance->io_port, instance->n_io_port, "Oak SCSI");
+	if (!request_region (instance->io_port, instance->n_io_port, "Oak SCSI"))
+		break;
 
 	if (instance->irq != IRQ_NONE)
 	    if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
diff -Nru a/drivers/acpi/acpi_osl.c b/drivers/acpi/acpi_osl.c
--- a/drivers/acpi/acpi_osl.c	Thu May  9 15:21:09 2002
+++ b/drivers/acpi/acpi_osl.c	Thu May  9 15:21:09 2002
@@ -77,12 +77,13 @@
 	 * Initialize PCI configuration space access, as we'll need to access
 	 * it while walking the namespace (bus 0 and root bridges w/ _BBNs).
 	 */
+#if 0
 	pcibios_config_init();
 	if (!pci_config_read || !pci_config_write) {
 		printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n");
 		return AE_NULL_ENTRY;
 	}
-
+#endif
 	return AE_OK;
 }
 
diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c
--- a/drivers/block/amiflop.c	Thu May  9 15:21:07 2002
+++ b/drivers/block/amiflop.c	Thu May  9 15:21:07 2002
@@ -206,7 +206,7 @@
 
 /* Prevent "aliased" accesses. */
 static int fd_ref[4] = { 0,0,0,0 };
-static int fd_device[4] = { 0,0,0,0 };
+static kdev_t fd_device[4] = { NODEV, NODEV, NODEV, NODEV };
 
 /*
  * Current device number. Taken either from the block header or from the
@@ -1393,13 +1393,10 @@
 		return;
 	}
 
-	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+	if (major(CURRENT->rq_dev) != MAJOR_NR)
 		panic(DEVICE_NAME ": request list destroyed");
 
-	if (CURRENT->bh && !buffer_locked(CURRENT->bh))
-		panic(DEVICE_NAME ": block not locked");
-
-	device = MINOR(CURRENT_DEVICE);
+	device = minor(CURRENT_DEVICE);
 	if (device < 8) {
 		/* manual selection */
 		drive = device & 3;
@@ -1435,7 +1432,7 @@
 		       "0x%08lx\n", track, sector, data);
 #endif
 
-		if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
+		if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) {
 			printk(KERN_WARNING "do_fd_request: unknown command\n");
 			end_request(0);
 			goto repeat;
@@ -1445,7 +1442,7 @@
 			goto repeat;
 		}
 
-		switch (CURRENT->cmd) {
+		switch (rq_data_dir(CURRENT)) {
 		case READ:
 			memcpy(data, unit[drive].trackbuf + sector * 512, 512);
 			break;
@@ -1490,9 +1487,8 @@
 static int fd_ioctl(struct inode *inode, struct file *filp,
 		    unsigned int cmd, unsigned long param)
 {
-	int drive = inode->i_rdev & 3;
+	int drive = minor(inode->i_rdev) & 3;
 	static struct floppy_struct getprm;
-	struct super_block * sb;
 
 	switch(cmd){
 	case HDIO_GETGEO:
@@ -1622,15 +1618,15 @@
 static int floppy_open(struct inode *inode, struct file *filp)
 {
 	int drive;
-	int old_dev;
+	kdev_t old_dev;
 	int system;
 	unsigned long flags;
 
-	drive = MINOR(inode->i_rdev) & 3;
+	drive = minor(inode->i_rdev) & 3;
 	old_dev = fd_device[drive];
 
 	if (fd_ref[drive])
-		if (old_dev != inode->i_rdev)
+		if (!kdev_same(old_dev, inode->i_rdev))
 			return -EBUSY;
 
 	if (unit[drive].type->code == FD_NODRIVE)
@@ -1662,14 +1658,14 @@
 #endif
 	restore_flags(flags);
 
-	if (old_dev && old_dev != inode->i_rdev)
+	if (!kdev_same(old_dev, NODEV) && !kdev_same(old_dev, inode->i_rdev))
 		invalidate_buffers(old_dev);
 
-	system=(inode->i_rdev & 4)>>2;
+	system=(minor(inode->i_rdev) & 4)>>2;
 	unit[drive].dtype=&data_types[system];
 	unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
 		data_types[system].sects*unit[drive].type->sect_mult;
-	floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1;
+	floppy_sizes[minor(inode->i_rdev)] = unit[drive].blocks >> 1;
 
 	printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
 	       unit[drive].type->name, data_types[system].name);
@@ -1679,10 +1675,7 @@
 
 static int floppy_release(struct inode * inode, struct file * filp)
 {
-#ifdef DEBUG
-	struct super_block * sb;
-#endif
-	int drive = MINOR(inode->i_rdev) & 3;
+	int drive = minor(inode->i_rdev) & 3;
 
 	if (unit[drive].dirty == 1) {
 		del_timer (flush_track_timer + drive);
@@ -1708,11 +1701,11 @@
  */
 static int amiga_floppy_change(kdev_t dev)
 {
-	int drive = MINOR(dev) & 3;
+	int drive = minor(dev) & 3;
 	int changed;
 	static int first_time = 1;
 
-	if (MAJOR(dev) != MAJOR_NR) {
+	if (major(dev) != MAJOR_NR) {
 		printk(KERN_CRIT "floppy_change: not a floppy\n");
 		return 0;
 	}
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Thu May  9 15:21:09 2002
+++ b/drivers/block/cciss.c	Thu May  9 15:21:09 2002
@@ -436,25 +436,7 @@
                         return  -EFAULT;
                 return(0);
 	}
-	case HDIO_GETGEO_BIG:
-        {
-		struct hd_big_geometry driver_geo;
-                if (hba[ctlr]->drv[dsk].cylinders) {
-                        driver_geo.heads = hba[ctlr]->drv[dsk].heads;
-                        driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
-                        driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
-                } else {
-                        driver_geo.heads = 0xff;
-                        driver_geo.sectors = 0x3f;
-                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
-              	}
-	      	driver_geo.start= 
-			hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
-		if (copy_to_user((void *) arg, &driver_geo,  
-				sizeof( struct hd_big_geometry)))
-                        return  -EFAULT;
-                return(0);
-        }
+
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case BLKGETSIZE:
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Thu May  9 15:21:02 2002
+++ b/drivers/block/cpqarray.c	Thu May  9 15:21:02 2002
@@ -769,7 +769,7 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
+	if (!capable(CAP_SYS_RAWIO) && ida_sizes[(ctlr << CTLR_SHIFT) +
 						minor(inode->i_rdev)] == 0)
 		return -ENXIO;
 
@@ -779,7 +779,7 @@
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
-	if (suser()
+	if (capable(CAP_SYS_ADMIN)
 		&& ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0 
 		&& minor(inode->i_rdev) != 0)
 		return -ENXIO;
@@ -1121,7 +1121,7 @@
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
-		if (!suser()) return -EPERM;
+		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
 		error = copy_from_user(&my_io, io, sizeof(my_io));
 		if (error) return error;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Thu May  9 15:21:03 2002
+++ b/drivers/block/floppy.c	Thu May  9 15:21:03 2002
@@ -129,6 +129,12 @@
  * floppy controller (lingering task on list after module is gone... boom.)
  */
 
+/*
+ * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
+ * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
+ * requires many non-obvious changes in arch dependent code.
+ */
+
 #define FLOPPY_SANITY_CHECK
 #undef  FLOPPY_SILENT_DCL_CLEAR
 
@@ -4248,7 +4254,7 @@
 		FDCS->rawcmd = 2;
 		if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){
  			/* free ioports reserved by floppy_grab_irq_and_dma() */
- 			release_region(FDCS->address, 6);
+ 			release_region(FDCS->address+2, 4);
  			release_region(FDCS->address+7, 1);
 			FDCS->address = -1;
 			FDCS->version = FDC_NONE;
@@ -4258,7 +4264,7 @@
 		FDCS->version = get_fdc_version();
 		if (FDCS->version == FDC_NONE){
  			/* free ioports reserved by floppy_grab_irq_and_dma() */
- 			release_region(FDCS->address, 6);
+ 			release_region(FDCS->address+2, 4);
  			release_region(FDCS->address+7, 1);
 			FDCS->address = -1;
 			continue;
@@ -4337,11 +4343,11 @@
 
 	for (fdc=0; fdc< N_FDC; fdc++){
 		if (FDCS->address != -1){
-			if (!request_region(FDCS->address, 6, "floppy")) {
-				DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address);
+			if (!request_region(FDCS->address+2, 4, "floppy")) {
+				DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 2);
 				goto cleanup1;
 			}
-			if (!request_region(FDCS->address + 7, 1, "floppy DIR")) {
+			if (!request_region(FDCS->address+7, 1, "floppy DIR")) {
 				DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 7);
 				goto cleanup2;
 			}
@@ -4369,12 +4375,12 @@
 	irqdma_allocated = 1;
 	return 0;
 cleanup2:
-	release_region(FDCS->address, 6);
+	release_region(FDCS->address + 2, 4);
 cleanup1:
 	fd_free_irq();
 	fd_free_dma();
 	while(--fdc >= 0) {
-		release_region(FDCS->address, 6);
+		release_region(FDCS->address + 2, 4);
 		release_region(FDCS->address + 7, 1);
 	}
 	MOD_DEC_USE_COUNT;
@@ -4441,7 +4447,7 @@
 	old_fdc = fdc;
 	for (fdc = 0; fdc < N_FDC; fdc++)
 		if (FDCS->address != -1) {
-			release_region(FDCS->address, 6);
+			release_region(FDCS->address+2, 4);
 			release_region(FDCS->address+7, 1);
 		}
 	fdc = old_fdc;
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Thu May  9 15:21:07 2002
+++ b/drivers/block/genhd.c	Thu May  9 15:21:07 2002
@@ -199,7 +199,7 @@
 
 
 extern int blk_dev_init(void);
-#ifdef CONFIG_FUSION_BOOT
+#ifdef CONFIG_FUSION
 extern int fusion_init(void);
 #endif
 extern int net_dev_init(void);
@@ -216,7 +216,7 @@
 #ifdef CONFIG_I2O
 	i2o_init();
 #endif
-#ifdef CONFIG_FUSION_BOOT
+#ifdef CONFIG_FUSION
 	fusion_init();
 #endif
 #ifdef CONFIG_FC4_SOC
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Thu May  9 15:21:02 2002
+++ b/drivers/block/ll_rw_blk.c	Thu May  9 15:21:02 2002
@@ -358,8 +358,8 @@
 	if (!tags->tag_map)
 		goto fail_map;
 
-	memset(tags->tag_index, depth * sizeof(struct request *), 0);
-	memset(tags->tag_map, bits * sizeof(unsigned long), 0);
+	memset(tags->tag_index, 0, depth * sizeof(struct request *));
+	memset(tags->tag_map, 0, bits * sizeof(unsigned long));
 	INIT_LIST_HEAD(&tags->busy_list);
 	tags->busy = 0;
 	tags->max_depth = depth;
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Thu May  9 15:21:00 2002
+++ b/drivers/block/ps2esdi.c	Thu May  9 15:21:00 2002
@@ -364,6 +364,11 @@
 	else
 		io_base = PRIMARY_IO_BASE;
 
+	if (!request_region(io_base, 4, "ed")) {
+		printk(KERN_WARNING"Unable to request region 0x%x\n", io_base);
+		free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);
+		return;
+	}
 	/* get the dma arbitration level */
 	dma_arb_level = (status >> 2) & 0xf;
 
@@ -413,7 +418,7 @@
 	ps2esdi_gendisk.nr_real = ps2esdi_drives;
 
 	request_dma(dma_arb_level, "ed");
-	request_region(io_base, 4, "ed");
+
 	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
 
 	for (i = 0; i < ps2esdi_drives; i++) {
diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c
--- a/drivers/block/swim3.c	Thu May  9 15:21:05 2002
+++ b/drivers/block/swim3.c	Thu May  9 15:21:05 2002
@@ -820,7 +820,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 		
-	if ((cmd & 0x80) && !suser())
+	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	fs = &floppy_states[devnum];
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Thu May  9 15:21:01 2002
+++ b/drivers/block/swim_iop.c	Thu May  9 15:21:01 2002
@@ -348,7 +348,7 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 		
-	if ((cmd & 0x80) && !suser())
+	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	fs = &floppy_states[devnum];
diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c
--- a/drivers/block/z2ram.c	Thu May  9 15:21:08 2002
+++ b/drivers/block/z2ram.c	Thu May  9 15:21:08 2002
@@ -38,7 +38,7 @@
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
 #include <asm/pgtable.h>
-#include <asm/io.h>
+
 #include <linux/zorro.h>
 
 
@@ -83,16 +83,16 @@
 
 	if ( ( start + len ) > z2ram_size )
 	{
-	    printk( KERN_ERR DEVICE_NAME ": bad access: block=%ld, count=%ld\n",
+	    printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
 		CURRENT->sector,
 		CURRENT->current_nr_sectors);
 	    end_request( FALSE );
 	    continue;
 	}
 
-	if ( ( CURRENT->cmd != READ ) && ( CURRENT->cmd != WRITE ) )
+	if ( ( rq_data_dir(CURRENT) != READ ) && ( rq_data_dir(CURRENT) != WRITE ) )
 	{
-	    printk( KERN_ERR DEVICE_NAME ": bad command: %d\n", CURRENT->cmd );
+	    printk( KERN_ERR DEVICE_NAME ": bad command: %ld\n", rq_data_dir(CURRENT) );
 	    end_request( FALSE );
 	    continue;
 	}
@@ -106,7 +106,7 @@
 
 	    addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
 
-	    if ( CURRENT->cmd == READ )
+	    if ( rq_data_dir(CURRENT) == READ )
 		memcpy( CURRENT->buffer, (char *)addr, size );
 	    else
 		memcpy( (char *)addr, CURRENT->buffer, size );
@@ -208,7 +208,7 @@
 						   _PAGE_WRITETHRU);
 
 #else
-		vaddr = (unsigned long)ioremap(paddr, size);
+		vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size);
 #endif
 		z2ram_map = 
 			kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]),
@@ -364,7 +364,7 @@
 	    }
     }    
    
-    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUES, &z2ram_lock);
+    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_z2_request, &z2ram_lock);
     blk_size[ MAJOR_NR ] = z2_sizes;
 
     return 0;
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Thu May  9 15:21:02 2002
+++ b/drivers/cdrom/cdu31a.c	Thu May  9 15:21:02 2002
@@ -3370,7 +3370,8 @@
 	if (drive_found) {
 		int deficiency = 0;
 
-		request_region(cdu31a_port, 4, "cdu31a");
+		if (!request_region(cdu31a_port, 4, "cdu31a"))
+			goto errout3;
 
 		if (devfs_register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) {
 			printk("Unable to get major %d for CDU-31a\n",
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Thu May  9 15:21:03 2002
+++ b/drivers/char/Config.in	Thu May  9 15:21:03 2002
@@ -209,13 +209,16 @@
 
 dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
 if [ "$CONFIG_AGP" != "n" ]; then
-   bool '  Intel 440LX/BX/GX and I815/I820/I830M/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
+   bool '  Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
    bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
    bool '  VIA chipset support' CONFIG_AGP_VIA
    bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   if [ "$CONFIG_IA64" = "y" ]; then
+     bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
+   fi
 fi
 
 source drivers/char/drm/Config.in
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Thu May  9 15:21:06 2002
+++ b/drivers/char/Makefile	Thu May  9 15:21:06 2002
@@ -150,7 +150,13 @@
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
 obj-$(CONFIG_SX) += sx.o generic_serial.o
-obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
+
+obj-$(CONFIG_RIO) += generic_serial.o
+subdir-$(CONFIG_RIO) += rio
+ifeq ($(CONFIG_RIO),y)
+  obj-y += rio/rio.o
+endif
+
 obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
 obj-$(CONFIG_SERIAL167) += serial167.o
 obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
@@ -158,8 +164,6 @@
 obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 
-subdir-$(CONFIG_RIO) += rio
-
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
@@ -188,12 +192,8 @@
 obj-$(CONFIG_QIC02_TAPE) += tpqic02.o
 
 subdir-$(CONFIG_FTAPE) += ftape
-subdir-$(CONFIG_DRM) += drm
-subdir-$(CONFIG_PCMCIA) += pcmcia
-subdir-$(CONFIG_AGP) += agp
-
 ifeq ($(CONFIG_FTAPE),y)
-obj-y       += ftape/ftape.o
+  obj-y       += ftape/ftape.o
 endif
 
 obj-$(CONFIG_H8) += h8.o
@@ -226,6 +226,21 @@
 subdir-$(CONFIG_MWAVE) += mwave
 ifeq ($(CONFIG_MWAVE),y)
   obj-y += mwave/mwave.o
+endif
+
+subdir-$(CONFIG_AGP) += agp
+ifeq ($(CONFIG_AGP),y)
+  obj-y += agp/agp.o
+endif
+
+subdir-$(CONFIG_DRM) += drm
+ifeq ($(CONFIG_DRM),y)
+  obj-y += drm/drm.o
+endif
+
+subdir-$(CONFIG_PCMCIA) += pcmcia
+ifeq ($(CONFIG_PCMCIA),y)
+  obj-y += pcmcia/pcmcia_char.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
--- a/drivers/char/acquirewdt.c	Thu May  9 15:21:02 2002
+++ b/drivers/char/acquirewdt.c	Thu May  9 15:21:02 2002
@@ -221,8 +221,18 @@
 	spin_lock_init(&acq_lock);
 	if (misc_register(&acq_miscdev))
 		return -ENODEV;
-	request_region(WDT_STOP, 1, "Acquire WDT");
-	request_region(WDT_START, 1, "Acquire WDT");
+	if (!request_region(WDT_STOP, 1, "Acquire WDT"))
+		{
+		misc_deregister(&acq_miscdev);
+		return -EIO;
+		}
+	if (!request_region(WDT_START, 1, "Acquire WDT"))
+		{
+		release_region(WDT_STOP, 1);
+		misc_deregister(&acq_miscdev);
+		return -EIO;
+		}
+
 	register_reboot_notifier(&acq_notifier);
 	return 0;
 }
diff -Nru a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
--- a/drivers/char/advantechwdt.c	Thu May  9 15:21:06 2002
+++ b/drivers/char/advantechwdt.c	Thu May  9 15:21:06 2002
@@ -241,11 +241,21 @@
 
 	advwdt_validate_timeout();
 	spin_lock_init(&advwdt_lock);
-	misc_register(&advwdt_miscdev);
+	if (misc_register(&advwdt_miscdev))
+		return -ENODEV;
 #if WDT_START != WDT_STOP
-	request_region(WDT_STOP, 1, "Advantech WDT");
+	if (!request_region(WDT_STOP, 1, "Advantech WDT")) {
+		misc_deregister(&advwdt_miscdev);
+		return -EIO;
+	}
 #endif
-	request_region(WDT_START, 1, "Advantech WDT");
+	if (!request_region(WDT_START, 1, "Advantech WDT")) {
+		misc_deregister(&advwdt_miscdev);
+#if WDT_START != WDT_STOP
+		release_region(WDT_STOP, 1);
+#endif
+		return -EIO;
+	}
 	register_reboot_notifier(&advwdt_notifier);
 	return 0;
 }
diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h	Thu May  9 15:21:06 2002
+++ b/drivers/char/agp/agp.h	Thu May  9 15:21:06 2002
@@ -125,10 +125,12 @@
 	
 };
 
+#define OUTREG64(mmap, addr, val)   __raw_writeq((val), (mmap)+(addr))
 #define OUTREG32(mmap, addr, val)   __raw_writel((val), (mmap)+(addr))
 #define OUTREG16(mmap, addr, val)   __raw_writew((val), (mmap)+(addr))
 #define OUTREG8(mmap, addr, val)   __raw_writeb((val), (mmap)+(addr))
 
+#define INREG64(mmap, addr)         __raw_readq((mmap)+(addr))
 #define INREG32(mmap, addr)         __raw_readl((mmap)+(addr))
 #define INREG16(mmap, addr)         __raw_readw((mmap)+(addr))
 #define INREG8(mmap, addr)         __raw_readb((mmap)+(addr))
@@ -377,5 +379,14 @@
 #define SVWRKS_TLBFLUSH   0x10
 #define SVWRKS_POSTFLUSH  0x14
 #define SVWRKS_DIRFLUSH   0x0c
+
+/* HP ZX1 SBA registers */
+#define HP_ZX1_CTRL		0x200
+#define HP_ZX1_IBASE		0x300
+#define HP_ZX1_IMASK		0x308
+#define HP_ZX1_PCOM		0x310
+#define HP_ZX1_TCNFG		0x318
+#define HP_ZX1_PDIR_BASE	0x320
+#define HP_ZX1_CACHE_FLUSH	0x428
 
 #endif				/* _AGP_BACKEND_PRIV_H */
diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
--- a/drivers/char/agp/agpgart_be.c	Thu May  9 15:21:03 2002
+++ b/drivers/char/agp/agpgart_be.c	Thu May  9 15:21:03 2002
@@ -3273,6 +3273,368 @@
 	 *        AGP devices and collect their data.
 	 */
 
+#ifdef CONFIG_AGP_HP_ZX1
+
+#ifndef log2
+#define log2(x)		ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE	GB(1UL)
+#define HP_ZX1_IOVA_SIZE	GB(1UL)
+#define HP_ZX1_GART_SIZE	(HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE	0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT	0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va)	((va - hp_private.iova_base) >> \
+					hp_private.io_tlb_shift)
+
+static aper_size_info_fixed hp_zx1_sizes[] =
+{
+	{0, 0, 0},		/* filled in by hp_zx1_fetch_size() */
+};
+
+static gatt_mask hp_zx1_masks[] =
+{
+	{HP_ZX1_PDIR_VALID_BIT, 0}
+};
+
+static struct _hp_private {
+	struct pci_dev *ioc;
+	volatile u8 *registers;
+	u64 *io_pdir;		// PDIR for entire IOVA
+	u64 *gatt;		// PDIR just for GART (subset of above)
+	u64 gatt_entries;
+	u64 iova_base;
+	u64 gart_base;
+	u64 gart_size;
+	u64 io_pdir_size;
+	int io_pdir_owner;	// do we own it, or share it with sba_iommu?
+	int io_page_size;
+	int io_tlb_shift;
+	int io_tlb_ps;		// IOC ps config
+	int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+	/*
+	 * IOC already configured by sba_iommu module; just use
+	 * its setup.  We assume:
+	 * 	- IOVA space is 1Gb in size
+	 * 	- first 512Mb is IOMMU, second 512Mb is GART
+	 */
+	hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+	switch (hp->io_tlb_ps) {
+		case 0: hp->io_tlb_shift = 12; break;
+		case 1: hp->io_tlb_shift = 13; break;
+		case 2: hp->io_tlb_shift = 14; break;
+		case 3: hp->io_tlb_shift = 16; break;
+		default:
+			printk(KERN_ERR PFX "Invalid IOTLB page size "
+			       "configuration 0x%x\n", hp->io_tlb_ps);
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENODEV;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+	hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+	hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+	if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+	    	hp->gatt = 0;
+		hp->gatt_entries = 0;
+		printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+		       "GART disabled\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+	/*
+	 * Select an IOV page size no larger than system page size.
+	 */
+	if (PAGE_SIZE >= KB(64)) {
+		hp->io_tlb_shift = 16;
+		hp->io_tlb_ps = 3;
+	} else if (PAGE_SIZE >= KB(16)) {
+		hp->io_tlb_shift = 14;
+		hp->io_tlb_ps = 2;
+	} else if (PAGE_SIZE >= KB(8)) {
+		hp->io_tlb_shift = 13;
+		hp->io_tlb_ps = 1;
+	} else {
+		hp->io_tlb_shift = 12;
+		hp->io_tlb_ps = 0;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = HP_ZX1_IOVA_BASE;
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+	hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+	struct _hp_private *hp = &hp_private;
+	struct pci_dev *ioc;
+	int i;
+	u8 ioc_rev;
+
+	ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+	if (!ioc) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+		return -ENODEV;
+	}
+	hp->ioc = ioc;
+
+	pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+			hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+									    i),
+						    pci_resource_len(ioc, i));
+			break;
+		}
+	}
+	if (!hp->registers) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+		return -ENODEV;
+	}
+
+	/*
+	 * If the IOTLB is currently disabled, we can take it over.
+	 * Otherwise, we have to share with sba_iommu.
+	 */
+	hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+	if (hp->io_pdir_owner)
+		return hp_zx1_ioc_owner(ioc_rev);
+
+	return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+	int size;
+
+	size = hp_private.gart_size / MB(1);
+	hp_zx1_sizes[0].size = size;
+	agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+	return size;
+}
+
+static int hp_zx1_configure(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	agp_bridge.gart_bus_addr = hp->gart_base;
+	agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+	pci_read_config_dword(agp_bridge.dev,
+		agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+	if (hp->io_pdir_owner) {
+		OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+			virt_to_phys(hp->io_pdir));
+		OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+		OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+		OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+		OUTREG64(hp->registers, HP_ZX1_PCOM,
+			hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+		INREG64(hp->registers, HP_ZX1_PCOM);
+	}
+
+	return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	if (hp->io_pdir_owner)
+		OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+	iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+	struct _hp_private *hp = &hp_private;
+
+	OUTREG64(hp->registers, HP_ZX1_PCOM, 
+		hp->gart_base | log2(hp->gart_size));
+	INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	int i;
+
+	if (hp->io_pdir_owner) {
+		hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+						get_order(hp->io_pdir_size));
+		if (!hp->io_pdir) {
+			printk(KERN_ERR PFX "Couldn't allocate contiguous "
+				"memory for I/O PDIR\n");
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENOMEM;
+		}
+		memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+		hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+	}
+
+	for (i = 0; i < hp->gatt_entries; i++) {
+		hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+	}
+
+	return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	
+	if (hp->io_pdir_owner)
+		free_pages((unsigned long) hp->io_pdir,
+			    get_order(hp->io_pdir_size));
+	else
+		hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+	return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, k;
+	off_t j, io_pg_start;
+	int io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+		return -EINVAL;
+	}
+
+	j = io_pg_start;
+	while (j < (io_pg_start + io_pg_count)) {
+		if (hp->gatt[j]) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+		unsigned long paddr;
+
+		paddr = mem->memory[i];
+		for (k = 0;
+		     k < hp->io_pages_per_kpage;
+		     k++, j++, paddr += hp->io_page_size) {
+			hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+		}
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, io_pg_start, io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+		hp->gatt[i] = agp_bridge.scratch_page;
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+	return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+	return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+static int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = hp_zx1_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.size_type = FIXED_APER_SIZE;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = hp_zx1_configure;
+	agp_bridge.fetch_size = hp_zx1_fetch_size;
+	agp_bridge.cleanup = hp_zx1_cleanup;
+	agp_bridge.tlb_flush = hp_zx1_tlbflush;
+	agp_bridge.mask_memory = hp_zx1_mask_memory;
+	agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+	agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+	agp_bridge.insert_memory = hp_zx1_insert_memory;
+	agp_bridge.remove_memory = hp_zx1_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 1;
+
+	return hp_zx1_ioc_init();
+
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_HP_ZX1 */
 
 	pci_for_each_dev(device) {
 		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
@@ -3432,6 +3794,368 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_HP_ZX1
+
+#ifndef log2
+#define log2(x)		ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE	GB(1UL)
+#define HP_ZX1_IOVA_SIZE	GB(1UL)
+#define HP_ZX1_GART_SIZE	(HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE	0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT	0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va)	((va - hp_private.iova_base) >> \
+					hp_private.io_tlb_shift)
+
+static aper_size_info_fixed hp_zx1_sizes[] =
+{
+	{0, 0, 0},		/* filled in by hp_zx1_fetch_size() */
+};
+
+static gatt_mask hp_zx1_masks[] =
+{
+	{HP_ZX1_PDIR_VALID_BIT, 0}
+};
+
+static struct _hp_private {
+	struct pci_dev *ioc;
+	volatile u8 *registers;
+	u64 *io_pdir;		// PDIR for entire IOVA
+	u64 *gatt;		// PDIR just for GART (subset of above)
+	u64 gatt_entries;
+	u64 iova_base;
+	u64 gart_base;
+	u64 gart_size;
+	u64 io_pdir_size;
+	int io_pdir_owner;	// do we own it, or share it with sba_iommu?
+	int io_page_size;
+	int io_tlb_shift;
+	int io_tlb_ps;		// IOC ps config
+	int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+	/*
+	 * IOC already configured by sba_iommu module; just use
+	 * its setup.  We assume:
+	 * 	- IOVA space is 1Gb in size
+	 * 	- first 512Mb is IOMMU, second 512Mb is GART
+	 */
+	hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+	switch (hp->io_tlb_ps) {
+		case 0: hp->io_tlb_shift = 12; break;
+		case 1: hp->io_tlb_shift = 13; break;
+		case 2: hp->io_tlb_shift = 14; break;
+		case 3: hp->io_tlb_shift = 16; break;
+		default:
+			printk(KERN_ERR PFX "Invalid IOTLB page size "
+			       "configuration 0x%x\n", hp->io_tlb_ps);
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENODEV;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+	hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+	hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+	if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+	    	hp->gatt = 0;
+		hp->gatt_entries = 0;
+		printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+		       "GART disabled\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+	/*
+	 * Select an IOV page size no larger than system page size.
+	 */
+	if (PAGE_SIZE >= KB(64)) {
+		hp->io_tlb_shift = 16;
+		hp->io_tlb_ps = 3;
+	} else if (PAGE_SIZE >= KB(16)) {
+		hp->io_tlb_shift = 14;
+		hp->io_tlb_ps = 2;
+	} else if (PAGE_SIZE >= KB(8)) {
+		hp->io_tlb_shift = 13;
+		hp->io_tlb_ps = 1;
+	} else {
+		hp->io_tlb_shift = 12;
+		hp->io_tlb_ps = 0;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = HP_ZX1_IOVA_BASE;
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+	hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+	struct _hp_private *hp = &hp_private;
+	struct pci_dev *ioc;
+	int i;
+	u8 ioc_rev;
+
+	ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+	if (!ioc) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+		return -ENODEV;
+	}
+	hp->ioc = ioc;
+
+	pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+			hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+									    i),
+						    pci_resource_len(ioc, i));
+			break;
+		}
+	}
+	if (!hp->registers) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+		return -ENODEV;
+	}
+
+	/*
+	 * If the IOTLB is currently disabled, we can take it over.
+	 * Otherwise, we have to share with sba_iommu.
+	 */
+	hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+	if (hp->io_pdir_owner)
+		return hp_zx1_ioc_owner(ioc_rev);
+
+	return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+	int size;
+
+	size = hp_private.gart_size / MB(1);
+	hp_zx1_sizes[0].size = size;
+	agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+	return size;
+}
+
+static int hp_zx1_configure(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	agp_bridge.gart_bus_addr = hp->gart_base;
+	agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+	pci_read_config_dword(agp_bridge.dev,
+		agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+	if (hp->io_pdir_owner) {
+		OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+			virt_to_phys(hp->io_pdir));
+		OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+		OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+		OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+		OUTREG64(hp->registers, HP_ZX1_PCOM,
+			hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+		INREG64(hp->registers, HP_ZX1_PCOM);
+	}
+
+	return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	if (hp->io_pdir_owner)
+		OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+	iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+	struct _hp_private *hp = &hp_private;
+
+	OUTREG64(hp->registers, HP_ZX1_PCOM, 
+		hp->gart_base | log2(hp->gart_size));
+	INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	int i;
+
+	if (hp->io_pdir_owner) {
+		hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+						get_order(hp->io_pdir_size));
+		if (!hp->io_pdir) {
+			printk(KERN_ERR PFX "Couldn't allocate contiguous "
+				"memory for I/O PDIR\n");
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENOMEM;
+		}
+		memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+		hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+	}
+
+	for (i = 0; i < hp->gatt_entries; i++) {
+		hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+	}
+
+	return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	
+	if (hp->io_pdir_owner)
+		free_pages((unsigned long) hp->io_pdir,
+			    get_order(hp->io_pdir_size));
+	else
+		hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+	return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, k;
+	off_t j, io_pg_start;
+	int io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+		return -EINVAL;
+	}
+
+	j = io_pg_start;
+	while (j < (io_pg_start + io_pg_count)) {
+		if (hp->gatt[j]) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+		unsigned long paddr;
+
+		paddr = mem->memory[i];
+		for (k = 0;
+		     k < hp->io_pages_per_kpage;
+		     k++, j++, paddr += hp->io_page_size) {
+			hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+		}
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, io_pg_start, io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+		hp->gatt[i] = agp_bridge.scratch_page;
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+	return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+	return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+static int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = hp_zx1_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.size_type = FIXED_APER_SIZE;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = hp_zx1_configure;
+	agp_bridge.fetch_size = hp_zx1_fetch_size;
+	agp_bridge.cleanup = hp_zx1_cleanup;
+	agp_bridge.tlb_flush = hp_zx1_tlbflush;
+	agp_bridge.mask_memory = hp_zx1_mask_memory;
+	agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+	agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+	agp_bridge.insert_memory = hp_zx1_insert_memory;
+	agp_bridge.remove_memory = hp_zx1_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 1;
+
+	return hp_zx1_ioc_init();
+
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_HP_ZX1 */
 
 /* per-chipset initialization data.
  * note -- all chipsets for a single vendor MUST be grouped together
@@ -3725,6 +4449,24 @@
 		via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
 
+#ifdef CONFIG_AGP_HP_ZX1
+	{ PCI_DEVICE_ID_HP_ZX1_LBA,
+		PCI_VENDOR_ID_HP,
+		HP_ZX1,
+		"HP",
+		"ZX1",
+		hp_zx1_setup },
+#endif
+
+#ifdef CONFIG_AGP_HP_ZX1
+	{ PCI_DEVICE_ID_HP_ZX1_LBA,
+		PCI_VENDOR_ID_HP,
+		HP_ZX1,
+		"HP",
+		"ZX1",
+		hp_zx1_setup },
+#endif
+
 	{ 0, }, /* dummy final entry, always present */
 };
 
@@ -3948,6 +4690,40 @@
 	}
 
 #endif	/* CONFIG_AGP_SWORKS */
+
+#ifdef CONFIG_AGP_HP_ZX1
+	if (dev->vendor == PCI_VENDOR_ID_HP) {
+		do {
+			/* ZX1 LBAs can be either PCI or AGP bridges */
+			if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+				printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+				       "chipset at %s\n", dev->slot_name);
+				agp_bridge.type = HP_ZX1;
+				agp_bridge.dev = dev;
+				return hp_zx1_setup(dev);
+			}
+			dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
+		} while (dev);
+		return -ENODEV;
+	}
+#endif	/* CONFIG_AGP_HP_ZX1 */
+
+#ifdef CONFIG_AGP_HP_ZX1
+	if (dev->vendor == PCI_VENDOR_ID_HP) {
+		do {
+			/* ZX1 LBAs can be either PCI or AGP bridges */
+			if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+				printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+				       "chipset at %s\n", dev->slot_name);
+				agp_bridge.type = HP_ZX1;
+				agp_bridge.dev = dev;
+				return hp_zx1_setup(dev);
+			}
+			dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
+		} while (dev);
+		return -ENODEV;
+	}
+#endif	/* CONFIG_AGP_HP_ZX1 */
 
 	/* find capndx */
 	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c
--- a/drivers/char/amiserial.c	Thu May  9 15:21:10 2002
+++ b/drivers/char/amiserial.c	Thu May  9 15:21:10 2002
@@ -89,7 +89,7 @@
 #include <asm/setup.h>
 
 #include <asm/system.h>
-#include <asm/io.h>
+
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
diff -Nru a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h
--- a/drivers/char/drm/drm_agpsupport.h	Thu May  9 15:21:00 2002
+++ b/drivers/char/drm/drm_agpsupport.h	Thu May  9 15:21:00 2002
@@ -317,6 +317,8 @@
 			break;
 #endif
 
+		case HP_ZX1:		head->chipset = "HP ZX1";	 break;
+
 		default:		head->chipset = "Unknown";       break;
 		}
 #if LINUX_VERSION_CODE <= 0x020408
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Thu May  9 15:21:07 2002
+++ b/drivers/char/ip2main.c	Thu May  9 15:21:07 2002
@@ -2662,7 +2662,7 @@
 	old_flags = pCh->flags;
 	old_baud_divisor = pCh->BaudDivisor;
 
-	if ( !suser() ) {
+	if ( !capable(CAP_SYS_ADMIN) ) {
 		if ( ( ns.close_delay != pCh->ClosingDelay ) ||
 		    ( (ns.flags & ~ASYNC_USR_MASK) !=
 		      (pCh->flags & ~ASYNC_USR_MASK) ) ) {
diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c
--- a/drivers/char/moxa.c	Thu May  9 15:21:09 2002
+++ b/drivers/char/moxa.c	Thu May  9 15:21:09 2002
@@ -2799,7 +2799,7 @@
 	    (new_serial.baud_base != 921600))
 		return (-EPERM);
 
-	if (!suser()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		if (((new_serial.flags & ~ASYNC_USR_MASK) !=
 		     (info->asyncflags & ~ASYNC_USR_MASK)))
 			return (-EPERM);
diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c	Thu May  9 15:21:08 2002
+++ b/drivers/char/mxser.c	Thu May  9 15:21:08 2002
@@ -2199,7 +2199,7 @@
 
 	flags = info->flags & ASYNC_SPD_MASK;
 
-	if (!suser()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
 		    (new_serial.close_delay != info->close_delay) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
diff -Nru a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in
--- a/drivers/char/pcmcia/Config.in	Thu May  9 15:21:02 2002
+++ b/drivers/char/pcmcia/Config.in	Thu May  9 15:21:02 2002
@@ -5,12 +5,8 @@
 mainmenu_option next_comment
 comment 'PCMCIA character devices'
 
-dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL
-if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then
-   define_bool CONFIG_PCMCIA_CHRDEV y
-fi
-
-tristate 'SyncLink PC Card support' CONFIG_SYNCLINK_CS
+dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA $CONFIG_SERIAL
+dep_tristate 'SyncLink PC Card support' CONFIG_SYNCLINK_CS $CONFIG_PCMCIA
 
 endmenu
 
diff -Nru a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
--- a/drivers/char/pcmcia/Makefile	Thu May  9 15:21:02 2002
+++ b/drivers/char/pcmcia/Makefile	Thu May  9 15:21:02 2002
@@ -4,16 +4,7 @@
 # Makefile for the Linux PCMCIA char device drivers.
 #
 
-SUB_DIRS     := 
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
 O_TARGET := pcmcia_char.o
-
-obj-y		:=
-obj-m		:=
-obj-n		:=
-obj-		:=
 
 obj-$(CONFIG_PCMCIA_SERIAL_CS)	+= serial_cs.o
 obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Thu May  9 15:21:02 2002
+++ b/drivers/char/random.c	Thu May  9 15:21:02 2002
@@ -2068,6 +2068,7 @@
 	seq += tv.tv_usec + tv.tv_sec*1000000;
 	return seq;
 }
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
 
 __u32 secure_ipv6_id(__u32 *daddr)
 {
@@ -2088,6 +2089,7 @@
 	return twothirdsMD4Transform(daddr, secret);
 }
 
+EXPORT_SYMBOL(secure_ipv6_id);
 #endif
 
 
diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
--- a/drivers/char/rio/rio_linux.c	Thu May  9 15:21:08 2002
+++ b/drivers/char/rio/rio_linux.c	Thu May  9 15:21:08 2002
@@ -702,7 +702,7 @@
   func_enter();
 
   /* The "dev" argument isn't used. */
-  rc = -riocontrol (p, 0, cmd, (void *)arg, suser ());
+  rc = -riocontrol (p, 0, cmd, (void *)arg, capable(CAP_SYS_ADMIN));
 
   func_exit ();
   return rc;
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Thu May  9 15:21:02 2002
+++ b/drivers/char/rocket.c	Thu May  9 15:21:02 2002
@@ -1238,11 +1238,7 @@
 	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
 		return -EFAULT;
 
-#ifdef CAP_SYS_ADMIN
 	if (!capable(CAP_SYS_ADMIN))
-#else
-	if (!suser())
-#endif
 	{
 		if ((new_serial.flags & ~ROCKET_USR_MASK) !=
 		    (info->flags & ~ROCKET_USR_MASK))
diff -Nru a/drivers/char/serial.c b/drivers/char/serial.c
--- a/drivers/char/serial.c	Thu May  9 15:21:04 2002
+++ b/drivers/char/serial.c	Thu May  9 15:21:04 2002
@@ -5226,7 +5226,8 @@
 
 static void inline avoid_irq_share(struct pci_dev *dev)
 {
-	int i, map = 0x1FF8;
+	int i;
+	unsigned long map = 0x1FF8;
 	struct serial_state *state = rs_table;
 	struct isapnp_irq *irq;
 	struct isapnp_resources *res = dev->sysdata;
diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c
--- a/drivers/char/serial167.c	Thu May  9 15:21:06 2002
+++ b/drivers/char/serial167.c	Thu May  9 15:21:06 2002
@@ -1472,7 +1472,7 @@
 	    return -EFAULT;
     old_info = *info;
 
-    if (!suser()) {
+    if (!capable(CAP_SYS_ADMIN)) {
 	    if ((new_serial.close_delay != info->close_delay) ||
 		((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
 		 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c	Thu May  9 15:21:03 2002
+++ b/drivers/char/sonypi.c	Thu May  9 15:21:03 2002
@@ -485,12 +485,10 @@
 
 static int sonypi_misc_open(struct inode * inode, struct file * file) {
 	down(&sonypi_device.lock);
-	if (sonypi_device.open_count)
-		goto out;
+	/* Flush input queue on first open */
+	if (!sonypi_device.open_count)
+		sonypi_initq();
 	sonypi_device.open_count++;
-	/* Flush input queue */
-	sonypi_initq();
-out:
 	up(&sonypi_device.lock);
 	return 0;
 }
@@ -718,9 +716,12 @@
 	       SONYPI_DRIVER_MAJORVERSION,
 	       SONYPI_DRIVER_MINORVERSION);
 	printk(KERN_INFO "sonypi: detected %s model, "
-	       "camera = %s, compat = %s, nojogdial = %s\n",
+	       "verbose = %s, fnkeyinit = %s, camera = %s, "
+	       "compat = %s, nojogdial = %s\n",
 	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 			"type1" : "type2",
+	       verbose ? "on" : "off",
+	       fnkeyinit ? "on" : "off",
 	       camera ? "on" : "off",
 	       compat ? "on" : "off",
 	       nojogdial ? "on" : "off");
@@ -779,7 +780,7 @@
 
 #ifndef MODULE
 static int __init sonypi_setup(char *str)  {
-	int ints[6];
+	int ints[7];
 
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 	if (ints[0] <= 0) 
diff -Nru a/drivers/char/sonypi.h b/drivers/char/sonypi.h
--- a/drivers/char/sonypi.h	Thu May  9 15:21:01 2002
+++ b/drivers/char/sonypi.h	Thu May  9 15:21:01 2002
@@ -35,7 +35,7 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	11
+#define SONYPI_DRIVER_MINORVERSION	13
 
 #include <linux/types.h>
 #include <linux/pci.h>
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Thu May  9 15:21:08 2002
+++ b/drivers/char/tty_io.c	Thu May  9 15:21:08 2002
@@ -1370,7 +1370,7 @@
 		retval = -ENODEV;
 	filp->f_flags = saved_flags;
 
-	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
+	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
 		retval = -EBUSY;
 
 	if (retval) {
@@ -1472,7 +1472,7 @@
 {
 	char ch, mbz = 0;
 
-	if ((current->tty != tty) && !suser())
+	if ((current->tty != tty) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(ch, arg))
 		return -EFAULT;
@@ -1510,7 +1510,7 @@
 {
 	if (IS_SYSCONS_DEV(inode->i_rdev) ||
 	    IS_CONSOLE_DEV(inode->i_rdev)) {
-		if (!suser())
+		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		redirect = NULL;
 		return 0;
@@ -1552,7 +1552,7 @@
 		 * This tty is already the controlling
 		 * tty for another session group!
 		 */
-		if ((arg == 1) && suser()) {
+		if ((arg == 1) && capable(CAP_SYS_ADMIN)) {
 			/*
 			 * Steal it away
 			 */
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Thu May  9 15:21:08 2002
+++ b/drivers/char/vt.c	Thu May  9 15:21:08 2002
@@ -440,10 +440,10 @@
 
 	/*
 	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or super-user.
+	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
 	perm = 0;
-	if (current->tty == tty || suser())
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		perm = 1;
  
 	kbd = kbd_table + console;
@@ -508,7 +508,7 @@
 	{
 		struct kbd_repeat kbrep;
 		
-		if (!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_TTY_CONFIG))
 			return -EPERM;
 
 		if (copy_from_user(&kbrep, (void *)arg,
@@ -621,7 +621,7 @@
 
 	case KDGETKEYCODE:
 	case KDSETKEYCODE:
-		if(!capable(CAP_SYS_ADMIN))
+		if(!capable(CAP_SYS_TTY_CONFIG))
 			perm=0;
 		return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
 
@@ -1038,12 +1038,12 @@
 		return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm);
 
 	case VT_LOCKSWITCH:
-		if (!suser())
+		if (!capable(CAP_SYS_TTY_CONFIG))
 		   return -EPERM;
 		vt_dont_switch = 1;
 		return 0;
 	case VT_UNLOCKSWITCH:
-		if (!suser())
+		if (!capable(CAP_SYS_TTY_CONFIG))
 		   return -EPERM;
 		vt_dont_switch = 0;
 		return 0;
diff -Nru a/drivers/char/wdt285.c b/drivers/char/wdt285.c
--- a/drivers/char/wdt285.c	Thu May  9 15:21:04 2002
+++ b/drivers/char/wdt285.c	Thu May  9 15:21:04 2002
@@ -136,11 +136,9 @@
 		default:
 			return -ENOTTY;
 		case WDIOC_GETSUPPORT:
-			i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
-			if (i)
-				return i;
-			else
-				return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
+			if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+				return -EFAULT;
+			return 0;
 		case WDIOC_GETSTATUS:
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0,(int *)arg);
diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
--- a/drivers/hotplug/cpqphp_core.c	Thu May  9 15:21:00 2002
+++ b/drivers/hotplug/cpqphp_core.c	Thu May  9 15:21:00 2002
@@ -38,7 +38,7 @@
 #include <asm/uaccess.h>
 #include "cpqphp.h"
 #include "cpqphp_nvram.h"
-#include "../../arch/i386/kernel/pci-i386.h"	/* horrible hack showing how processor dependant we are... */
+#include "../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependant we are... */
 
 
 /* Global variables */
diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c
--- a/drivers/hotplug/cpqphp_pci.c	Thu May  9 15:21:09 2002
+++ b/drivers/hotplug/cpqphp_pci.c	Thu May  9 15:21:09 2002
@@ -35,7 +35,7 @@
 #include <linux/pci.h>
 #include "cpqphp.h"
 #include "cpqphp_nvram.h"
-#include "../../arch/i386/kernel/pci-i386.h"	/* horrible hack showing how processor dependant we are... */
+#include "../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependant we are... */
 
 
 u8 cpqhp_nic_irq;
diff -Nru a/drivers/hotplug/ibmphp.h b/drivers/hotplug/ibmphp.h
--- a/drivers/hotplug/ibmphp.h	Thu May  9 15:21:02 2002
+++ b/drivers/hotplug/ibmphp.h	Thu May  9 15:21:02 2002
@@ -168,13 +168,11 @@
 
 struct ebda_hpc_bus {
 	u32 bus_num;
-/*
 	u8 slots_at_33_conv;
 	u8 slots_at_66_conv;
 	u8 slots_at_66_pcix;
 	u8 slots_at_100_pcix;
 	u8 slots_at_133_pcix;
-*/
 };
 
 
@@ -232,12 +230,15 @@
 	u8 slot_max;
 	u8 slot_count;
 	u8 busno;
-	u8 current_speed;
-	u8 supported_speed;
 	u8 controller_id;
-	u8 supported_bus_mode;
+	u8 current_speed;
 	u8 current_bus_mode;
 	u8 index;
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
 	struct list_head bus_info_list;
 };
 
@@ -690,8 +691,11 @@
 	u8 bus;
 	u8 device;
 	u8 number;
+	u8 real_physical_slot_num;
 	char name[100];
 	u32 capabilities;
+	u8 supported_speed;
+	u8 supported_bus_mode;
 	struct hotplug_slot *hotplug_slot;
 	struct controller *ctrl;
 	struct pci_func *func;
@@ -709,10 +713,12 @@
 struct controller {
 	struct ebda_hpc_slot *slots;
 	struct ebda_hpc_bus *buses;
+	u8 starting_slot_num;	/* starting and ending slot #'s this ctrl controls*/
+	u8 ending_slot_num;
 	u8 revision;
 	u8 options;		/* which options HPC supports */
 	u8 status;
-	u8 ctlr_id;		/* TONI */
+	u8 ctlr_id;
 	u8 slot_count;
 	u8 bus_count;
 	u8 ctlr_relative_id;
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Thu May  9 15:21:07 2002
+++ b/drivers/hotplug/ibmphp_core.c	Thu May  9 15:21:07 2002
@@ -35,7 +35,7 @@
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
-#include "../../arch/i386/kernel/pci-i386.h"	/* for struct irq_routing_table */
+#include "../../arch/i386/pci/pci.h"	/* for struct irq_routing_table */
 #include "ibmphp.h"
 
 #define attn_on(sl)  ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.1"
+#define DRIVER_VERSION	"0.2"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -393,8 +393,8 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			mode = pslot->bus_on->supported_bus_mode;
-			*value = pslot->bus_on->supported_speed;
+			mode = pslot->supported_bus_mode;
+			*value = pslot->supported_speed;
 			*value &= 0x0f;
 
 			if (mode == BUS_MODE_PCIX)
@@ -1009,6 +1009,7 @@
 	}
 	return rc;
 }
+
 /*******************************************************
  * Returns whether the bus is empty or not 
  *******************************************************/
@@ -1036,7 +1037,9 @@
 
 /***********************************************************
  * If the HPC permits and the bus currently empty, tries to set the 
- * bus speed and mode at the maximum card capability
+ * bus speed and mode at the maximum card and bus capability
+ * Parameters: slot
+ * Returns: bus is set (0) or error code
  ***********************************************************/
 static int set_bus (struct slot * slot_cur)
 {
@@ -1056,30 +1059,102 @@
 			cmd = HPC_BUS_33CONVMODE;
 			break;
 		case HPC_SLOT_SPEED_66:
-			if (SLOT_PCIX (slot_cur->ext_status))
-				cmd = HPC_BUS_66PCIXMODE;
-			else
-				cmd = HPC_BUS_66CONVMODE;
+			if (SLOT_PCIX (slot_cur->ext_status)) {
+				if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX))
+					cmd = HPC_BUS_66PCIXMODE;
+				else if (!SLOT_BUS_MODE (slot_cur->ext_status))
+					/* if max slot/bus capability is 66 pci
+					and there's no bus mode mismatch, then
+					the adapter supports 66 pci */ 
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			} else {
+				if (slot_cur->supported_speed >= BUS_SPEED_66)
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			}
 			break;
 		case HPC_SLOT_SPEED_133:
-			if (slot_cur->bus_on->slot_count > 1)
+			switch (slot_cur->supported_speed) {
+			case BUS_SPEED_33:
+				cmd = HPC_BUS_33CONVMODE;
+				break;
+			case BUS_SPEED_66:
+				if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
+					cmd = HPC_BUS_66PCIXMODE;
+				else
+					cmd = HPC_BUS_66CONVMODE;
+				break;
+			case BUS_SPEED_100:
 				cmd = HPC_BUS_100PCIXMODE;
-			else
+				break;
+			case BUS_SPEED_133:
 				cmd = HPC_BUS_133PCIXMODE;
+				break;
+			default:
+				err ("Wrong bus speed \n");
+				return -ENODEV;
+			}
 			break;
 		default:
 			err ("wrong slot speed \n");
 			return -ENODEV;
 		}
 		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
-		rc = ibmphp_hpc_writeslot (slot_cur, cmd);
-		if (rc)
-			return rc;
+		ibmphp_hpc_writeslot (slot_cur, cmd);
 	}
+	/* This is for x400, once Brandon fixes the firmware, 
+	will not need this delay */
+	long_delay (1 * HZ);
 	debug ("%s -Exit \n", __FUNCTION__);
 	return 0;
 }
 
+/* This routine checks the bus limitations that the slot is on from the BIOS.
+ * This is used in deciding whether or not to power up the slot.  
+ * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on
+ * same bus) 
+ * Parameters: slot
+ * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
+ */
+static int check_limitations (struct slot *slot_cur)
+{
+	u8 i;
+	struct slot * tmp_slot;
+	u8 count = 0;
+	u8 limitation = 0;
+
+	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
+		tmp_slot = ibmphp_get_slot_from_physical_num (i);
+		if ((SLOT_POWER (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
+			count++;
+	}
+	get_cur_bus_info (&slot_cur);
+	switch (slot_cur->bus_on->current_speed) {
+	case BUS_SPEED_33:
+		limitation = slot_cur->bus_on->slots_at_33_conv;
+		break;
+	case BUS_SPEED_66:
+		if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+			limitation = slot_cur->bus_on->slots_at_66_pcix;
+		else
+			limitation = slot_cur->bus_on->slots_at_66_conv;
+		break;
+	case BUS_SPEED_100:
+		limitation = slot_cur->bus_on->slots_at_100_pcix;
+		break;
+	case BUS_SPEED_133:
+		limitation = slot_cur->bus_on->slots_at_133_pcix;
+		break;
+	}
+
+	if ((count + 1) > limitation)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void print_card_capability (struct slot *slot_cur)
 {
 	info ("capability of the card is ");
@@ -1136,7 +1211,28 @@
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
-		
+
+	/*-----------------debugging------------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); 
+	/*----------------------------------------------------------*/
+
+	rc = check_limitations (slot_cur);
+	if (rc) {
+		err ("Adding this card exceeds the limitations of this bus. \n");
+		err ("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus \n. Try hot-adding into another bus \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -EINVAL;
+	}
+
 	rc = power_on (slot_cur);
 
 	if (rc) {
@@ -1151,19 +1247,24 @@
 			return -ENODEV;
 		}
 		/* Check to see the error of why it failed */
-		if (!(SLOT_PWRGD (slot_cur->status)))
+		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status)))
 			err ("power fault occured trying to power up \n");
 		else if (SLOT_BUS_SPEED (slot_cur->status)) {
 			err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
 			print_card_capability (slot_cur);
-		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) 
+		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) {
 			err ("bus mode mismatch occured.  please check current bus mode and card capability \n");
-
+			print_card_capability (slot_cur);
+		}
 		ibmphp_update_slot_info (slot_cur);
-		ibmphp_unlock_operations (); 
+		ibmphp_unlock_operations ();
 		return rc;
 	}
 	debug ("after power_on\n");
+	/*-----------------------debugging---------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
 
 	rc = slot_update (&slot_cur);
 	if (rc) {
@@ -1180,7 +1281,7 @@
 	
 	if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
 		faulted = 1;
-		err ("power fault occured trying to power up...\n");
+		err ("power fault occured trying to power up... \n");
 	} else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
 		faulted = 1;
 		err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
@@ -1200,8 +1301,8 @@
 			return rcpr;
 		}
 			
-		if (slot_update (&slot_cur)) {
-			ibmphp_unlock_operations ();
+		if (slot_update (&slot_cur)) {                      
+			ibmphp_unlock_operations ();	
 			return -ENODEV;
 		}
 		ibmphp_update_slot_info (slot_cur);
@@ -1278,20 +1379,24 @@
 {
 	int rc;
 	struct slot *slot_cur = (struct slot *) hotplug_slot->private;
-	u8 flag = slot_cur->flag;
+	u8 flag;
+	int parm = 0;
 
-	slot_cur->flag = TRUE;
 	debug ("DISABLING SLOT... \n"); 
 		
-	ibmphp_lock_operations (); 
-	if (slot_cur == NULL) {
-		ibmphp_unlock_operations ();
+	if (slot_cur == NULL) 
 		return -ENODEV;
-	}
-	if (slot_cur->ctrl == NULL) {
-		ibmphp_unlock_operations ();
+	
+	if (slot_cur->ctrl == NULL) 
 		return -ENODEV;
-	}
+	
+	flag = slot_cur->flag;	/* to see if got here from polling */
+	
+	if (flag)
+		ibmphp_lock_operations ();
+	
+	slot_cur->flag = TRUE;
+
 	if (flag == TRUE) {
 		rc = validate (slot_cur, DISABLE);	/* checking if powered off already & valid slot # */
 		if (rc) {
@@ -1333,10 +1438,21 @@
 		ibmphp_unlock_operations ();
 		return rc;
 	}
+        
+	/* If we got here from latch suddenly opening on operating card or 
+	a power fault, there's no power to the card, so cannot
+	read from it to determine what resources it occupied.  This operation
+	is forbidden anyhow.  The best we can do is remove it from kernel
+	lists at least */
+
+	if (!flag) {
+		attn_off (slot_cur);
+		return 0;
+	}
 
-	rc = ibmphp_unconfigure_card (&slot_cur, 0);
+	rc = ibmphp_unconfigure_card (&slot_cur, parm);
 	slot_cur->func = NULL;
-	debug ("in disable_slot. after unconfigure_card \n");
+	debug ("in disable_slot. after unconfigure_card\n");
 	if (rc) {
 		err ("could not unconfigure card.\n");
 		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
@@ -1347,9 +1463,7 @@
 			return -EFAULT;
 		}
 
-		if (flag) 
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
@@ -1363,9 +1477,7 @@
 			return -EFAULT;
 		}
 
-		if (flag)
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return rc;
 	}
@@ -1375,11 +1487,7 @@
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
-	if (flag) 
-		rc = ibmphp_update_slot_info (slot_cur);
-	else
-		rc = 0;
-
+	rc = ibmphp_update_slot_info (slot_cur);
 	ibmphp_print_test ();
 	ibmphp_unlock_operations();
 	return rc;
@@ -1422,9 +1530,12 @@
 	int rc = 0;
 
 	init_flag = 1;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
 	ibmphp_pci_root_ops = get_root_pci_ops ();
 	if (ibmphp_pci_root_ops == NULL) {
-		err ("cannot read bus operations... will not be able to read the cards.  Please check your system \n");
+		err ("cannot read bus operations... will not be able to read the cards.  Please check your system\n");
 		return -ENODEV;	
 	}
 
@@ -1439,13 +1550,13 @@
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("after ibmphp_access_ebda () \n");
+	debug ("after ibmphp_access_ebda ()\n");
 
 	if ((rc = ibmphp_rsrc_init ())) {
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+	debug ("AFTER Resource & EBDA INITIALIZATIONS\n");
 
 	max_slots = get_max_slots ();
 
@@ -1463,7 +1574,6 @@
 	 * so that no one can unload us. */
 	MOD_DEC_USE_COUNT;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 	return 0;
 }
@@ -1471,9 +1581,9 @@
 static void __exit ibmphp_exit (void)
 {
 	ibmphp_hpc_stop_poll_thread ();
-	debug ("after polling \n");
+	debug ("after polling\n");
 	ibmphp_unload ();
-	debug ("done \n");
+	debug ("done\n");
 }
 
 module_init (ibmphp_init);
diff -Nru a/drivers/hotplug/ibmphp_ebda.c b/drivers/hotplug/ibmphp_ebda.c
--- a/drivers/hotplug/ibmphp_ebda.c	Thu May  9 15:21:03 2002
+++ b/drivers/hotplug/ibmphp_ebda.c	Thu May  9 15:21:03 2002
@@ -161,9 +161,14 @@
 		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
 		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
 		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
-		debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed);
 		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
-		debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode);
+		
+		debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv);
+		debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv);
+		debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix);
+		debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix);
+		debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix);
+
 	}
 }
 
@@ -455,19 +460,9 @@
 				bus_info_ptr1->index = bus_index++;
 				bus_info_ptr1->current_speed = 0xff;
 				bus_info_ptr1->current_bus_mode = 0xff;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX )
-					bus_info_ptr1->supported_speed =  3;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX )
-					bus_info_ptr1->supported_speed =  2;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX )
-					bus_info_ptr1->supported_speed =  1;
+				
 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP )
-					bus_info_ptr1->supported_bus_mode = 1;
-				else
-					bus_info_ptr1->supported_bus_mode =0;
-
-
+				
 				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
 
 			} else {
@@ -486,9 +481,25 @@
 		/* init bus structure */
 		bus_ptr = hpc_ptr->buses;
 		for (bus = 0; bus < bus_num; bus++) {
-			bus_ptr->bus_num = readb (io_mem + addr_bus);
+			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
+			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
+			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
+
+			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
+
+			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
+
+			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
+			if (bus_info_ptr2) {
+				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
+				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
+				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
+				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
+				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; 
+			}
 			bus_ptr++;
-			addr_bus += 1;
 		}
 
 		hpc_ptr->ctlr_type = temp;
@@ -511,10 +522,6 @@
 			case 2:
 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
-				/* following 2 lines for testing purpose */
-				if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) 
-					hpc_ptr->ctlr_type = 4;	
-				
 
 				hpc_ptr->irq = readb (io_mem + addr + 5);
 				addr += 6;
@@ -537,6 +544,8 @@
 
 		hpc_ptr->revision = 0xff;
 		hpc_ptr->options = 0xff;
+		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
+		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
 
 		// register slots with hpc core as well as create linked list of ibm slot
 		for (index = 0; index < hpc_ptr->slot_count; index++) {
@@ -573,10 +582,24 @@
 				return -ENOMEM;
 			}
 
+
 			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
 			snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num);
 
 			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  3;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  2;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  1;
+				
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 1;
+			else
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 0;
+
+
 			((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
 
 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
@@ -591,7 +614,7 @@
 
 			((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
 			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
-
+			
 			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
 
 			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c
--- a/drivers/hotplug/ibmphp_hpc.c	Thu May  9 15:21:04 2002
+++ b/drivers/hotplug/ibmphp_hpc.c	Thu May  9 15:21:04 2002
@@ -83,10 +83,6 @@
 //
 //----------------------------------------------------------------------------
 #define WPG_I2C_IOREMAP_SIZE	0x2044	// size of linear address interval
-#define WPG_CTLR_MAX		0x01	// max controllers
-#define WPG_SLOT_MAX		0x06	// max slots
-#define WPG_CTLR_SLOT_MAX	0x06	// max slots per controller
-#define WPG_FIRST_CTLR		0x00	// index of the controller
 
 //----------------------------------------------------------------------------
 // command index
@@ -127,7 +123,7 @@
 static void poll_hpc (void);
 static int update_slot (struct slot *, u8);
 static int process_changeinstatus (struct slot *, struct slot *);
-static int process_changeinlatch (u8, u8);
+static int process_changeinlatch (u8, u8, struct controller *);
 static int hpc_poll_thread (void *);
 static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
 //----------------------------------------------------------------------------
@@ -277,8 +273,7 @@
 	int i;
 
 
-	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n",
-		       __FUNCTION__, (ulong) WPGBbar, index, cmd);
+	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd);
 
 	rc = 0;
 	//--------------------------------------------------------------------
@@ -470,8 +465,7 @@
 	int rc = 0;
 	int busindex;
 
-	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n",
-		       __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
+	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
 
 	if ((pslot == NULL)
 	    || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
@@ -779,7 +773,7 @@
 										  &curlatchlow);
 							if (oldlatchlow != curlatchlow)
 								process_changeinlatch (oldlatchlow,
-											curlatchlow);
+											curlatchlow, pslot->ctrl);
 						}
 					}
 				}
@@ -917,7 +911,6 @@
 
 	// bit 0 - HPC_SLOT_POWER
 	if ((pslot->status & 0x01) != (poldslot->status & 0x01))
-		/* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */
 		update = TRUE;
 
 	// bit 1 - HPC_SLOT_CONNECT
@@ -936,7 +929,7 @@
 	// bit 5 - HPC_SLOT_PWRGD
 	if ((pslot->status & 0x20) != (poldslot->status & 0x20))
 		// OFF -> ON: ignore, ON -> OFF: disable slot
-		if (poldslot->status & 0x20)
+		if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) 
 			disable = TRUE;
 
 	// bit 6 - HPC_SLOT_BUS_SPEED
@@ -947,20 +940,20 @@
 		update = TRUE;
 		// OPEN -> CLOSE
 		if (pslot->status & 0x80) {
-			if (SLOT_POWER (pslot->status)) {
+			if (SLOT_PWRGD (pslot->status)) {
 				// power goes on and off after closing latch
 				// check again to make sure power is still ON
 				long_delay (1 * HZ);
 				rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status);
-				if (SLOT_POWER (status))
+				if (SLOT_PWRGD (status))
 					update = TRUE;
 				else	// overwrite power in pslot to OFF
 					pslot->status &= ~HPC_SLOT_POWER;
 			}
 		}
 		// CLOSE -> OPEN 
-		else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON)
-			|| (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) {
+		else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD)
+			&& (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) {
 			disable = TRUE;
 		}
 		// else - ignore
@@ -994,7 +987,7 @@
 * Return   0 or error codes
 * Value:
 *---------------------------------------------------------------------*/
-static int process_changeinlatch (u8 old, u8 new)
+static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
 {
 	struct slot myslot, *pslot;
 	u8 i;
@@ -1004,7 +997,7 @@
 	debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new);
 	// bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
 
-	for (i = 1; i <= 6; i++) {
+	for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) {
 		mask = 0x01 << i;
 		if ((mask & old) != (mask & new)) {
 			pslot = ibmphp_get_slot_from_physical_num (i);
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Thu May  9 15:21:04 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Thu May  9 15:21:04 2002
@@ -86,14 +86,6 @@
 LIST_HEAD(pci_hotplug_slot_list);
 
 
-static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf)
-{
-	buf->f_type = PCIHPFS_MAGIC;
-	buf->f_bsize = PAGE_CACHE_SIZE;
-	buf->f_namelen = 255;
-	return 0;
-}
-
 static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev)
 {
 	struct inode *inode = new_inode(sb);
diff -Nru a/drivers/i2c/i2c-adap-ite.c b/drivers/i2c/i2c-adap-ite.c
--- a/drivers/i2c/i2c-adap-ite.c	Thu May  9 15:21:04 2002
+++ b/drivers/i2c/i2c-adap-ite.c	Thu May  9 15:21:04 2002
@@ -241,7 +241,7 @@
 };
 
 /* Called when the module is loaded.  This function starts the
- * cascade of calls up through the heirarchy of i2c modules (i.e. up to the
+ * cascade of calls up through the hierarchy of i2c modules (i.e. up to the
  *  algorithm layer and into to the core layer)
  */
 static int __init iic_ite_init(void) 
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Thu May  9 15:21:09 2002
+++ b/drivers/ide/Config.help	Thu May  9 15:21:09 2002
@@ -216,11 +216,6 @@
   Linux. This may slow disk throughput by a few percent, but at least
   things will operate 100% reliably.
 
-CONFIG_BLK_DEV_IDEPCI
-  Say Y here for PCI systems which use IDE drive(s).
-  This option helps the IDE driver to automatically detect and
-  configure all PCI-based IDE interfaces in your system.
-
 CONFIG_IDEPCI_SHARE_IRQ
   Some ATA/IDE chipsets have hardware support which allows for
   sharing a single IRQ with other cards. To enable support for
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Thu May  9 15:21:09 2002
+++ b/drivers/ide/Config.in	Thu May  9 15:21:09 2002
@@ -33,58 +33,55 @@
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
-   comment 'ATA host chipset support'
-   dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
+   comment 'ATA host chip set support'
+   dep_bool '  CMD640 chip set bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
    dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
    dep_bool '  ISA-PNP support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
    if [ "$CONFIG_PCI" = "y" ]; then
-      dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-      bool '  PCI host chipset support' CONFIG_BLK_DEV_IDEPCI
-      if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
-	 bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
-	 bool '    Sharing PCI ATA interrupts support' CONFIG_IDEPCI_SHARE_IRQ
-	 bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
-         dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
-	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	 dep_bool '      TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
-	 if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then
-	    int '      Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
-	 fi
-	 dep_bool '    Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL
-	 dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
-	 dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 $CONFIG_EXPERIMENTAL
-	 dep_bool '    AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 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 (EXPERMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
-	 dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-	 if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
-	    dep_bool '      Use UDMA133 even on ICH2, ICH3 and CICH chips (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TRY133 $CONFIG_EXPERIMENTAL
-	 fi
-	 if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
-	    dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
-	 fi
-	 dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	 dep_mbool '    Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_EXPERIMENTAL
-	 dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
-	 dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	 dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	 dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	 dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    VIA chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '  RZ1000 chip set bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+      comment '  PCI host chip set support'
+      dep_bool '    Boot off-board chip sets first support' CONFIG_BLK_DEV_OFFBOARD $CONFIG_PCI
+      dep_bool '    Sharing PCI ATA interrupts support' CONFIG_IDEPCI_SHARE_IRQ $CONFIG_PCI
+      dep_bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_PCI
+      dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '      Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
+      define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+      dep_bool '      TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
+      if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then
+         int '      Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32
       fi
-
+      dep_bool '    Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL
+      dep_bool '    AEC62XX chip set support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
+      dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 $CONFIG_EXPERIMENTAL
+      dep_bool '    AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+      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 (EXPERMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
+      dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
+      if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+         dep_bool '      Use UDMA133 even on ICH2, ICH3 and CICH chips (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TRY133 $CONFIG_EXPERIMENTAL
+      fi
+      if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
+         dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
+         dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
+      fi
+      dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_mbool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_PCI $CONFIG_EXPERIMENTAL
+      dep_mbool '    Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_EXPERIMENTAL
+      dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
+      dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
+      dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+      dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+      dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    VIA chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+      dep_bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEDMA_PCI
    fi
    if [ "$CONFIG_ALL_PPC" = "y" ]; then
       bool '    Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
@@ -93,9 +90,6 @@
       if [ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" ]; then
 	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC
       fi
-      if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-	 define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC
-      fi
    fi
    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
       dep_bool '    ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN
@@ -109,7 +103,7 @@
       dep_mbool '    Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL
    fi
    if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_mbool '  Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
+      dep_mbool '  Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA $CONFIG_ZORRO $CONFIG_EXPERIMENTAL
    fi
    if [ "$CONFIG_ATARI" = "y" ]; then
       dep_bool '  Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE $CONFIG_ATARI
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Thu May  9 15:21:08 2002
+++ b/drivers/ide/Makefile	Thu May  9 15:21:08 2002
@@ -45,7 +45,7 @@
 ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
 ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_TCQ)	+= tcq.o
-ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
+ide-obj-$(CONFIG_PCI)			+= ide-pci.o
 ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
 ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
 ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
@@ -71,8 +71,6 @@
 obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
-
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
 
 ide-mod-objs		:= ide-taskfile.o ide.o ide-probe.o ide-geometry.o ide-features.o ata-timing.o $(ide-obj-y)
 
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Thu May  9 15:21:05 2002
+++ b/drivers/ide/aec62xx.c	Thu May  9 15:21:05 2002
@@ -1,5 +1,6 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.09	June. 9, 2000
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ * Version 0.09	June. 9, 2000
  *
  * Copyright (C) 1999-2000	Andre Hedrick (andre@linux-ide.org)
  * May be copied or modified under the terms of the GNU General Public License
@@ -25,8 +26,9 @@
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
-#define DISPLAY_AEC62XX_TIMINGS
+#undef DISPLAY_AEC62XX_TIMINGS
 
 #ifndef HIGH_4
 #define HIGH_4(H)		((H)=(H>>4))
@@ -218,7 +220,7 @@
 	return 0x00;
 }
 
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
+static int aec6210_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -254,7 +256,7 @@
 	return(err);
 }
 
-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
+static int aec6260_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -291,7 +293,7 @@
 }
 
 
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
+static int aec62xx_tune_chipset(struct ata_device *drive, byte speed)
 {
 	if (drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
 		return ((int) aec6210_tune_chipset(drive, speed));
@@ -301,7 +303,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
+static int config_aec6210_chipset_for_dma(struct ata_device *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
 	struct ata_channel *hwif = drive->channel;
@@ -346,7 +348,7 @@
 						     0);
 }
 
-static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
+static int config_aec6260_chipset_for_dma(struct ata_device *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
 	struct ata_channel *hwif = drive->channel;
@@ -394,7 +396,7 @@
 						     0);
 }
 
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+static int config_chipset_for_dma(struct ata_device *drive, byte ultra)
 {
 	switch(drive->channel->pci_dev->device) {
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
@@ -409,7 +411,7 @@
 
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
+static void aec62xx_tune_drive(struct ata_device *drive, byte pio)
 {
 	byte speed;
 
@@ -430,7 +432,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
+static int config_drive_xfer_rate(struct ata_device *drive)
 {
 	struct hd_driveid *id = drive->id;
 	int on = 1;
@@ -490,7 +492,7 @@
 #endif
 #endif
 
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev)
+static unsigned int __init aec62xx_init_chipset(struct pci_dev *dev)
 {
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -503,21 +505,22 @@
 		bmide_dev = dev;
 		aec62xx_display_info = &aec62xx_get_info;
 	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+#endif
 
 	return dev->irq;
 }
 
-unsigned int __init ata66_aec62xx(struct ata_channel *hwif)
+static unsigned int __init aec62xx_ata66_check(struct ata_channel *ch)
 {
-	byte mask	= hwif->unit ? 0x02 : 0x01;
-	byte ata66	= 0;
+	u8 mask	= ch->unit ? 0x02 : 0x01;
+	u8 ata66 = 0;
+
+	pci_read_config_byte(ch->pci_dev, 0x49, &ata66);
 
-	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
 	return ((ata66 & mask) ? 0 : 1);
 }
 
-void __init ide_init_aec62xx(struct ata_channel *hwif)
+static void __init aec62xx_init_channel(struct ata_channel *hwif)
 {
 #ifdef CONFIG_AEC62XX_TUNING
 	hwif->tuneproc = aec62xx_tune_drive;
@@ -533,19 +536,58 @@
 #endif
 }
 
-void __init ide_dmacapable_aec62xx(struct ata_channel *hwif, unsigned long dmabase)
+static void __init aec62xx_init_dma(struct ata_channel *hwif, unsigned long dmabase)
 {
 #ifdef CONFIG_AEC62XX_TUNING
-	unsigned long flags;
-	byte reg54h = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
+	u8 reg54h = 0;
 
 	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
 	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->unit ? 0xF0 : 0x0F));
+#endif
+	ata_init_dma(hwif, dmabase);
+}
 
-	__restore_flags(flags);	/* local CPU only */
-#endif /* CONFIG_AEC62XX_TUNING */
-	ide_setup_dma(hwif, dmabase, 8);
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_ARTOP,
+		device: PCI_DEVICE_ID_ARTOP_ATP850UF,
+		init_chipset: aec62xx_init_chipset,
+		init_channel: aec62xx_init_channel,
+		init_dma: aec62xx_init_dma,
+		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
+		bootable: OFF_BOARD,
+		flags: ATA_F_SER | ATA_F_IRQ | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_ARTOP,
+		device: PCI_DEVICE_ID_ARTOP_ATP860,
+		init_chipset: aec62xx_init_chipset,
+		ata66_check: aec62xx_ata66_check,
+		init_channel: aec62xx_init_channel,
+		enablebits: { {0x00,0x00,0x00},	{0x00,0x00,0x00} },
+		bootable: NEVER_BOARD,
+		flags: ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_ARTOP,
+		device: PCI_DEVICE_ID_ARTOP_ATP860R,
+		init_chipset: aec62xx_init_chipset,
+		ata66_check: aec62xx_ata66_check,
+		init_channel: aec62xx_init_channel,
+		enablebits: { {0x4a,0x02,0x02},	{0x4a,0x04,0x04} },
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+};
+
+int __init init_aec62xx(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+	return 0;
 }
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/alim15x3.c	Thu May  9 15:21:08 2002
@@ -20,15 +20,16 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/init.h>
 
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
-#define DISPLAY_ALI_TIMINGS
+#undef DISPLAY_ALI_TIMINGS
 
 #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -239,7 +240,7 @@
 byte ali_proc = 0;
 static struct pci_dev *isa_dev;
 
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+static void ali15x3_tune_drive(struct ata_device *drive, byte pio)
 {
 	struct ata_timing *t;
 	struct ata_channel *hwif = drive->channel;
@@ -303,7 +304,7 @@
 	__restore_flags(flags);
 }
 
-static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
+static int ali15x3_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -352,13 +353,13 @@
 	return (err);
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive)
+static void config_chipset_for_pio(struct ata_device *drive)
 {
 	ali15x3_tune_drive(drive, 5);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
+static int config_chipset_for_dma(struct ata_device *drive, byte ultra33)
 {
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
@@ -408,7 +409,7 @@
 	return rval;
 }
 
-static byte ali15x3_can_ultra (ide_drive_t *drive)
+static byte ali15x3_can_ultra(struct ata_device *drive)
 {
 #ifndef CONFIG_WDC_ALI15X3
 	struct hd_driveid *id	= drive->id;
@@ -429,7 +430,7 @@
 	}
 }
 
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+static int ali15x3_config_drive_for_dma(struct ata_device *drive)
 {
 	struct hd_driveid *id = drive->id;
 	struct ata_channel *hwif = drive->channel;
@@ -505,7 +506,7 @@
 }
 #endif
 
-unsigned int __init pci_init_ali15x3(struct pci_dev *dev)
+static unsigned int __init ali15x3_init_chipset(struct pci_dev *dev)
 {
 	unsigned long fixdma_base = pci_resource_start(dev, 4);
 
@@ -543,7 +544,7 @@
  * of UDMA66 transfers. It doesn't check the drives.
  * But see note 2 below!
  */
-unsigned int __init ata66_ali15x3(struct ata_channel *hwif)
+static unsigned int __init ali15x3_ata66_check(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int ata66	= 0;
@@ -638,7 +639,7 @@
 	return(ata66);
 }
 
-void __init ide_init_ali15x3(struct ata_channel *hwif)
+static void __init ali15x3_init_channel(struct ata_channel *hwif)
 {
 #ifndef CONFIG_SPARC64
 	byte ideic, inmir;
@@ -694,13 +695,33 @@
 		hwif->autodma = 0;
 #else
 	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 }
 
-void __init ide_dmacapable_ali15x3(struct ata_channel *hwif, unsigned long dmabase)
+static void __init ali15x3_init_dma(struct ata_channel *ch, unsigned long dmabase)
 {
-	if ((dmabase) && (m5229_revision < 0x20)) {
+	if ((dmabase) && (m5229_revision < 0x20))
 		return;
-	}
-	ide_setup_dma(hwif, dmabase, 8);
+
+	ata_init_dma(ch, dmabase);
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_AL,
+        device: PCI_DEVICE_ID_AL_M5229,
+	init_chipset: ali15x3_init_chipset,
+	ata66_check: ali15x3_ata66_check,
+	init_channel: ali15x3_init_channel,
+	init_dma: ali15x3_init_dma,
+	enablebits: { {0x00,0x00,0x00}, {0x00,0x00,0x00} },
+	bootable: ON_BOARD
+};
+
+int __init init_ali15x3(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/amd74xx.c	Thu May  9 15:21:08 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * $Id: amd74xx.c,v 2.8 2002/03/14 11:52:20 vojtech Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik
@@ -42,9 +43,11 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #define AMD_IDE_ENABLE		(0x00 + amd_config->base)
 #define AMD_IDE_CONFIG		(0x01 + amd_config->base)
@@ -94,7 +97,7 @@
  * AMD /proc entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -298,7 +301,7 @@
  * and initialize its drive independent registers.
  */
 
-unsigned int __init pci_init_amd74xx(struct pci_dev *dev, const char *name)
+static unsigned int __init amd74xx_init_chipset(struct pci_dev *dev)
 {
 	unsigned char t;
 	unsigned int u;
@@ -384,7 +387,7 @@
  * Register /proc/ide/amd74xx entry
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 	if (!amd74xx_proc) {
 		amd_base = pci_resource_start(dev, 4);
 		bmide_dev = dev;
@@ -396,12 +399,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_amd74xx(struct ata_channel *hwif)
+static unsigned int __init amd74xx_ata66_check(struct ata_channel *hwif)
 {
 	return ((amd_enabled & amd_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_amd74xx(struct ata_channel *hwif)
+static void __init amd74xx_init_channel(struct ata_channel *hwif)
 {
 	int i;
 
@@ -432,9 +435,84 @@
 /*
  * We allow the BM-DMA driver only work on enabled interfaces.
  */
+static void __init amd74xx_init_dma(struct ata_channel *ch, unsigned long dmabase)
+{
+	if ((amd_enabled >> ch->unit) & 1)
+		ata_init_dma(ch, dmabase);
+}
+
 
-void __init ide_dmacapable_amd74xx(struct ata_channel *hwif, unsigned long dmabase)
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_AMD,
+		device: PCI_DEVICE_ID_AMD_COBRA_7401,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor:	PCI_VENDOR_ID_AMD,
+		device:	PCI_DEVICE_ID_AMD_VIPER_7409,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor:	PCI_VENDOR_ID_AMD,
+		device:	PCI_DEVICE_ID_AMD_VIPER_7411,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor:	PCI_VENDOR_ID_AMD,
+		device:	PCI_DEVICE_ID_AMD_OPUS_7441,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor:	PCI_VENDOR_ID_AMD,
+		device:	PCI_DEVICE_ID_AMD_8111_IDE,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor:	PCI_VENDOR_ID_NVIDIA,
+		device:	PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		init_chipset: amd74xx_init_chipset,
+		ata66_check: amd74xx_ata66_check,
+		init_channel: amd74xx_init_channel,
+		init_dma: amd74xx_init_dma,
+		enablebits: {{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		bootable: ON_BOARD
+	},
+};
+
+int __init init_amd74xx(void)
 {
-	if ((amd_enabled >> hwif->unit) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
 }
diff -Nru a/drivers/ide/buddha.c b/drivers/ide/buddha.c
--- a/drivers/ide/buddha.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/buddha.c	Thu May  9 15:21:06 2002
@@ -1,10 +1,10 @@
 /*
  *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
  *
- *	Copyright (C) 1997 by Geert Uytterhoeven
+ *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
  *
- *  This driver was written by based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at 
+ *  This driver was written based on the specifications in README.buddha and
+ *  the X-Surf info from Inside_XSurf.txt available at
  *  http://www.jschoenfeld.com
  *
  *  This file is subject to the terms and conditions of the GNU General Public
@@ -52,7 +52,7 @@
     BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
 };
 
-static const u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
      XSURF_BASE1, XSURF_BASE2
 };
 
@@ -97,7 +97,7 @@
     BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
 };
 
-static const int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
     XSURF_IRQ1, XSURF_IRQ2
 };
 
@@ -108,8 +108,9 @@
      *  Board information
      */
 
-enum BuddhaType_Enum {BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF};
-typedef enum BuddhaType_Enum BuddhaType;
+typedef enum BuddhaType_Enum {
+    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
 
 
     /*
@@ -175,15 +176,20 @@
 			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
 				continue;
 			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+				goto fail_base2;
+			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+				release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+				release_mem_region(board+XSURF_BASE1, 0x1000);
 				continue;
-			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE"))
-				continue;
+			}
 		}	  
 		buddha_board = ZTWO_VADDR(board);
 		
 		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
 		/* X-Surf doesn't have this.  IRQs are always on */
-		if(type != BOARD_XSURF) *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0;
+		if (type != BOARD_XSURF)
+			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
 		
 		for(i=0;i<buddha_num_hwifs;i++) {
 			if(type != BOARD_XSURF) {
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Thu May  9 15:21:05 2002
+++ b/drivers/ide/cmd64x.c	Thu May  9 15:21:05 2002
@@ -1,4 +1,6 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ * $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
  *
  * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
  *
@@ -18,12 +20,13 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/hdreg.h>
-#include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #ifndef SPLIT_BYTE
 #define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
@@ -79,7 +82,7 @@
 #define UDIDETCR1	0x7B
 #define DTPR1		0x7C
 
-#define DISPLAY_CMD64X_TIMINGS
+#undef DISPLAY_CMD64X_TIMINGS
 
 #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -1070,19 +1073,19 @@
 		bmide_dev = dev;
 		cmd64x_display_info = &cmd64x_get_info;
 	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+#endif
 
 	return 0;
 }
 
-unsigned int __init pci_init_cmd64x(struct pci_dev *dev)
+static unsigned int __init cmd64x_init_chipset(struct pci_dev *dev)
 {
 	if (dev->device == PCI_DEVICE_ID_CMD_680)
 		return cmd680_pci_init (dev);
 	return cmd64x_pci_init (dev);
 }
 
-unsigned int cmd680_ata66(struct ata_channel *hwif)
+static unsigned int cmd680_ata66(struct ata_channel *hwif)
 {
 	byte ata66	= 0;
 	byte addr_mask	= (hwif->unit) ? 0xB0 : 0xA0;
@@ -1091,7 +1094,7 @@
 	return (ata66 & 0x01) ? 1 : 0;
 }
 
-unsigned int cmd64x_ata66(struct ata_channel *hwif)
+static unsigned int cmd64x_ata66(struct ata_channel *hwif)
 {
 	byte ata66 = 0;
 	byte mask = (hwif->unit) ? 0x02 : 0x01;
@@ -1100,7 +1103,7 @@
 	return (ata66 & mask) ? 1 : 0;
 }
 
-unsigned int __init ata66_cmd64x(struct ata_channel *hwif)
+static unsigned int __init cmd64x_ata66_check(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	if (dev->device == PCI_DEVICE_ID_CMD_680)
@@ -1108,7 +1111,7 @@
 	return cmd64x_ata66(hwif);
 }
 
-void __init ide_init_cmd64x(struct ata_channel *hwif)
+static void __init cmd64x_init_channel(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int class_rev;
@@ -1158,5 +1161,64 @@
 	}
 
 	hwif->highmem = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
+}
+
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_643,
+		init_chipset: cmd64x_init_chipset,
+		init_channel: cmd64x_init_channel,
+		bootable: ON_BOARD,
+	},
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_646,
+		init_chipset: cmd64x_init_chipset,
+		init_channel: cmd64x_init_channel,
+		enablebits: {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		bootable: ON_BOARD,
+		flags: ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_648,
+		init_chipset: cmd64x_init_chipset,
+		ata66_check: cmd64x_ata66_check,
+		init_channel: cmd64x_init_channel,
+		bootable: ON_BOARD,
+		flags: ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_649,
+		init_chipset: cmd64x_init_chipset,
+		ata66_check: cmd64x_ata66_check,
+		init_channel: cmd64x_init_channel,
+		bootable: ON_BOARD,
+		flags: ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_680,
+		init_chipset: cmd64x_init_chipset,
+		ata66_check: cmd64x_ata66_check,
+		init_channel: cmd64x_init_channel,
+		bootable: ON_BOARD,
+		flags: ATA_F_DMA
+	},
+};
+
+int __init init_cmd64x(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
 }
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/cs5530.c	Thu May  9 15:21:08 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
  *
  * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
@@ -24,12 +25,14 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
-#define DISPLAY_CS5530_TIMINGS
+#undef DISPLAY_CS5530_TIMINGS
 
 #if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -243,7 +246,7 @@
 /*
  * Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
-unsigned int __init pci_init_cs5530(struct pci_dev *dev)
+static unsigned int __init pci_init_cs5530(struct pci_dev *dev)
 {
 	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 	unsigned short pcicmd = 0;
@@ -334,7 +337,7 @@
  * This gets invoked by the IDE driver once for each channel,
  * and performs channel-specific pre-initialization before drive probing.
  */
-void __init ide_init_cs5530(struct ata_channel *hwif)
+static void __init ide_init_cs5530(struct ata_channel *hwif)
 {
 	hwif->serialized = 1;
 	if (!hwif->dma_base) {
@@ -363,4 +366,22 @@
 				hwif->drives[1].autotune = 1;	/* needs autotuning later */
 		}
 	}
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_CYRIX,
+	device: PCI_DEVICE_ID_CYRIX_5530_IDE,
+	init_chipset: pci_init_cs5530,
+	init_channel: ide_init_cs5530,
+	bootable: ON_BOARD,
+	flags: ATA_F_DMA
+};
+
+int __init init_cs5530(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/cy82c693.c	Thu May  9 15:21:04 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
  *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
@@ -48,12 +49,13 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 /* the current version */
 #define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
@@ -383,7 +385,7 @@
  * the device prior to INIT.
  */
 
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
+static unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
 {
 #ifdef CY82C693_SETDMA_CLOCK
         byte data;
@@ -419,18 +421,18 @@
         OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
         OUT_BYTE(data, CY82_DATA_PORT);
 
-#if CY82C693_DEBUG_INFO
+# if CY82C693_DEBUG_INFO
 	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", dev->name, data);
-#endif /* CY82C693_DEBUG_INFO */
+# endif
 
-#endif /* CY82C693_SETDMA_CLOCK */
+#endif
 	return 0;
 }
 
 /*
  * the init function - called for each ide channel once
  */
-void __init ide_init_cy82c693(struct ata_channel *hwif)
+static void __init ide_init_cy82c693(struct ata_channel *hwif)
 {
 	hwif->chipset = ide_cy82c693;
 	hwif->tuneproc = cy82c693_tune_drive;
@@ -445,5 +447,23 @@
 		if (!noautodma)
 			hwif->autodma = 1;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_CONTAQ,
+	device: PCI_DEVICE_ID_CONTAQ_82C693,
+	init_chipset: pci_init_cy82c693,
+	init_channel: ide_init_cy82c693,
+	bootable: ON_BOARD,
+	flags: ATA_F_DMA
+};
+
+int __init init_cy82c693(void)
+{
+	ata_register_chipset(&chipset);
+
+	return 0;
 }
diff -Nru a/drivers/ide/falconide.c b/drivers/ide/falconide.c
--- a/drivers/ide/falconide.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/falconide.c	Thu May  9 15:21:06 2002
@@ -7,7 +7,7 @@
  *  License.  See the file COPYING in the main directory of this archive for
  *  more details.
  */
-#include <linux/config.h>
+
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Thu May  9 15:21:02 2002
+++ b/drivers/ide/hpt34x.c	Thu May  9 15:21:02 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
  *
  * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
@@ -40,10 +41,12 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+# define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
 #endif
 
 #define HPT343_DEBUG_DRIVE_INFO		0
@@ -373,7 +376,7 @@
  */
 #define	HPT34X_PCI_INIT_REG		0x80
 
-unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
+static unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
 {
 	int i = 0;
 	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
@@ -420,15 +423,15 @@
 		bmide_dev = dev;
 		hpt34x_display_info = &hpt34x_get_info;
 	}
-#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+#endif
 
 	return dev->irq;
 }
 
-void __init ide_init_hpt34x(struct ata_channel *hwif)
+static void __init ide_init_hpt34x(struct ata_channel *hwif)
 {
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->tuneproc = hpt34x_tune_drive;
+	hwif->speedproc = hpt34x_tune_chipset;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
@@ -449,9 +452,28 @@
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
+#else
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_TTI,
+	device: PCI_DEVICE_ID_TTI_HPT343,
+	init_chipset: pci_init_hpt34x,
+	init_channel:	ide_init_hpt34x,
+	bootable: NEVER_BOARD,
+	extra: 16,
+	flags: ATA_F_NOADMA | ATA_F_DMA
+};
+
+int __init init_hpt34x(void)
+{
+	ata_register_chipset(&chipset);
+
+	return 0;
 }
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Thu May  9 15:21:02 2002
+++ b/drivers/ide/hpt366.c	Thu May  9 15:21:02 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
  *
  * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
@@ -13,10 +14,10 @@
  * Note that final HPT370 support was done by force extraction of GPL.
  *
  * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma 
+ * - the HPT370's state machine can get confused. reset it before each dma
  *   xfer to prevent that from happening.
  * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma. 
+ * - check for busmaster state at end of dma.
  * - use new highpoint timings.
  * - detect bus speed using highpoint register.
  * - use pll if we don't have a clock table. added a 66MHz table that's
@@ -25,21 +26,23 @@
  *   pci clocks as the chip can glitch in those cases. the highpoint
  *   approved workaround slows everything down too much to be useful. in
  *   addition, we would have to serialize access to each chip.
- * 	Adrian Sun <a.sun@sun.com>
+ *	Adrian Sun <a.sun@sun.com>
  *
  * add drive timings for 66MHz PCI bus,
  * fix ATA Cable signal detection, fix incorrect /proc info
  * add /proc display for per-drive PIO/DMA/UDMA mode and
  * per-channel ATA-33/66 Cable detect.
- * 	Duncan Laurie <void@sun.com>
+ *	Duncan Laurie <void@sun.com>
  *
  * fixup /proc output for multiple controllers
  *	Tim Hockin <thockin@sun.com>
  *
- * On hpt366: 
+ * On hpt366:
  * Reset the hpt366 on error, reset on dma
  * Fix disabling Fast Interrupt hpt366.
- * 	Mike Waychison <crlf@sun.com>
+ *	Mike Waychison <crlf@sun.com>
+ *
+ * 02 May 2002 - HPT374 support (Andre Hedrick <andre@linux-ide.org>)
  */
 
 #include <linux/config.h>
@@ -62,8 +65,10 @@
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
-#define DISPLAY_HPT366_TIMINGS
+
+#undef DISPLAY_HPT366_TIMINGS
 
 /* various tuning parameters */
 #define HPT_RESET_STATE_ENGINE
@@ -75,7 +80,7 @@
 #include <linux/proc_fs.h>
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-const char *quirk_drives[] = {
+static const char *quirk_drives[] = {
 	"QUANTUM FIREBALLlct08 08",
 	"QUANTUM FIREBALLP KA6.4",
 	"QUANTUM FIREBALLP LM20.4",
@@ -83,7 +88,7 @@
         NULL
 };
 
-const char *bad_ata100_5[] = {
+static const char *bad_ata100_5[] = {
 	"IBM-DTLA-307075",
 	"IBM-DTLA-307060",
 	"IBM-DTLA-307045",
@@ -102,7 +107,7 @@
 	NULL
 };
 
-const char *bad_ata66_4[] = {
+static const char *bad_ata66_4[] = {
 	"IBM-DTLA-307075",
 	"IBM-DTLA-307060",
 	"IBM-DTLA-307045",
@@ -121,12 +126,12 @@
 	NULL
 };
 
-const char *bad_ata66_3[] = {
+static const char *bad_ata66_3[] = {
 	"WDC AC310200R",
 	NULL
 };
 
-const char *bad_ata33[] = {
+static const char *bad_ata33[] = {
 	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
 	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
 	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
@@ -138,7 +143,7 @@
 };
 
 struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
+	u8		xfer_speed;
 	unsigned int	chipset_settings;
 };
 
@@ -164,9 +169,8 @@
  *        PIO.
  * 31     FIFO enable.
  */
-struct chipset_bus_clock_list_entry forty_base [] = {
-
-	{	XFER_UDMA_4,    0x900fd943	},
+static struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x900fd943	},
 	{	XFER_UDMA_3,	0x900ad943	},
 	{	XFER_UDMA_2,	0x900bd943	},
 	{	XFER_UDMA_1,	0x9008d943	},
@@ -184,8 +188,7 @@
 	{	0,		0x0120d9d9	}
 };
 
-struct chipset_bus_clock_list_entry thirty_three_base [] = {
-
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
 	{	XFER_UDMA_4,	0x90c9a731	},
 	{	XFER_UDMA_3,	0x90cfa731	},
 	{	XFER_UDMA_2,	0x90caa731	},
@@ -204,7 +207,7 @@
 	{	0,		0x0120a7a7	}
 };
 
-struct chipset_bus_clock_list_entry twenty_five_base [] = {
+static struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
 
 	{	XFER_UDMA_4,	0x90c98521	},
 	{	XFER_UDMA_3,	0x90cf8521	},
@@ -226,7 +229,7 @@
 
 #if 1
 /* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
         {       XFER_UDMA_5,    0x12446231      },
         {       XFER_UDMA_4,    0x12446231      },
         {       XFER_UDMA_3,    0x126c6231      },
@@ -247,7 +250,7 @@
 };
 
 /* 2x 33MHz timings */
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
 	{       XFER_UDMA_5,    0x1488e673       },
 	{       XFER_UDMA_4,    0x1488e673       },
 	{       XFER_UDMA_3,    0x1498e673       },
@@ -256,7 +259,7 @@
 	{       XFER_UDMA_0,    0x14a0e73f       },
 
 	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_1,  0x2480fa77       },
 	{       XFER_MW_DMA_0,  0x2480fb3f       },
 
 	{       XFER_PIO_4,     0x0c82be73       },
@@ -268,7 +271,7 @@
 };
 #else
 /* from highpoint documentation. these are old values */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
 	{	XFER_UDMA_5,	0x16454e31	},
 	{	XFER_UDMA_4,	0x16454e31	},
 	{	XFER_UDMA_3,	0x166d4e31	},
@@ -288,18 +291,18 @@
 	{	0,		0x06514e57	}
 };
 
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
 	{       XFER_UDMA_5,    0x14846231      },
 	{       XFER_UDMA_4,    0x14886231      },
 	{       XFER_UDMA_3,    0x148c6231      },
 	{       XFER_UDMA_2,    0x148c6231      },
 	{       XFER_UDMA_1,    0x14906231      },
 	{       XFER_UDMA_0,    0x14986231      },
-	
+
 	{       XFER_MW_DMA_2,  0x26514e21      },
 	{       XFER_MW_DMA_1,  0x26514e33      },
 	{       XFER_MW_DMA_0,  0x26514e97      },
-	
+
 	{       XFER_PIO_4,     0x06514e21      },
 	{       XFER_PIO_3,     0x06514e22      },
 	{       XFER_PIO_2,     0x06514e33      },
@@ -309,7 +312,7 @@
 };
 #endif
 
-struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+static struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
 	{       XFER_UDMA_5,    0x12848242      },
 	{       XFER_UDMA_4,    0x12ac8242      },
 	{       XFER_UDMA_3,    0x128c8242      },
@@ -329,6 +332,144 @@
 	{       0,              0x0ac1f48a      }
 };
 
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+static struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x0a81f443	}
+};
+
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x06814e93	}
+};
+
+#if 0
+static struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
 #define HPT366_DEBUG_DRIVE_INFO		0
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
@@ -345,8 +486,12 @@
 
 static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
 static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
-byte hpt366_proc = 0;
-extern char *ide_xfer_verbose (byte xfer_rate);
+static unsigned int pci_rev3_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev5_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev7_check_hpt3xx(struct pci_dev *dev);
+
+static u8 hpt366_proc = 0;
+extern char *ide_xfer_verbose(u8 xfer_rate);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
@@ -355,11 +500,13 @@
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p	= buffer;
-	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"??",  "374" };
 	int i;
 
 	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370\n");
+		"HighPoint HPT366/368/370/372/374\n");
 	for (i = 0; i < n_hpt_devs; i++) {
 		struct pci_dev *dev = hpt_devs[i];
 		unsigned short iobase = dev->resource[4].start;
@@ -384,7 +531,7 @@
 			(c0 & 0x80) ? "no" : "yes",
 			(c1 & 0x80) ? "no" : "yes");
 
-		if (pci_rev_check_hpt3xx(dev)) {
+		if (pci_rev3_check_hpt3xx(dev)) {
 			u8 cbl;
 			cbl = inb_p(iobase + 0x7b);
 			outb_p(cbl | 1, iobase + 0x7b);
@@ -408,7 +555,7 @@
 
 		{
 			u8 c2, c3;
-			/* older revs don't have these registers mapped 
+			/* older revs don't have these registers mapped
 			 * into io space */
 			pci_read_config_byte(dev, 0x43, &c0);
 			pci_read_config_byte(dev, 0x47, &c1);
@@ -417,7 +564,7 @@
 
 			p += sprintf(p, "Mode:           %s             %s"
 					"           %s              %s\n",
-				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
 					(c0 & 0x80) ? "PIO " : "off ",
 				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
 					(c1 & 0x80) ? "PIO " : "off ",
@@ -428,11 +575,15 @@
 		}
 	}
 	p += sprintf(p, "\n");
-	
+
 	return p-buffer;/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+/*
+ * fixme: it really needs to be a switch.
+ */
+
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
 	unsigned int class_rev;
@@ -449,7 +600,31 @@
 	return ((int) (class_rev > 0x01) ? 1 : 0);
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+static unsigned int pci_rev3_check_hpt3xx (struct pci_dev *dev)
+{
+	unsigned int class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev > 0x02) ? 1 : 0);
+}
+
+static unsigned int pci_rev5_check_hpt3xx (struct pci_dev *dev)
+{
+	unsigned int class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev > 0x04) ? 1 : 0);
+}
+
+static unsigned int pci_rev7_check_hpt3xx (struct pci_dev *dev)
+{
+	unsigned int class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev > 0x06) ? 1 : 0);
+}
+
+static int check_in_drive_lists(struct ata_device *drive, const char **list)
 {
 	struct hd_driveid *id = drive->id;
 
@@ -469,7 +644,7 @@
 	return 0;
 }
 
-static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list(byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
@@ -478,8 +653,9 @@
 	return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
+static void hpt366_tune_chipset(struct ata_device *drive, byte speed)
 {
+	struct pci_dev *dev	= drive->channel->pci_dev;
 	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	byte regfast		= (drive->channel->unit) ? 0x55 : 0x51;
 			/*
@@ -491,32 +667,15 @@
 	byte drive_fast		= 0;
 
 	/*
-	 * Disable the "fast interrupt" prediction. 
+	 * Disable the "fast interrupt" prediction.
 	 */
-	pci_read_config_byte(drive->channel->pci_dev, regfast, &drive_fast);
+	pci_read_config_byte(dev, regfast, &drive_fast);
 	if (drive_fast & 0x02)
-		pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast & ~0x20);
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
 
-	pci_read_config_dword(drive->channel->pci_dev, regtime, &reg1);
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
-			break;
-		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
-			break;
-		default:
-		case 7:
-			reg2 = pci_bus_clock_list(speed, thirty_three_base);
-			break;
-	}
-#if 0
-	/* this is a nice idea ... */
-	list_conf = pci_bus_clock_list(speed,
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-#endif
+	pci_read_config_dword(dev, regtime, &reg1);
+	reg2 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) dev->sysdata);
 	/*
 	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
 	 */
@@ -524,13 +683,18 @@
 		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
 	} else {
 		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
+	}
 	reg2 &= ~0x80000000;
 
-	pci_write_config_dword(drive->channel->pci_dev, regtime, reg2);
+	pci_write_config_dword(dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
+static void hpt368_tune_chipset(struct ata_device *drive, byte speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset(struct ata_device *drive, byte speed)
 {
 	byte regfast		= (drive->channel->unit) ? 0x55 : 0x51;
 	unsigned int list_conf	= 0;
@@ -542,7 +706,7 @@
 
 	/*
 	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
 	 */
 	pci_read_config_byte(dev, regfast, &drive_fast);
 	new_fast = drive_fast;
@@ -559,13 +723,13 @@
 	if (new_fast != drive_fast)
 		pci_write_config_byte(drive->channel->pci_dev, regfast, new_fast);
 
-	list_conf = pci_bus_clock_list(speed, 
+	list_conf = pci_bus_clock_list(speed,
 				       (struct chipset_bus_clock_list_entry *)
 				       dev->sysdata);
 
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	
+
 	if (speed < XFER_MW_DMA_0) {
 		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
 	}
@@ -573,7 +737,40 @@
 	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
+static void hpt372_tune_chipset(struct ata_device *drive, byte speed)
+{
+	byte regfast		= (drive->channel->unit) ? 0x55 : 0x51;
+	unsigned int list_conf	= 0;
+	unsigned int drive_conf	= 0;
+	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte drive_fast		= 0;
+	struct pci_dev *dev	= drive->channel->pci_dev;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast);
+
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					dev->sysdata);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset(struct ata_device *drive, byte speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
+static int hpt3xx_tune_chipset(struct ata_device *drive, byte speed)
 {
 	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return -1;
@@ -581,16 +778,22 @@
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 
-	if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
+	if (pci_rev7_check_hpt3xx(drive->channel->pci_dev)) {
+		hpt374_tune_chipset(drive, speed);
+	} else if (pci_rev5_check_hpt3xx(drive->channel->pci_dev)) {
+		hpt372_tune_chipset(drive, speed);
+	} else if (pci_rev3_check_hpt3xx(drive->channel->pci_dev)) {
 		hpt370_tune_chipset(drive, speed);
-        } else {
+	} else if (pci_rev2_check_hpt3xx(drive->channel->pci_dev)) {
+		hpt368_tune_chipset(drive, speed);
+	} else {
                 hpt366_tune_chipset(drive, speed);
         }
 	drive->current_speed = speed;
 	return ((int) ide_config_drive_speed(drive, speed));
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive)
+static void config_chipset_for_pio(struct ata_device *drive)
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
@@ -628,7 +831,7 @@
 	(void) hpt3xx_tune_chipset(drive, speed);
 }
 
-static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
+static void hpt3xx_tune_drive(struct ata_device *drive, byte pio)
 {
 	byte speed;
 	switch(pio) {
@@ -653,20 +856,28 @@
  * check_in_drive_lists(drive, bad_ata33)
  *
  */
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(struct ata_device *drive)
 {
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
 	byte ultra66		= eighty_ninty_three(drive);
 	int  rval;
 
+	config_chipset_for_pio(drive);
+	drive->init_speed = 0;
+
 	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return 0;
 
-	if ((id->dma_ultra & 0x0020) &&
+	if ((id->dma_ultra & 0x0040) &&
+	    (pci_rev5_check_hpt3xx(drive->channel->pci_dev)) &&
+	    (ultra66)) {
+		speed = XFER_UDMA_6;
+	} else if ((id->dma_ultra & 0x0020) &&
 	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
 	    (HPT370_ALLOW_ATA100_5) &&
 	    (pci_rev_check_hpt3xx(drive->channel->pci_dev)) &&
+	    (pci_rev3_check_hpt3xx(drive->channel->pci_dev)) &&
 	    (ultra66)) {
 		speed = XFER_UDMA_5;
 	} else if ((id->dma_ultra & 0x0010) &&
@@ -699,19 +910,20 @@
 
 	(void) hpt3xx_tune_chipset(drive, speed);
 
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? 1 :
+	rval = (int)(	((id->dma_ultra >> 14) & 3) ? 1 :
+			((id->dma_ultra >> 11) & 7) ? 1 :
 			((id->dma_ultra >> 8) & 7) ? 1 :
 			((id->dma_mword >> 8) & 7) ? 1 :
 						     0);
 	return rval;
 }
 
-int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(struct ata_device *drive)
 {
 	return ((int) check_in_drive_lists(drive, quirk_drives));
 }
 
-void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(struct ata_device *drive)
 {
 	if (drive->quirk_list) {
 		/* drives in the quirk_list may not like intr setups/cleanups */
@@ -720,14 +932,16 @@
 	}
 }
 
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(struct ata_device *drive, int mask)
 {
+	struct pci_dev *dev = drive->channel->pci_dev;
+
 	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
+		if (pci_rev3_check_hpt3xx(dev)) {
 			byte reg5a = 0;
-			pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5a);
+			pci_read_config_byte(dev, 0x5a, &reg5a);
 			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(drive->channel->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
 		} else {
 			if (mask) {
 				disable_irq(drive->channel->irq);
@@ -741,7 +955,7 @@
 	}
 }
 
-static int config_drive_xfer_rate (ide_drive_t *drive)
+static int config_drive_xfer_rate(struct ata_device *drive)
 {
 	struct hd_driveid *id = drive->id;
 	int on = 1;
@@ -756,7 +970,7 @@
 		on = 0;
 		verbose = 0;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				on = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) &&
@@ -897,11 +1111,38 @@
 	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
 }
 
-
 static int hpt370_dmaproc(struct ata_device *drive)
 {
 	return config_drive_xfer_rate(drive);
 }
+
+static int hpt374_udma_stop(struct ata_device *drive)
+{
+	struct ata_channel *ch = drive->channel;
+	struct pci_dev *dev = drive->channel->pci_dev;
+	unsigned long dma_base = ch->dma_base;
+	u8 mscreg = ch->unit ? 0x54 : 0x50;
+	u8 dma_stat;
+	u8 bwsr_mask = ch->unit ? 0x02 : 0x01;
+	u8 bwsr_stat, msc_stat;
+	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+	pci_read_config_byte(dev, mscreg, &msc_stat);
+	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+	        pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+
+	drive->waiting_for_dma = 0;
+	outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
+	dma_stat = inb(dma_base+2);		/* get DMA status */
+	outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
+	udma_destroy_table(ch);			/* purge DMA mappings */
+
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
+}
+
+static int hpt374_dmaproc(struct ata_device *drive)
+{
+	return config_drive_xfer_rate(drive);
+}
 #endif
 
 /*
@@ -909,7 +1150,7 @@
  * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
  * HOTSWAP ATA Infrastructure.
  */
-void hpt3xx_reset (ide_drive_t *drive)
+static void hpt3xx_reset(struct ata_device *drive)
 {
 #if 0
 	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
@@ -923,19 +1164,19 @@
 }
 
 #if 0
-static int hpt3xx_tristate (ide_drive_t * drive, int state)
+static int hpt3xx_tristate(struct ata_device * drive, int state)
 {
-	struct ata_channel *hwif	= drive->channel;
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte reset		= (hwif->unit) ? 0x80 : 0x40;
-	byte state_reg		= (hwif->unit) ? 0x57 : 0x53;
+	struct ata_channel *ch	= drive->channel;
+	struct pci_dev *dev	= ch->pci_dev;
+	byte reset		= (ch->unit) ? 0x80 : 0x40;
+	byte state_reg		= (ch->unit) ? 0x57 : 0x53;
 	byte reg59h		= 0;
 	byte regXXh		= 0;
 
-	if (!hwif)
+	if (!ch)
 		return -EINVAL;
 
-//	hwif->bus_state = state;
+//	ch->bus_state = state;
 
 	pci_read_config_byte(dev, 0x59, &reg59h);
 	pci_read_config_byte(dev, state_reg, &regXXh);
@@ -953,7 +1194,7 @@
 }
 #endif
 
-/* 
+/*
  * set/get power state for a drive.
  * turning the power off does the following things:
  *   1) soft-reset the drive
@@ -962,71 +1203,71 @@
  * when we turn things back on, we need to re-initialize things.
  */
 #define TRISTATE_BIT  0x8000
-static int hpt370_busproc(ide_drive_t * drive, int state)
+static int hpt370_busproc(struct ata_device * drive, int state)
 {
-	struct ata_channel *hwif = drive->channel;
-	byte tristate, resetmask, bus_reg;
+	struct ata_channel *ch = drive->channel;
+	u8 tristate, resetmask, bus_reg;
 	u16 tri_reg;
 
-	if (!hwif)
+	if (!ch)
 		return -EINVAL;
 
-	hwif->bus_state = state;
+	ch->bus_state = state;
 
-	if (hwif->unit) { 
+	if (ch->unit) {
 		/* secondary channel */
 		tristate = 0x56;
-		resetmask = 0x80; 
-	} else { 
+		resetmask = 0x80;
+	} else {
 		/* primary channel */
 		tristate = 0x52;
 		resetmask = 0x40;
 	}
 
 	/* grab status */
-	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
-	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+	pci_read_config_word(ch->pci_dev, tristate, &tri_reg);
+	pci_read_config_byte(ch->pci_dev, 0x59, &bus_reg);
 
 	/* set the state. we don't set it if we don't need to do so.
 	 * make sure that the drive knows that it has failed if it's off */
 	switch (state) {
 	case BUSSTATE_ON:
-		hwif->drives[0].failures = 0;
-		hwif->drives[1].failures = 0;
+		ch->drives[0].failures = 0;
+		ch->drives[1].failures = 0;
 		if ((bus_reg & resetmask) == 0)
 			return 0;
 		tri_reg &= ~TRISTATE_BIT;
 		bus_reg &= ~resetmask;
 		break;
 	case BUSSTATE_OFF:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		ch->drives[0].failures = ch->drives[0].max_failures + 1;
+		ch->drives[1].failures = ch->drives[1].max_failures + 1;
 		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
 			return 0;
 		tri_reg &= ~TRISTATE_BIT;
 		bus_reg |= resetmask;
 		break;
 	case BUSSTATE_TRISTATE:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		ch->drives[0].failures = ch->drives[0].max_failures + 1;
+		ch->drives[1].failures = ch->drives[1].max_failures + 1;
 		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
 			return 0;
 		tri_reg |= TRISTATE_BIT;
 		bus_reg |= resetmask;
 		break;
 	}
-	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
-	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+	pci_write_config_byte(ch->pci_dev, 0x59, bus_reg);
+	pci_write_config_word(ch->pci_dev, tristate, tri_reg);
 
 	return 0;
 }
 
-static void __init init_hpt370(struct pci_dev *dev)
+static void __init hpt37x_init(struct pci_dev *dev)
 {
 	int adjust, i;
 	u16 freq;
 	u32 pll;
-	byte reg5bh;
+	u8 reg5bh;
 
 	/*
 	 * default to pci clock. make sure MA15/16 are set to output
@@ -1035,27 +1276,53 @@
 	pci_write_config_byte(dev, 0x5b, 0x23);
 
 	/*
-	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * set up the PLL. we need to adjust it so that it's stable.
 	 * freq = Tpll * 192 / Tpci
 	 */
 	pci_read_config_word(dev, 0x78, &freq);
 	freq &= 0x1FF;
 	if (freq < 0x9c) {
 		pll = F_LOW_PCI_33;
-		dev->sysdata = (void *) thirty_three_base_hpt370;
-		printk("HPT370: using 33MHz PCI clock\n");
+		if (pci_rev7_check_hpt3xx(dev)) {
+			dev->sysdata = (void *) thirty_three_base_hpt374;
+		} else if (pci_rev5_check_hpt3xx(dev)) {
+			dev->sysdata = (void *) thirty_three_base_hpt372;
+		} else if (dev->device == PCI_DEVICE_ID_TTI_HPT372) {
+			dev->sysdata = (void *) thirty_three_base_hpt372;
+		} else {
+			dev->sysdata = (void *) thirty_three_base_hpt370;
+		}
+		printk("HPT37X: using 33MHz PCI clock\n");
 	} else if (freq < 0xb0) {
 		pll = F_LOW_PCI_40;
 	} else if (freq < 0xc8) {
 		pll = F_LOW_PCI_50;
-		dev->sysdata = (void *) fifty_base_hpt370;
-		printk("HPT370: using 50MHz PCI clock\n");
+		if (pci_rev7_check_hpt3xx(dev)) {
+	//		dev->sysdata = (void *) fifty_base_hpt374;
+			BUG();
+		} else if (pci_rev5_check_hpt3xx(dev)) {
+			dev->sysdata = (void *) fifty_base_hpt372;
+		} else if (dev->device == PCI_DEVICE_ID_TTI_HPT372) {
+			dev->sysdata = (void *) fifty_base_hpt372;
+		} else {
+			dev->sysdata = (void *) fifty_base_hpt370;
+		}
+		printk("HPT37X: using 50MHz PCI clock\n");
 	} else {
 		pll = F_LOW_PCI_66;
-		dev->sysdata = (void *) sixty_six_base_hpt370;
-		printk("HPT370: using 66MHz PCI clock\n");
+		if (pci_rev7_check_hpt3xx(dev)) {
+	//		dev->sysdata = (void *) sixty_six_base_hpt374;
+			BUG();
+		} else if (pci_rev5_check_hpt3xx(dev)) {
+			dev->sysdata = (void *) sixty_six_base_hpt372;
+		} else if (dev->device == PCI_DEVICE_ID_TTI_HPT372) {
+			dev->sysdata = (void *) sixty_six_base_hpt372;
+		} else {
+			dev->sysdata = (void *) sixty_six_base_hpt370;
+		}
+		printk("HPT37X: using 66MHz PCI clock\n");
 	}
-	
+
 	/*
 	 * only try the pll if we don't have a table for the clock
 	 * speed that we're running at. NOTE: the internal PLL will
@@ -1063,9 +1330,9 @@
 	 * don't like to use the PLL because it will cause glitches
 	 * on PRST/SRST when the HPT state engine gets reset.
 	 */
-	if (dev->sysdata) 
-		goto init_hpt370_done;
-	
+	if (dev->sysdata)
+		goto init_hpt37X_done;
+
 	/*
 	 * adjust PLL based upon PCI clock, enable it, and wait for
 	 * stabilization.
@@ -1082,18 +1349,27 @@
 			if (reg5bh & 0x80) {
 				/* spin looking for the clock to destabilize */
 				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b, 
+					pci_read_config_byte(dev, 0x5b,
 							     &reg5bh);
 					if ((reg5bh & 0x80) == 0)
 						goto pll_recal;
 				}
 				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c, 
+				pci_write_config_dword(dev, 0x5c,
 						       pll & ~0x100);
 				pci_write_config_byte(dev, 0x5b, 0x21);
-				dev->sysdata = (void *) fifty_base_hpt370;
-				printk("HPT370: using 50MHz internal PLL\n");
-				goto init_hpt370_done;
+				if (pci_rev7_check_hpt3xx(dev)) {
+	//	dev->sysdata = (void *) fifty_base_hpt374;
+					BUG();
+				} else if (pci_rev5_check_hpt3xx(dev)) {
+					dev->sysdata = (void *) fifty_base_hpt372;
+				} else if (dev->device == PCI_DEVICE_ID_TTI_HPT372) {
+					dev->sysdata = (void *) fifty_base_hpt372;
+				} else {
+					dev->sysdata = (void *) fifty_base_hpt370;
+				}
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
 			}
 		}
 pll_recal:
@@ -1101,18 +1377,46 @@
 			pll -= (adjust >> 1);
 		else
 			pll += (adjust >> 1);
-	} 
+	}
 
-init_hpt370_done:
+init_hpt37X_done:
 	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
-	pci_write_config_byte(dev, 0x54, 0x37); 
+	pci_write_config_byte(dev, 0x50, 0x37);
+	pci_write_config_byte(dev, 0x54, 0x37);
 	udelay(100);
 }
 
-unsigned int __init pci_init_hpt366(struct pci_dev *dev)
+static void __init hpt366_init(struct pci_dev *dev)
 {
-	byte test = 0;
+	unsigned int reg1	= 0;
+	u8 drive_fast		= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			dev->sysdata = (void *) forty_base_hpt366;
+			break;
+		case 9:
+			dev->sysdata = (void *) twenty_five_base_hpt366;
+			break;
+		case 7:
+		default:
+			dev->sysdata = (void *) thirty_three_base_hpt366;
+			break;
+	}
+}
+
+static unsigned int __init hpt366_init_chipset(struct pci_dev *dev)
+{
+	u8 test = 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start)
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -1133,8 +1437,10 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-	if (pci_rev_check_hpt3xx(dev))
-		init_hpt370(dev);
+	if (pci_rev3_check_hpt3xx(dev))
+		hpt37x_init(dev);
+	else
+		hpt366_init(dev);
 
 	if (n_hpt_devs < HPT366_MAX_DEVS)
 		hpt_devs[n_hpt_devs++] = dev;
@@ -1149,105 +1455,161 @@
 	return dev->irq;
 }
 
-unsigned int __init ata66_hpt366(struct ata_channel *hwif)
+static unsigned int __init hpt366_ata66_check(struct ata_channel *ch)
 {
-	byte ata66	= 0;
-	byte regmask	= (hwif->unit) ? 0x01 : 0x02;
+	u8 ata66	= 0;
+	u8 regmask	= (ch->unit) ? 0x01 : 0x02;
 
-	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+	pci_read_config_byte(ch->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
 		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
+		PCI_FUNC(ch->pci_dev->devfn));
 #endif
 	return ((ata66 & regmask) ? 0 : 1);
 }
 
-void __init ide_init_hpt366(struct ata_channel *hwif)
+static void __init hpt366_init_channel(struct ata_channel *ch)
 {
-	int hpt_rev;
-
-	hwif->tuneproc	= &hpt3xx_tune_drive;
-	hwif->speedproc	= &hpt3xx_tune_chipset;
-	hwif->quirkproc	= &hpt3xx_quirkproc;
-	hwif->intrproc	= &hpt3xx_intrproc;
-	hwif->maskproc	= &hpt3xx_maskproc;
+	ch->tuneproc = hpt3xx_tune_drive;
+	ch->speedproc = hpt3xx_tune_chipset;
+	ch->quirkproc = hpt3xx_quirkproc;
+	ch->intrproc = hpt3xx_intrproc;
+	ch->maskproc = hpt3xx_maskproc;
 
 #ifdef HPT_SERIALIZE_IO
 	/* serialize access to this device */
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
+	if (ch->mate)
+		ch->serialized = ch->mate->serialized = 1;
 #endif
 
-	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
-	if (hpt_rev) {
-		/* set up ioctl for power status. note: power affects both
-		 * drives on each channel */
-		hwif->busproc   = &hpt370_busproc;
-	}
-
-	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-		/* do nothing now but will split device types */
-		hwif->resetproc = &hpt3xx_reset;
-/*
- * don't do until we can parse out the cobalt box argh ...
- *		hwif->busproc   = &hpt3xx_tristate;
- */
-	}
-
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		if (hpt_rev) {
+	if (ch->dma_base) {
+		if (pci_rev3_check_hpt3xx(ch->pci_dev)) {
 			byte reg5ah = 0;
-			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
+			pci_read_config_byte(ch->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
-				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
-			hwif->udma_start = hpt370_udma_start;
-			hwif->udma_stop = hpt370_udma_stop;
-			hwif->udma_timeout = hpt370_udma_timeout;
-			hwif->udma_irq_lost = hpt370_udma_irq_lost;
-			hwif->XXX_udma = hpt370_dmaproc;
+				pci_write_config_byte(ch->pci_dev, 0x5a, reg5ah & ~0x10);
+			/*
+			 * set up ioctl for power status.
+			 * note: power affects both
+			 * drives on each channel
+			 */
+			ch->resetproc	= hpt3xx_reset;
+			ch->busproc	= hpt370_busproc;
+
+			if (pci_rev7_check_hpt3xx(ch->pci_dev)) {
+				ch->udma_stop = hpt374_udma_stop;
+				ch->XXX_udma = hpt374_dmaproc;
+			} else if (pci_rev5_check_hpt3xx(ch->pci_dev)) {
+				ch->udma_stop = hpt374_udma_stop;
+				ch->XXX_udma = hpt374_dmaproc;
+			} else if (ch->pci_dev->device == PCI_DEVICE_ID_TTI_HPT372) {
+				ch->udma_stop = hpt374_udma_stop;
+				ch->XXX_udma = hpt374_dmaproc;
+			} else if (pci_rev3_check_hpt3xx(ch->pci_dev)) {
+			        ch->udma_start = hpt370_udma_start;
+				ch->udma_stop = hpt370_udma_stop;
+				ch->udma_timeout = hpt370_udma_timeout;
+				ch->udma_irq_lost = hpt370_udma_irq_lost;
+				ch->XXX_udma = hpt370_dmaproc;
+			}
+		} else if (pci_rev2_check_hpt3xx(ch->pci_dev)) {
+			ch->udma_irq_lost = hpt366_udma_irq_lost;
+//			ch->resetproc = hpt3xx_reset;
+//			ch->busproc = hpt3xx_tristate;
+			ch->XXX_udma = hpt366_dmaproc;
 		} else {
-			hwif->udma_irq_lost = hpt366_udma_irq_lost;
-			hwif->XXX_udma = hpt366_dmaproc;
+			ch->udma_irq_lost = hpt366_udma_irq_lost;
+//			ch->resetproc = hpt3xx_reset;
+//			ch->busproc = hpt3xx_tristate;
+			ch->XXX_udma = hpt366_dmaproc;
 		}
 		if (!noautodma)
-			hwif->autodma = 1;
+			ch->autodma = 1;
 		else
-			hwif->autodma = 0;
-		hwif->highmem = 1;
+			ch->autodma = 0;
+		ch->highmem = 1;
 	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_hpt366(struct ata_channel *hwif, unsigned long dmabase)
-{
-	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = inb(dmabase+2);
-	byte primary	= hwif->unit ? 0x4b : 0x43;
-	byte secondary	= hwif->unit ? 0x4f : 0x47;
-	unsigned long flags;
+		ch->autodma = 0;
+		ch->drives[0].autotune = 1;
+		ch->drives[1].autotune = 1;
+	}
+#else
+	ch->drives[0].autotune = 1;
+	ch->drives[1].autotune = 1;
+	ch->autodma = 0;
+#endif
+}
 
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
+static void __init hpt366_init_dma(struct ata_channel *ch, unsigned long dmabase)
+{
+	u8 masterdma = 0;
+	u8 slavedma = 0;
+	u8 dma_new = 0;
+	u8 dma_old = inb(dmabase+2);
+	u8 primary	= ch->unit ? 0x4b : 0x43;
+	u8 secondary	= ch->unit ? 0x4f : 0x47;
 
 	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+	pci_read_config_byte(ch->pci_dev, primary, &masterdma);
+	pci_read_config_byte(ch->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)
+		dma_new |= 0x20;
+	if (slavedma & 0x30)
+		dma_new |= 0x40;
+	if (dma_new != dma_old)
+		outb(dma_new, dmabase+2);
+
+	ata_init_dma(ch, dmabase);
+}
+
 
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) outb(dma_new, dmabase+2);
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_TTI,
+		device: PCI_DEVICE_ID_TTI_HPT366,
+		init_chipset: hpt366_init_chipset,
+		ata66_check: hpt366_ata66_check,
+		init_channel: hpt366_init_channel,
+		init_dma: hpt366_init_dma,
+		bootable: OFF_BOARD,
+		extra: 240,
+		flags: ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_TTI,
+		device: PCI_DEVICE_ID_TTI_HPT372,
+		init_chipset: hpt366_init_chipset,
+		ata66_check: hpt366_ata66_check,
+		init_channel: hpt366_init_channel,
+		init_dma: hpt366_init_dma,
+		bootable: OFF_BOARD,
+		extra: 0,
+		flags: ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_TTI,
+		device: PCI_DEVICE_ID_TTI_HPT374,
+		init_chipset: hpt366_init_chipset,
+		ata66_check: hpt366_ata66_check,
+		init_channel: hpt366_init_channel,
+		init_dma: hpt366_init_dma,
+		bootable: OFF_BOARD,
+		extra: 0,
+		flags: ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA
+	},
+};
 
-	__restore_flags(flags);	/* local CPU only */
+int __init init_hpt366(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
 
-	ide_setup_dma(hwif, dmabase, 8);
+    return 0;
 }
diff -Nru a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c
--- a/drivers/ide/hptraid.c	Thu May  9 15:21:07 2002
+++ b/drivers/ide/hptraid.c	Thu May  9 15:21:07 2002
@@ -107,22 +107,6 @@
 			return 0;
 		}
 
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			unsigned int bios_cyl;
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val = 63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-			
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/ide-cd.c	Thu May  9 15:21:06 2002
@@ -962,7 +962,7 @@
 
 	/* First, figure out if we need to bit-bucket
 	   any of the leading sectors. */
-	nskip = MIN(rq->current_nr_sectors - bio_sectors(rq->bio), sectors_to_transfer);
+	nskip = MIN((int)(rq->current_nr_sectors - bio_sectors(rq->bio)), sectors_to_transfer);
 
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
@@ -2906,7 +2906,6 @@
 	check_media_change:	ide_cdrom_check_media_change,
 	revalidate:		ide_cdrom_revalidate,
 	capacity:		ide_cdrom_capacity,
-	proc:			NULL
 };
 
 /* options */
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Thu May  9 15:21:01 2002
+++ b/drivers/ide/ide-disk.c	Thu May  9 15:21:01 2002
@@ -1,4 +1,4 @@
-/***** vi:set ts=8 sts=8 sw=8:************************************************
+/**** vi:set ts=8 sts=8 sw=8:************************************************
  *
  *  Copyright (C) 1994-1998,2002  Linus Torvalds and authors:
  *
@@ -34,9 +34,9 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
+# define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
 #else
-#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
 
 /*
@@ -304,9 +304,9 @@
 	}
 
 	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(struct ata_device *, struct request *, unsigned long);
+		extern ide_startstop_t promise_do_request(struct ata_device *, struct request *, sector_t);
 
-		return promise_rw_disk(drive, rq, block);
+		return promise_do_request(drive, rq, block);
 	}
 
 	/*
@@ -364,7 +364,7 @@
 		 * point.
 		 */
 
-		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -383,10 +383,10 @@
 
 	ide_cmd_type_parser(&args);
 
-	return ide_raw_taskfile(drive, &args, NULL);
+	return ide_raw_taskfile(drive, &args);
 }
 
-static void idedisk_release (struct inode *inode, struct file *filp, struct ata_device *drive)
+static void idedisk_release(struct inode *inode, struct file *filp, struct ata_device *drive)
 {
 	if (drive->removable && !drive->usage) {
 		struct ata_taskfile args;
@@ -398,7 +398,7 @@
 		ide_cmd_type_parser(&args);
 
 		if (drive->doorlocking &&
-		    ide_raw_taskfile(drive, &args, NULL))
+		    ide_raw_taskfile(drive, &args))
 			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
@@ -419,269 +419,64 @@
 	return drive->capacity - drive->sect0;
 }
 
-static ide_startstop_t idedisk_special(struct ata_device *drive)
-{
-	unsigned char special_cmd = drive->special_cmd;
-
-	if (special_cmd & ATA_SPECIAL_GEOMETRY) {
-		struct ata_taskfile args;
-
-		drive->special_cmd &= ~ATA_SPECIAL_GEOMETRY;
-
-		memset(&args, 0, sizeof(args));
-		args.taskfile.sector_number	= drive->sect;
-		args.taskfile.low_cylinder	= drive->cyl;
-		args.taskfile.high_cylinder	= drive->cyl>>8;
-		args.taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
-		if (!IS_PDC4030_DRIVE) {
-			args.taskfile.sector_count = drive->sect;
-			args.taskfile.command = WIN_SPECIFY;
-			args.handler = set_geometry_intr;;
-		}
-		ata_taskfile(drive, &args, NULL);
-	} else if (special_cmd & ATA_SPECIAL_RECALIBRATE) {
-		drive->special_cmd &= ~ATA_SPECIAL_RECALIBRATE;
-
-		if (!IS_PDC4030_DRIVE) {
-			struct ata_taskfile args;
-
-			memset(&args, 0, sizeof(args));
-			args.taskfile.sector_count = drive->sect;
-			args.taskfile.command = WIN_RESTORE;
-			args.handler = recal_intr;
-			ata_taskfile(drive, &args, NULL);
-		}
-	} else if (special_cmd & ATA_SPECIAL_MMODE) {
-		drive->special_cmd &= ~ATA_SPECIAL_MMODE;
-		if (drive->id && drive->mult_req > drive->id->max_multsect)
-			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE) {
-			struct ata_taskfile args;
-
-			memset(&args, 0, sizeof(args));
-			args.taskfile.sector_count = drive->mult_req;
-			args.taskfile.command = WIN_SETMULT;
-			args.handler = set_multmode_intr;
-
-			ata_taskfile(drive, &args, NULL);
-		}
-	} else if (special_cmd) {
-		drive->special_cmd = 0;
-
-		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special_cmd);
-		return ide_stopped;
-	}
-	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
-}
-
-static void idedisk_pre_reset(struct ata_device *drive)
-{
-	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
-
-	if (legacy)
-		drive->special_cmd = (ATA_SPECIAL_GEOMETRY | ATA_SPECIAL_RECALIBRATE);
-	else
-		drive->special_cmd = 0;
-	if (OK_TO_RESET_CONTROLLER)
-		drive->mult_count = 0;
-	if (drive->mult_req != drive->mult_count)
-		drive->special_cmd |= ATA_SPECIAL_MMODE;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static int smart_enable(struct ata_device *drive)
-{
-	struct ata_taskfile args;
-
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SMART_ENABLE;
-	args.taskfile.low_cylinder = SMART_LCYL_PASS;
-	args.taskfile.high_cylinder = SMART_HCYL_PASS;
-	args.taskfile.command = WIN_SMART;
-	ide_cmd_type_parser(&args);
-
-	return ide_raw_taskfile(drive, &args, NULL);
-}
-
-static int get_smart_values(struct ata_device *drive, u8 *buf)
-{
-	struct ata_taskfile args;
-
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SMART_READ_VALUES;
-	args.taskfile.sector_count = 0x01;
-	args.taskfile.low_cylinder = SMART_LCYL_PASS;
-	args.taskfile.high_cylinder = SMART_HCYL_PASS;
-	args.taskfile.command = WIN_SMART;
-	ide_cmd_type_parser(&args);
-
-	smart_enable(drive);
-
-	return ide_raw_taskfile(drive, &args, buf);
-}
-
-static int get_smart_thresholds(struct ata_device *drive, u8 *buf)
-{
-	struct ata_taskfile args;
-
-	memset(&args, 0, sizeof(args));
-	args.taskfile.feature = SMART_READ_THRESHOLDS;
-	args.taskfile.sector_count = 0x01;
-	args.taskfile.low_cylinder = SMART_LCYL_PASS;
-	args.taskfile.high_cylinder = SMART_HCYL_PASS;
-	args.taskfile.command = WIN_SMART;
-	ide_cmd_type_parser(&args);
-
-	smart_enable(drive);
-
-	return ide_raw_taskfile(drive, &args, buf);
-}
-
-static int proc_idedisk_read_cache
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_device *drive = (struct ata_device *) data;
-	char		*out = page;
-	int		len;
-
-	if (drive->id)
-		len = sprintf(out,"%i\n", drive->id->buf_size / 2);
-	else
-		len = sprintf(out,"(none)\n");
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_idedisk_read_smart_thresholds
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_device *drive = (struct ata_device *)data;
-	int		len = 0, i = 0;
-
-	if (!get_smart_thresholds(drive, page)) {
-		unsigned short *val = (unsigned short *) page;
-		char *out = ((char *)val) + (SECTOR_WORDS * 4);
-		page = out;
-		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
-			val += 1;
-		} while (i < (SECTOR_WORDS * 2));
-		len = out - page;
-	}
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_idedisk_read_smart_values
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_device *drive = (struct ata_device *)data;
-	int len = 0, i = 0;
-
-	if (!get_smart_values(drive, page)) {
-		unsigned short *val = (unsigned short *) page;
-		char *out = ((char *)val) + (SECTOR_WORDS * 4);
-		page = out;
-		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
-			val += 1;
-		} while (i < (SECTOR_WORDS * 2));
-		len = out - page;
-	}
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-static int proc_idedisk_read_tcq
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_device *drive = (struct ata_device *) data;
-	char		*out = page;
-	int		len, cmds, i;
-	unsigned long	flags;
-
-	if (!blk_queue_tagged(&drive->queue)) {
-		len = sprintf(out, "not configured\n");
-		PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-	}
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	len = sprintf(out, "TCQ currently on:\t%s\n", drive->using_tcq ? "yes" : "no");
-	len += sprintf(out+len, "Max queue depth:\t%d\n",drive->queue_depth);
-	len += sprintf(out+len, "Max achieved depth:\t%d\n",drive->max_depth);
-	len += sprintf(out+len, "Max depth since last:\t%d\n",drive->max_last_depth);
-	len += sprintf(out+len, "Current depth:\t\t%d\n", ata_pending_commands(drive));
-	len += sprintf(out+len, "Active tags:\t\t[ ");
-	for (i = 0, cmds = 0; i < drive->queue_depth; i++) {
-		struct request *rq = blk_queue_tag_request(&drive->queue, i);
-
-		if (!rq)
-			continue;
-
-		len += sprintf(out+len, "%d, ", i);
-		cmds++;
-	}
-	len += sprintf(out+len, "]\n");
-
-	len += sprintf(out+len, "Queue:\t\t\treleased [ %lu ] - started [ %lu ]\n", drive->immed_rel, drive->immed_comp);
-
-	if (ata_pending_commands(drive) != cmds)
-		len += sprintf(out+len, "pending request and queue count mismatch (counted: %d)\n", cmds);
-
-	len += sprintf(out+len, "DMA status:\t\t%srunning\n", test_bit(IDE_DMA, &HWGROUP(drive)->flags) ? "" : "not ");
-
-	drive->max_last_depth = 0;
-
-	spin_unlock_irqrestore(&ide_lock, flags);
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-#endif
-
-static ide_proc_entry_t idedisk_proc[] = {
-	{ "cache",		S_IFREG|S_IRUGO,	proc_idedisk_read_cache,		NULL },
-	{ "geometry",		S_IFREG|S_IRUGO,	proc_ide_read_geometry,			NULL },
-	{ "smart_values",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_values,		NULL },
-	{ "smart_thresholds",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_thresholds,	NULL },
-#ifdef CONFIG_BLK_DEV_IDE_TCQ
-	{ "tcq",		S_IFREG|S_IRUSR,	proc_idedisk_read_tcq,			NULL },
-#endif
-	{ NULL, 0, NULL, NULL }
-};
-
-#else
-
-#define	idedisk_proc	NULL
-
-#endif	/* CONFIG_PROC_FS */
-
 /*
  * This is tightly woven into the driver->special can not touch.
  * DON'T do it again until a total personality rewrite is committed.
  */
 static int set_multcount(struct ata_device *drive, int arg)
 {
-	struct request rq;
+	struct ata_taskfile args;
 
-	if (drive->special_cmd & ATA_SPECIAL_MMODE)
+	/* Setting multi mode count on this channel type is not supported/not
+	 * handled.
+	 */
+	if (IS_PDC4030_DRIVE)
+		return -EIO;
+
+	/* Hugh, we still didn't detect the devices capabilities.
+	 */
+	if (!drive->id)
+		return -EIO;
+
+	/* FIXME: Hmm... just bailing out my be problematic, since there *is*
+	 * activity during boot. For now the same problem persists in
+	 * set_pio_mode() we will have to do something about it soon.
+	 */
+	if (HWGROUP(drive)->handler)
 		return -EBUSY;
 
-	ide_init_drive_cmd(&rq);
+	if (arg > drive->id->max_multsect)
+		arg = drive->id->max_multsect;
+
+	memset(&args, 0, sizeof(args));
+	args.taskfile.sector_count = arg;
+	args.taskfile.command	= WIN_SETMULT;
+	ide_cmd_type_parser(&args);
 
-	drive->mult_req = arg;
-	drive->special_cmd |= ATA_SPECIAL_MMODE;
+	if (!ide_raw_taskfile(drive, &args)) {
+		/* all went well track this setting as valid */
+		drive->mult_count = arg;
 
-	ide_do_drive_cmd(drive, &rq, ide_wait);
+		return 0;
+	} else
+		drive->mult_count = 0; /* reset */
 
-	return (drive->mult_count == arg) ? 0 : -EIO;
+	return -EIO;
 }
 
 static int set_nowerr(struct ata_device *drive, int arg)
 {
-	if (ide_spin_wait_hwgroup(drive))
+	if (HWGROUP(drive)->handler)
 		return -EBUSY;
+
 	drive->nowerr = arg;
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+
+	/* FIXME: I'm less then sure that we are under the global request lock here!
+	 */
+#if 0
 	spin_unlock_irq(&ide_lock);
+#endif
 
 	return 0;
 }
@@ -697,7 +492,7 @@
 	args.taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
 	args.taskfile.command	= WIN_SETFEATURES;
 	ide_cmd_type_parser(&args);
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 
 	drive->wcache = arg;
 
@@ -712,7 +507,7 @@
 	args.taskfile.command = WIN_STANDBYNOW1;
 	ide_cmd_type_parser(&args);
 
-	return ide_raw_taskfile(drive, &args, NULL);
+	return ide_raw_taskfile(drive, &args);
 }
 
 static int set_acoustic(struct ata_device *drive, int arg)
@@ -724,7 +519,7 @@
 	args.taskfile.sector_count = arg;
 	args.taskfile.command = WIN_SETFEATURES;
 	ide_cmd_type_parser(&args);
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 
 	drive->acoustic = arg;
 
@@ -777,17 +572,11 @@
 {
 	struct hd_driveid *id = drive->id;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
-	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
-	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
 	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
 	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
 	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
 	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
-	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
-	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
 	ide_add_setting(drive,	"using_tcq",		SETTING_RW,					HDIO_GET_QDMA,		HDIO_SET_QDMA,		TYPE_BYTE,	0,	IDE_MAX_TAG,			1,		1,		&drive->using_tcq,		set_using_tcq);
 #endif
@@ -865,7 +654,7 @@
 	args.handler = task_no_data_intr;
 
 	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 
 	/* if OK, compute maximum address value */
 	if ((args.taskfile.command & 0x01) == 0) {
@@ -893,7 +682,7 @@
 	args.handler = task_no_data_intr;
 
         /* submit command request */
-        ide_raw_taskfile(drive, &args, NULL);
+        ide_raw_taskfile(drive, &args);
 
 	/* if OK, compute maximum address value */
 	if ((args.taskfile.command & 0x01) == 0) {
@@ -933,7 +722,7 @@
 	args.taskfile.command = WIN_SET_MAX;
 	args.handler = task_no_data_intr;
 	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 	/* if OK, read new maximum address value */
 	if ((args.taskfile.command & 0x01) == 0) {
 		addr_set = ((args.taskfile.device_head & 0x0f) << 24)
@@ -969,7 +758,7 @@
 
         args.handler = task_no_data_intr;
 	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 	/* if OK, compute maximum address value */
 	if ((args.taskfile.command & 0x01) == 0) {
 		u32 high = (args.hobfile.high_cylinder << 16) |
@@ -1182,7 +971,13 @@
 	printk("\n");
 
 	drive->mult_count = 0;
+#if 0
 	if (id->max_multsect) {
+
+		/* FIXME: reenable this again after making it to use
+		 * the same code path as the ioctl stuff.
+		 */
+
 #ifdef CONFIG_IDEDISK_MULTI_MODE
 		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
 		id->multsect_valid = id->multsect ? 1 : 0;
@@ -1198,6 +993,7 @@
 			drive->special_cmd |= ATA_SPECIAL_MMODE;
 #endif
 	}
+#endif
 
 	/* FIXME: Nowadays there are many chipsets out there which *require* 32
 	 * bit IO. Those will most propably not work properly with drives not
@@ -1240,10 +1036,7 @@
 	release:		idedisk_release,
 	check_media_change:	idedisk_check_media_change,
 	revalidate:		NULL, /* use default method */
-	pre_reset:		idedisk_pre_reset,
 	capacity:		idedisk_capacity,
-	special:		idedisk_special,
-	proc:			idedisk_proc
 };
 
 MODULE_DESCRIPTION("ATA DISK Driver");
@@ -1260,10 +1053,6 @@
 		}
 		/* We must remove proc entries defined in this module.
 		   Otherwise we oops while accessing these entries */
-#ifdef CONFIG_PROC_FS
-		if (drive->proc)
-			ide_remove_proc_entries(drive->proc, idedisk_proc);
-#endif
 	}
 }
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Thu May  9 15:21:03 2002
+++ b/drivers/ide/ide-dma.c	Thu May  9 15:21:03 2002
@@ -466,14 +466,14 @@
 /*
  * This can be called for a dynamically installed interface. Don't __init it
  */
-void ide_setup_dma(struct ata_channel *ch, unsigned long dma_base, unsigned int num_ports)
+void ata_init_dma(struct ata_channel *ch, unsigned long dma_base)
 {
-	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + num_ports - 1);
-	if (check_region(dma_base, num_ports)) {
-		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
+	if (!request_region(dma_base, 8, ch->name)) {
+		printk(KERN_ERR "ATA: ERROR: BM DMA portst already in use!\n");
+
 		return;
 	}
-	request_region(dma_base, num_ports, ch->name);
+	printk(KERN_INFO"    %s: BM-DMA at 0x%04lx-0x%04lx", ch->name, dma_base, dma_base + 7);
 	ch->dma_base = dma_base;
 	ch->dmatable_cpu = pci_alloc_consistent(ch->pci_dev,
 						  PRD_ENTRIES * PRD_BYTES,
@@ -489,7 +489,8 @@
 		goto dma_alloc_failure;
 	}
 
-	ch->XXX_udma = XXX_ide_dmaproc;
+	if (!ch->XXX_udma)
+		ch->XXX_udma = XXX_ide_dmaproc;
 
 	if (ch->chipset != ide_trm290) {
 		u8 dma_stat = inb(dma_base+2);
@@ -532,8 +533,20 @@
 {
 	struct ata_channel *ch = drive->channel;
 	int set_high = 1;
-	u8 unit = (drive->select.b.unit & 0x01);
-	u64 addr = BLK_BOUNCE_HIGH;
+	u8 unit;
+	u64 addr;
+
+
+	/* Method overloaded by host chip specific code. */
+	if (ch->udma_enable) {
+		ch->udma_enable(drive, on, verbose);
+
+		return;
+	}
+
+	/* Fall back to the default implementation. */
+	unit = (drive->select.b.unit & 0x01);
+	addr = BLK_BOUNCE_HIGH;
 
 	if (!on) {
 		if (verbose)
diff -Nru a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
--- a/drivers/ide/ide-features.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/ide-features.c	Thu May  9 15:21:08 2002
@@ -103,6 +103,105 @@
 	}
 }
 
+/*
+ * hd_driveid data come as little endian,
+ * they need to be converted on big endian machines
+ */
+void ide_fix_driveid(struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+#ifdef __BIG_ENDIAN
+	int i;
+	unsigned short *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (unsigned short *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (unsigned short *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (unsigned short *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; i++)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; i++)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; i++)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+}
+
 int ide_driveid_update (ide_drive_t *drive)
 {
 	/*
@@ -331,6 +430,7 @@
 }
 
 EXPORT_SYMBOL(ide_auto_reduce_xfer);
+EXPORT_SYMBOL(ide_fix_driveid);
 EXPORT_SYMBOL(ide_driveid_update);
 EXPORT_SYMBOL(ide_ata66_check);
 EXPORT_SYMBOL(set_transfer);
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/ide-floppy.c	Thu May  9 15:21:04 2002
@@ -2032,19 +2032,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-
-static ide_proc_entry_t idefloppy_proc[] = {
-	{ "geometry",	S_IFREG|S_IRUGO,	proc_ide_read_geometry,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
-
-#else
-
-#define	idefloppy_proc	NULL
-
-#endif	/* CONFIG_PROC_FS */
-
 /*
  *	IDE subdriver functions, registered with ide.c
  */
@@ -2060,7 +2047,6 @@
 	check_media_change:	idefloppy_check_media_change,
 	revalidate:		NULL, /* use default method */
 	capacity:		idefloppy_capacity,
-	proc:			idefloppy_proc
 };
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
@@ -2075,13 +2061,6 @@
 			printk ("%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
 		}
-
-#ifdef CONFIG_PROC_FS
-		/* We must remove proc entries defined in this module.
-		   Otherwise we oops while accessing these entries */
-		if (drive->proc)
-			ide_remove_proc_entries(drive->proc, idefloppy_proc);
-#endif
 	}
 }
 
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- a/drivers/ide/ide-geometry.c	Thu May  9 15:21:01 2002
+++ b/drivers/ide/ide-geometry.c	Thu May  9 15:21:01 2002
@@ -2,7 +2,7 @@
  * linux/drivers/ide/ide-geometry.c
  *
  * Sun Feb 24 23:13:03 CET 2002: Patch by Andries Brouwer to remove the
- * confused CMOS probe applied. This is solving more problems then it my
+ * confused CMOS probe applied. This is solving more problems than it may
  * (unexpectedly) introduce.
  */
 
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Thu May  9 15:21:09 2002
+++ b/drivers/ide/ide-pci.c	Thu May  9 15:21:09 2002
@@ -25,289 +25,45 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#include "pcihost.h"
+
 /* Missing PCI device IDs: */
 #define PCI_VENDOR_ID_HINT 0x3388
 #define PCI_DEVICE_ID_HINT 0x8013
 
 /*
- * Some combi chips, which can be used on the PCI bus or the VL bus can be in
- * some systems acessed either through the PCI config space or through the
- * hosts IO bus.  If the corresponding initialization driver is using the host
- * IO space to deal with them please define the following.
+ * This is the list of registered PCI chipset driver data structures.
  */
+static struct ata_pci_device *ata_pci_device_list = NULL;
 
-#define	ATA_PCI_IGNORE	((void *)-1)
-#define IDE_NO_DRIVER	((void *)-2)
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern unsigned int pci_init_aec62xx(struct pci_dev *);
-extern unsigned int ata66_aec62xx(struct ata_channel *);
-extern void ide_init_aec62xx(struct ata_channel *);
-extern void ide_dmacapable_aec62xx(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern unsigned int pci_init_ali15x3(struct pci_dev *);
-extern unsigned int ata66_ali15x3(struct ata_channel *);
-extern void ide_init_ali15x3(struct ata_channel *);
-extern void ide_dmacapable_ali15x3(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern unsigned int pci_init_amd74xx(struct pci_dev *);
-extern unsigned int ata66_amd74xx(struct ata_channel *);
-extern void ide_init_amd74xx(struct ata_channel *);
-extern void ide_dmacapable_amd74xx(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *);
-extern unsigned int ata66_cmd64x(struct ata_channel *);
-extern void ide_init_cmd64x(struct ata_channel *);
-extern void ide_dmacapable_cmd64x(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern unsigned int pci_init_cy82c693(struct pci_dev *);
-extern void ide_init_cy82c693(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *);
-extern void ide_init_cs5530(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern unsigned int pci_init_hpt34x(struct pci_dev *);
-extern void ide_init_hpt34x(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern unsigned int pci_init_hpt366(struct pci_dev *);
-extern unsigned int ata66_hpt366(struct ata_channel *);
-extern void ide_init_hpt366(struct ata_channel *);
-extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *);
-extern unsigned int ata66_pdcadma(struct ata_channel *);
-extern void ide_init_pdcadma(struct ata_channel *);
-extern void ide_dmacapable_pdcadma(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *);
-extern unsigned int ata66_pdc202xx(struct ata_channel *);
-extern void ide_init_pdc202xx(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern unsigned int pci_init_piix(struct pci_dev *);
-extern unsigned int ata66_piix(struct ata_channel *);
-extern void ide_init_piix(struct ata_channel *);
-extern void ide_dmacapable_piix(struct ata_channel *, unsigned long);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *);
-extern void ide_init_it8172(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern unsigned int pci_init_svwks(struct pci_dev *);
-extern unsigned int ata66_svwks(struct ata_channel *);
-extern void ide_init_svwks(struct ata_channel *);
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern unsigned int pci_init_sis5513(struct pci_dev *);
-extern unsigned int ata66_sis5513(struct ata_channel *);
-extern void ide_init_sis5513(struct ata_channel *);
-#endif
+/*
+ * This function supplies the data necessary to detect the particular chipset.
+ *
+ * Please note that we don't copy data over. We are just linking it in to the
+ * list.
+ */
+void ata_register_chipset(struct ata_pci_device *d)
+{
+	struct ata_pci_device *tmp;
 
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *);
-extern void dma_init_sl82c105(struct ata_channel *, unsigned long);
-extern void ide_init_sl82c105(struct ata_channel *);
-#endif
+	if (!d)
+		return;
 
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(struct ata_channel *);
-#endif
+	d->next = NULL;
 
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *);
-extern unsigned int ata66_via82cxxx(struct ata_channel *);
-extern void ide_init_via82cxxx(struct ata_channel *);
-extern void ide_dmacapable_via82cxxx(struct ata_channel *, unsigned long);
-#endif
+	if (!ata_pci_device_list) {
+		ata_pci_device_list = d;
 
-typedef struct ide_pci_enablebit_s {
-	u8	reg;	/* pci configuration register holding the enable-bit */
-	u8	mask;	/* mask used to isolate the enable-bit */
-	u8	val;	/* expected value of masked register when "enabled" */
-} ide_pci_enablebit_t;
+		return;
+	}
 
-/* Flags used to untangle quirk handling.
- */
-#define ATA_F_DMA	0x01
-#define ATA_F_NODMA	0x02	/* no DMA mode supported at all */
-#define ATA_F_NOADMA	0x04	/* DMA has to be enabled explicitely */
-#define ATA_F_FIXIRQ	0x08	/* fixed irq wiring */
-#define ATA_F_SER	0x10	/* serialize on first and second channel interrupts */
-#define ATA_F_IRQ	0x20	/* trust IRQ information from config */
-#define ATA_F_PHACK	0x40	/* apply PROMISE hacks */
-#define ATA_F_HPTHACK	0x80	/* apply HPT366 hacks */
-
-struct ata_pci_device {
-	unsigned short		vendor;
-	unsigned short		device;
-	unsigned int		(*init_chipset)(struct pci_dev *dev);
-	unsigned int		(*ata66_check)(struct ata_channel *hwif);
-	void			(*init_channel)(struct ata_channel *hwif);
-	void			(*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
-	ide_pci_enablebit_t	enablebits[2];
-	unsigned int		bootable;
-	unsigned int		extra;
-	unsigned int		flags;
-};
+	tmp = ata_pci_device_list;
+	while (tmp->next) {
+		tmp = tmp->next;
+	}
 
-static struct ata_pci_device pci_chipsets[] __initdata = {
-#ifdef CONFIG_BLK_DEV_PIIX
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1,	pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA },
-	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,	pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA },
-#endif
-#ifdef CONFIG_BLK_DEV_PDC202XX
-# ifdef CONFIG_PDC202XX_FORCE
-        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD,	16, ATA_F_IRQ | ATA_F_DMA },
-        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
-        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
-        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_DMA },
-# else
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16, ATA_F_IRQ | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK  | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ  | ATA_F_DMA },
-# endif
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
-	/* Promise used a different PCI identification for the raid card
-	 * apparently to try and prevent Linux detecting it and using our own
-	 * raid code. We want to detect it for the ataraid drivers, so we have
-	 * to list both here.. */
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ  | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx,	ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
-	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, pci_init_pdc202xx, ata66_pdc202xx,	ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_RZ1000
-	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL,	ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, NULL, NULL,	ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_SIS5513
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_init_sis5513, ata66_sis5513, ide_init_sis5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0, ATA_F_NOADMA },
-#endif
-#ifdef CONFIG_BLK_DEV_CMD64X
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, ATA_F_DMA },
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_OPTI621
-	{PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_TRM290
-	{PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, NULL, NULL, ide_init_trm290,	NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_NS87415
-	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, NULL, NULL, ide_init_ns87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, pci_init_aec62xx, NULL, ide_init_aec62xx, ide_dmacapable_aec62xx, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_SER | ATA_F_IRQ | ATA_F_DMA },
-	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA },
-	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_SL82C105
-	{PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, pci_init_sl82c105, NULL, ide_init_sl82c105, dma_init_sl82c105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_HPT34X
-	{PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, pci_init_hpt34x, NULL, ide_init_hpt34x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16, ATA_F_NOADMA | ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_HPT366
-	{PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, pci_init_hpt366, ata66_hpt366, ide_init_hpt366, ide_dmacapable_hpt366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240, ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	{PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, pci_init_ali15x3, ata66_ali15x3, ide_init_ali15x3, ide_dmacapable_ali15x3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_CY82C693
-	{PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_init_cy82c693, NULL, ide_init_cy82c693,	NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_CS5530
-	{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, pci_init_cs5530, NULL, ide_init_cs5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-#endif
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x50,0x01,0x01}, {0x50,0x02,0x02}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-	{PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, pci_init_pdcadma, ata66_pdcadma, ide_init_pdcadma, ide_dmacapable_pdcadma, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_NODMA },
-#endif
-#ifdef CONFIG_BLK_DEV_SVWKS
-        {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
-	{PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-#endif
-#ifdef CONFIG_BLK_DEV_IT8172
-	{PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, pci_init_it8172,	NULL, ide_init_it8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0, 0 },
-#endif
-	/* Those are id's of chips we don't deal currently with,
-	 * but which still need some generic quirk handling.
-	 */
-	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, NULL, NULL, ATA_PCI_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
-	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, NULL, NULL, NULL, NULL, {{0x6D,0x80,0x80}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_NODMA },
-	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
-	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
-	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
-	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_NOADMA },
-	{PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, NULL, NULL, IDE_NO_DRIVER, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240, ATA_F_IRQ | ATA_F_HPTHACK },
-	{0, 0, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }};
+	tmp->next = d;
+}
 
 /*
  * This allows off board ide-pci cards the enable a BIOS, verify interrupt
@@ -326,7 +82,7 @@
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-static struct ata_channel __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
+static struct ata_channel __init *lookup_channel(unsigned long io_base, int bootable, const char *name)
 {
 	int h;
 	struct ata_channel *hwif;
@@ -478,7 +234,8 @@
 /*
  * Setup DMA transfers on a channel.
  */
-static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev,
+static void __init setup_channel_dma(struct ata_channel *ch,
+		struct pci_dev *dev,
 		struct ata_pci_device *d,
 		int port,
 		u8 class_rev,
@@ -492,14 +249,15 @@
 		autodma = 0;
 
 	if (autodma)
-		hwif->autodma = 1;
+		ch->autodma = 1;
 
 	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
 		return;
 
-	dma_base = get_dma_base(hwif, ((port == ATA_PRIMARY) && d->extra) ? d->extra : 0, dev->name);
+	dma_base = get_dma_base(ch, ((port == ATA_PRIMARY) && d->extra) ? d->extra : 0, dev->name);
 	if (!dma_base) {
-		printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+		printk("%s: %s Bus-Master DMA was disabled by BIOS\n",
+				ch->name, dev->name);
 
 		return;
 	}
@@ -509,17 +267,18 @@
 		 * Set up BM-DMA capability (PnP BIOS should have done this already)
 		 */
 		if (!(d->vendor == PCI_VENDOR_ID_CYRIX && d->device == PCI_DEVICE_ID_CYRIX_5530_IDE))
-			hwif->autodma = 0;	/* default DMA off if we had to configure it here */
+			ch->autodma = 0;	/* default DMA off if we had to configure it here */
 		pci_write_config_word(dev, PCI_COMMAND, *pcicmd | PCI_COMMAND_MASTER);
 		if (pci_read_config_word(dev, PCI_COMMAND, pcicmd) || !(*pcicmd & PCI_COMMAND_MASTER)) {
-			printk("%s: %s error updating PCICMD\n", hwif->name, dev->name);
+			printk("%s: %s error updating PCICMD\n",
+					ch->name, dev->name);
 			dma_base = 0;
 		}
 	}
-	if (d->dma_init)
-		d->dma_init(hwif, dma_base);
+	if (d->init_dma)
+		d->init_dma(ch, dma_base);
 	else
-		ide_setup_dma(hwif, dma_base, 8);
+		ata_init_dma(ch, dma_base);
 }
 #endif
 
@@ -594,7 +353,7 @@
 	if (!base)
 		base = port ? 0x170 : 0x1f0;
 
-	if ((ch = lookup_hwif(base, d->bootable, dev->name)) == NULL)
+	if ((ch = lookup_channel(base, d->bootable, dev->name)) == NULL)
 		return -ENOMEM;	/* no room in ide_hwifs[] */
 
 	if (ch->io_ports[IDE_DATA_OFFSET] != base) {
@@ -665,11 +424,6 @@
 		autodma = 1;
 #endif
 
-	if (d->init_channel == IDE_NO_DRIVER) {
-		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", dev->name);
-		d->init_channel = NULL;
-	}
-
 	if (pci_enable_device(dev)) {
 		printk(KERN_WARNING "%s: Could not enable PCI device.\n", dev->name);
 		return;
@@ -800,13 +554,57 @@
 		}
 	}
 
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev->name, dev->bus->number, dev->devfn);
+	printk("ATA: %s: controller on PCI bus %02x dev %02x\n",
+			dev->name, dev->bus->number, dev->devfn);
 	setup_pci_device(dev, d);
 	if (!dev2)
 		return;
 	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev2->name, dev2->bus->number, dev2->devfn);
+	printk("ATA: %s: controller on PCI bus %02x dev %02x\n",
+			dev2->name, dev2->bus->number, dev2->devfn);
+	setup_pci_device(dev2, d2);
+}
+
+static void __init hpt374_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
+{
+	struct pci_dev *dev2 = NULL;
+	struct pci_dev *findev;
+	struct ata_pci_device *d2;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			dev2 = findev;
+			break;
+		}
+	}
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		dev->name, dev->bus->number, dev->devfn);
+	setup_pci_device(dev, d);
+	if (!dev2) {
+		return;
+	} else {
+		byte irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+			dev2->irq = dev->irq;
+			printk("%s: pci-config space interrupt fixed.\n",
+				dev2->name);
+		}
+	}
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+		dev2->name, dev2->bus->number, dev2->devfn);
 	setup_pci_device(dev2, d2);
+
 }
 
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, struct ata_pci_device *d)
@@ -823,6 +621,7 @@
 	class_rev &= 0xff;
 
 	switch(class_rev) {
+		case 5:
 		case 4:
 		case 3:	printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name);
 			setup_pci_device(dev, d);
@@ -854,6 +653,8 @@
 	setup_pci_device(dev2, d2);
 }
 
+
+
 /*
  * This finds all PCI IDE controllers and calls appropriate initialization
  * functions for them.
@@ -867,11 +668,23 @@
 	vendor = dev->vendor;
 	device = dev->device;
 
+
+
 	/* Look up the chipset information.
+	 * We expect only one match.
 	 */
-	d = pci_chipsets;
-	while (d->vendor && !(d->vendor == vendor && d->device == device))
-		++d;
+	for (d = ata_pci_device_list; d; d = d->next) {
+		if (d->vendor == vendor && d->device == device)
+			break;
+	}
+
+	if (!d) {
+		if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+			printk(KERN_INFO "ATA: unknown interface: %s, on PCI slot %s\n",
+					dev->name, dev->slot_name);
+		}
+		return;
+	}
 
 	if (d->init_channel == ATA_PCI_IGNORE)
 		printk(KERN_INFO "ATA: %s: ignored by PCI bus scan\n", dev->name);
@@ -883,16 +696,16 @@
 		return;	/* IT8172G is also more than only an IDE controller */
 	else if ((d->vendor == PCI_VENDOR_ID_UMC && d->device == PCI_DEVICE_ID_UMC_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
 		return;	/* UM8886A/BF pair */
-	else if (d->flags & ATA_F_HPTHACK)
-		hpt366_device_order_fixup(dev, d);
-	else if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20268R)
+	else if (d->flags & ATA_F_HPTHACK) {
+		if (d->device == PCI_DEVICE_ID_TTI_HPT366)
+			hpt366_device_order_fixup(dev, d);
+		if (d->device == PCI_DEVICE_ID_TTI_HPT374)
+			hpt374_device_order_fixup(dev, d);
+	} else if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20268R)
 		pdc20270_device_order_fixup(dev, d);
-	else if (!(d->vendor == 0 && d->device == 0) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		if (d->vendor == 0 && d->device == 0)
-			printk(KERN_INFO "ATA: unknown interface: %s (%04x:%04x) on PCI slot %s\n",
-			       dev->name, vendor, device, dev->slot_name);
-		else
-			printk(KERN_INFO "ATA: interface: %s, on PCI slot %s\n", dev->name, dev->slot_name);
+	else if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		printk(KERN_INFO "ATA: %s (%04x:%04x) on PCI slot %s\n",
+				dev->name, vendor, device, dev->slot_name);
 		setup_pci_device(dev, d);
 	}
 }
@@ -910,4 +723,80 @@
 			scan_pcidev(dev);
 		}
 	}
+}
+
+/* known chips without particular chipset driver module data table */
+/* Those are id's of chips we don't deal currently with, but which still need
+ * some generic quirk handling.
+ */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_PCTECH,
+		device: PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_CMD,
+		device: PCI_DEVICE_ID_CMD_640,
+		init_channel: ATA_PCI_IGNORE,
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_NS,
+		device: PCI_DEVICE_ID_NS_87410,
+		enablebits: {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_HINT,
+		device: PCI_DEVICE_ID_HINT,
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_HOLTEK,
+		device: PCI_DEVICE_ID_HOLTEK_6565,
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82371MX,
+		enablebits: {{0x6D,0x80,0x80}, {0x00,0x00,0x00}},
+		bootable: ON_BOARD, 0,
+		flags: ATA_F_NODMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_UMC,
+		device: PCI_DEVICE_ID_UMC_UM8673F,
+		bootable: ON_BOARD,
+		flags: ATA_F_FIXIRQ
+	},
+	{
+		vendor: PCI_VENDOR_ID_UMC,
+		device: PCI_DEVICE_ID_UMC_UM8886A,
+		bootable: ON_BOARD,
+		flags: ATA_F_FIXIRQ
+	},
+	{
+		vendor: PCI_VENDOR_ID_UMC,
+		device: PCI_DEVICE_ID_UMC_UM8886BF,
+		bootable: ON_BOARD,
+		flags: ATA_F_FIXIRQ
+	},
+	{
+		vendor: PCI_VENDOR_ID_VIA,
+		device: PCI_DEVICE_ID_VIA_82C561,
+		bootable: ON_BOARD,
+		flags: ATA_F_NOADMA
+	}
+};
+
+int __init init_ata_pci_misc(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+	return 0;
 }
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/ide-pmac.c	Thu May  9 15:21:08 2002
@@ -256,7 +256,15 @@
 #define IDE_WAKEUP_DELAY_MS	2000
 
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq);
+
+static void pmac_udma_enable(struct ata_device *drive, int on, int verbose);
+static int pmac_udma_start(struct ata_device *drive, struct request *rq);
+static int pmac_udma_stop(struct ata_device *drive);
+static int pmac_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq);
+static int pmac_udma_read(struct ata_device *drive, struct request *rq);
+static int pmac_udma_write(struct ata_device *drive, struct request *rq);
+static int pmac_udma_irq_status(struct ata_device *drive);
+static int pmac_ide_dmaproc(struct ata_device *drive);
 static int pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr);
 static int pmac_ide_tune_chipset(struct ata_device *drive, byte speed);
 static void pmac_ide_tuneproc(struct ata_device *drive, byte pio);
@@ -323,11 +331,18 @@
 	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
 	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
 	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].udma = pmac_ide_dmaproc;
+		ide_hwifs[ix].udma_enable = pmac_udma_enable;
+		ide_hwifs[ix].udma_start = pmac_udma_start;
+		ide_hwifs[ix].udma_stop = pmac_udma_stop;
+		ide_hwifs[ix].udma_read = pmac_udma_read;
+		ide_hwifs[ix].udma_write = pmac_udma_write;
+		ide_hwifs[ix].udma_irq_status = pmac_udma_irq_status;
+		ide_hwifs[ix].XXX_udma = pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 		if (!noautodma)
 			ide_hwifs[ix].autodma = 1;
 #endif
+		ide_hwifs[ix].unmask = 1;
 	}
 }
 
@@ -1025,7 +1040,13 @@
 				    	pmif->dma_table_cpu, pmif->dma_table_dma);
 		return;
 	}
-	ide_hwifs[ix].udma = pmac_ide_dmaproc;
+	ide_hwifs[ix].udma_enable = pmac_udma_enable;
+	ide_hwifs[ix].udma_start = pmac_udma_start;
+	ide_hwifs[ix].udma_stop = pmac_udma_stop;
+	ide_hwifs[ix].udma_read = pmac_udma_read;
+	ide_hwifs[ix].udma_write = pmac_udma_write;
+	ide_hwifs[ix].udma_irq_status = pmac_udma_irq_status;
+	ide_hwifs[ix].XXX_udma = pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
 		ide_hwifs[ix].autodma = 1;
@@ -1336,130 +1357,178 @@
 	blk_queue_bounce_limit(&drive->queue, addr);
 }
 
-static int pmac_ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
+static void pmac_udma_enable(struct ata_device *drive, int on, int verbose)
 {
-	int ix, dstat, reading, ata4;
+	if (verbose) {
+		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+	}
+
+	drive->using_dma = 0;
+	ide_toggle_bounce(drive, 0);
+}
+
+static int pmac_udma_start(struct ata_device *drive, struct request *rq)
+{
+	int ix, ata4;
+	volatile struct dbdma_regs *dma;
+
+	/* Can we stuff a pointer to our intf structure in config_data
+	 * or select_data in hwif ?
+	 */
+	ix = pmac_ide_find(drive);
+	if (ix < 0)
+		return 0;
+	dma = pmac_ide[ix].dma_regs;
+	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
+		pmac_ide[ix].kind == controller_kl_ata4_80);
+
+	out_le32(&dma->control, (RUN << 16) | RUN);
+	/* Make sure it gets to the controller right now */
+	(void)in_le32(&dma->control);
+	return 0;
+}
+
+static int pmac_udma_stop(struct ata_device *drive)
+{
+	int ix, dstat, ata4;
+	volatile struct dbdma_regs *dma;
+
+	/* Can we stuff a pointer to our intf structure in config_data
+	 * or select_data in hwif ?
+	 */
+	ix = pmac_ide_find(drive);
+	if (ix < 0)
+		return 0;
+	dma = pmac_ide[ix].dma_regs;
+	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
+		pmac_ide[ix].kind == controller_kl_ata4_80);
+
+	drive->waiting_for_dma = 0;
+	dstat = in_le32(&dma->status);
+	out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
+	pmac_ide_destroy_dmatable(drive->channel, ix);
+	/* verify good dma status */
+	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+}
+
+static int pmac_do_udma(unsigned int reading, struct ata_device *drive, struct request *rq)
+{
+	int ix, ata4;
 	volatile struct dbdma_regs *dma;
 	byte unit = (drive->select.b.unit & 0x01);
-	
+
 	/* Can we stuff a pointer to our intf structure in config_data
 	 * or select_data in hwif ?
 	 */
 	ix = pmac_ide_find(drive);
 	if (ix < 0)
-		return 0;		
+		return 0;
 	dma = pmac_ide[ix].dma_regs;
 	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
 		pmac_ide[ix].kind == controller_kl_ata4_80);
-	
-	switch (func) {
-	case ide_dma_off:
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	case ide_dma_off_quietly:
-		drive->using_dma = 0;
-		ide_toggle_bounce(drive, 0);
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		/* Change this to better match ide-dma.c */
-		pmac_ide_check_dma(drive);
-		ide_toggle_bounce(drive, drive->using_dma);
-		break;
-	case ide_dma_read:
-	case ide_dma_write:
-		reading = (func == ide_dma_read);
-		if (!pmac_ide_build_dmatable(drive, rq, ix, !reading))
-			return 1;
-		/* Apple adds 60ns to wrDataSetup on reads */
-		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-				pmac_ide[ix].timings[unit] + 
-				((func == ide_dma_read) ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-		}
-		drive->waiting_for_dma = 1;
-		if (drive->type != ATA_DISK)
-			return 0;
-		ide_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
-		if ((rq->flags & REQ_DRIVE_ACB) &&
-		    (drive->addressing == 1)) {
-			struct ata_taskfile *args = rq->special;
-			OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
-		} else if (drive->addressing) {
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-		}
-		/* fall through */
-	case ide_dma_begin:
-		out_le32(&dma->control, (RUN << 16) | RUN);
-		/* Make sure it gets to the controller right now */
-		(void)in_le32(&dma->control);
-		break;
-	case ide_dma_end: /* returns 1 on error, 0 otherwise */
-		drive->waiting_for_dma = 0;
-		dstat = in_le32(&dma->status);
-		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-		pmac_ide_destroy_dmatable(drive->channel, ix);
-		/* verify good dma status */
-		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-		/* We have to things to deal with here:
-		 * 
-		 * - The dbdma won't stop if the command was started
-		 * but completed with an error without transfering all
-		 * datas. This happens when bad blocks are met during
-		 * a multi-block transfer.
-		 * 
-		 * - The dbdma fifo hasn't yet finished flushing to
-		 * to system memory when the disk interrupt occurs.
-		 * 
-		 * The trick here is to increment drive->waiting_for_dma,
-		 * and return as if no interrupt occured. If the counter
-		 * reach a certain timeout value, we then return 1. If
-		 * we really got the interrupt, it will happen right away
-		 * again.
-		 * Apple's solution here may be more elegant. They issue
-		 * a DMA channel interrupt (a separate irq line) via a DBDMA
-		 * NOP command just before the STOP, and wait for both the
-		 * disk and DBDMA interrupts to have completed.
-		 */
-		 
-		/* If ACTIVE is cleared, the STOP command have passed and
-		 * transfer is complete.
-		 */
-		if (!(in_le32(&dma->status) & ACTIVE))
-			return 1;
-		if (!drive->waiting_for_dma)
-			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
 
-		/* If dbdma didn't execute the STOP command yet, the
-		 * active bit is still set */
-		drive->waiting_for_dma++;
-		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-			printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-			return 1;
-		}
-		udelay(1);
+	if (!pmac_ide_build_dmatable(drive, rq, ix, !reading))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
+		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+			pmac_ide[ix].timings[unit] + 
+			((reading) ? 0x00800000UL : 0));
+		(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->type != ATA_DISK)
 		return 0;
+	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
+	if ((rq->flags & REQ_DRIVE_ACB) &&
+		(drive->addressing == 1)) {
+		struct ata_taskfile *args = rq->special;
+		OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
+	} else if (drive->addressing) {
+		OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+	} else {
+		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+	}
+
+	return udma_start(drive, rq);
+}
+
+static int pmac_udma_read(struct ata_device *drive, struct request *rq)
+{
+	return pmac_do_udma(1, drive, rq);
+}
+
+static int pmac_udma_write(struct ata_device *drive, struct request *rq)
+{
+	return pmac_do_udma(0, drive, rq);
+}
+
+/*
+ * FIXME: This should be attached to a channel as we can see now!
+ */
+static int pmac_udma_irq_status(struct ata_device *drive)
+{
+	int ix, ata4;
+	volatile struct dbdma_regs *dma;
 
-		/* Let's implement tose just in case someone wants them */
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-	case ide_dma_lostirq:
-	case ide_dma_timeout:
-		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported func only: %d\n", func);
+	/* Can we stuff a pointer to our intf structure in config_data
+	 * or select_data in hwif ?
+	 */
+	ix = pmac_ide_find(drive);
+	if (ix < 0)
+		return 0;
+	dma = pmac_ide[ix].dma_regs;
+	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
+		pmac_ide[ix].kind == controller_kl_ata4_80);
+
+	/* We have to things to deal with here:
+	 *
+	 * - The dbdma won't stop if the command was started but completed with
+	 * an error without transfering all datas. This happens when bad blocks
+	 * are met during a multi-block transfer.
+	 *
+	 * - The dbdma fifo hasn't yet finished flushing to to system memory
+	 * when the disk interrupt occurs.
+	 *
+	 * The trick here is to increment drive->waiting_for_dma, and return as
+	 * if no interrupt occured. If the counter reach a certain timeout
+	 * value, we then return 1. If we really got the interrupt, it will
+	 * happen right away again.  Apple's solution here may be more elegant.
+	 * They issue a DMA channel interrupt (a separate irq line) via a DBDMA
+	 * NOP command just before the STOP, and wait for both the disk and
+	 * DBDMA interrupts to have completed.
+	 */
+
+	/* If ACTIVE is cleared, the STOP command have passed and
+	 * transfer is complete.
+	 */
+	if (!(in_le32(&dma->status) & ACTIVE))
 		return 1;
-	default:
-		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported func: %d\n", func);
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+				called while not waiting\n", ix);
+
+	/* If dbdma didn't execute the STOP command yet, the
+	 * active bit is still set */
+	drive->waiting_for_dma++;
+	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+		printk(KERN_WARNING "ide%d, timeout waiting \
+				for dbdma command stop\n", ix);
 		return 1;
 	}
+	udelay(1);
 	return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+static int pmac_ide_dmaproc(struct ata_device *drive)
+{
+	/* Change this to better match ide-dma.c */
+	pmac_ide_check_dma(drive);
+	ide_toggle_bounce(drive, drive->using_dma);
+
+	return 0;
+}
+#endif
 
 static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Thu May  9 15:21:00 2002
+++ b/drivers/ide/ide-probe.c	Thu May  9 15:21:00 2002
@@ -518,7 +518,7 @@
 	sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
 	sprintf(ch->dev.name, "ide");
 	ch->dev.driver_data = ch;
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 	if (ch->pci_dev)
 		ch->dev.parent = &ch->pci_dev->dev;
 	else
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Thu May  9 15:21:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,636 +0,0 @@
-/*
- *  Copyright (C) 1997-1998	Mark Lord
- *
- * This is the /proc/ide/ filesystem implementation.
- *
- * The major reason this exists is to provide sufficient access
- * to driver and config data, such that user-mode programs can
- * be developed to handle chipset tuning for most PCI interfaces.
- * This should provide better utilities, and less kernel bloat.
- *
- * The entire pci config space for a PCI interface chipset can be
- * retrieved by just reading it.  e.g.    "cat /proc/ide3/config"
- *
- * To modify registers *safely*, do something like:
- *   echo "P40:88" >/proc/ide/ide3/config
- * That expression writes 0x88 to pci config register 0x40
- * on the chip which controls ide3.  Multiple tuples can be issued,
- * and the writes will be completed as an atomic set:
- *   echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
- *
- * All numbers must be specified using pairs of ascii hex digits.
- * It is important to note that these writes will be performed
- * after waiting for the IDE controller (both interfaces)
- * to be completely idle, to ensure no corruption of I/O in progress.
- *
- * Non-PCI registers can also be written, using "R" in place of "P"
- * in the above examples.  The size of the port transfer is determined
- * by the number of pairs of hex digits given for the data.  If a two
- * digit value is given, the write will be a byte operation; if four
- * digits are used, the write will be performed as a 16-bit operation;
- * and if eight digits are specified, a 32-bit "dword" write will be
- * performed.  Odd numbers of digits are not permitted.
- *
- * If there is an error *anywhere* in the string of registers/data
- * then *none* of the writes will be performed.
- *
- * Drive/Driver settings can be retrieved by reading the drive's
- * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
- * To write a new value "val" into a specific setting "name", use:
- *   echo "name:val" >/proc/ide/ide0/hda/settings
- *
- * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
- * smart_thresholds, capabilities]" will issue an IDENTIFY /
- * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
- * SENSE CAPABILITIES command to /dev/hda, and then dump out the
- * returned data as 256 16-bit words.  The "hdparm" utility will
- * be updated someday soon to use this mechanism.
- *
- * Feel free to develop and distribute fancy GUI configuration
- * utilities for your favorite PCI chipsets.  I'll be working on
- * one for the Promise 20246 someday soon.  -ml
- *
- */
-
-#include <linux/config.h>
-#include <asm/uaccess.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/ctype.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern byte aec62xx_proc;
-int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern byte ali_proc;
-int (*ali_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern byte amd74xx_proc;
-int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern byte cmd64x_proc;
-int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-extern byte cs5530_proc;
-int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern byte hpt34x_proc;
-int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt366_proc;
-int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern byte pdc202xx_proc;
-int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-extern byte piix_proc;
-int (*piix_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern byte svwks_proc;
-int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern byte sis_proc;
-int (*sis_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern byte via_proc;
-int (*via_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
-static struct proc_dir_entry * proc_ide_root = NULL;
-
-static int ide_getdigit(char c)
-{
-	int digit;
-	if (isdigit(c))
-		digit = c - '0';
-	else
-		digit = -1;
-	return digit;
-}
-
-static int proc_ide_read_imodel
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_channel *hwif = data;
-	int		len;
-	const char	*name;
-
-	switch (hwif->chipset) {
-		case ide_unknown:	name = "(none)";	break;
-		case ide_generic:	name = "generic";	break;
-		case ide_pci:		name = "pci";		break;
-		case ide_cmd640:	name = "cmd640";	break;
-		case ide_dtc2278:	name = "dtc2278";	break;
-		case ide_ali14xx:	name = "ali14xx";	break;
-		case ide_qd65xx:	name = "qd65xx";	break;
-		case ide_umc8672:	name = "umc8672";	break;
-		case ide_ht6560b:	name = "ht6560b";	break;
-		case ide_pdc4030:	name = "pdc4030";	break;
-		case ide_rz1000:	name = "rz1000";	break;
-		case ide_trm290:	name = "trm290";	break;
-		case ide_cmd646:	name = "cmd646";	break;
-		case ide_cy82c693:	name = "cy82c693";	break;
-		case ide_pmac:		name = "mac-io";	break;
-		default:		name = "(unknown)";	break;
-	}
-	len = sprintf(page, "%s\n", name);
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_ide_read_channel(char *page, char **start,
-		off_t off, int count, int *eof, void *data)
-{
-	struct ata_channel *hwif = data;
-	int		len;
-
-	page[0] = hwif->unit ? '1' : '0';
-	page[1] = '\n';
-	len = 2;
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int get_identify(ide_drive_t *drive, u8 *buf)
-{
-	struct ata_taskfile args;
-
-	memset(&args, 0, sizeof(args));
-	args.taskfile.sector_count = 0x01;
-	args.taskfile.command = (drive->type == ATA_DISK) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
-	ide_cmd_type_parser(&args);
-
-	return ide_raw_taskfile(drive, &args, buf);
-}
-
-static int proc_ide_read_identify
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t *drive = data;
-	int len = 0;
-	int i = 0;
-
-	if (drive && !get_identify(drive, page)) {
-		unsigned short *val = (unsigned short *) page;
-		char *out = ((char *)val) + (SECTOR_WORDS * 4);
-		page = out;
-		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
-			val += 1;
-		} while (i < (SECTOR_WORDS * 2));
-		len = out - page;
-	} else
-		len = sprintf(page, "\n");
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_ide_read_settings
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = data;
-	ide_settings_t	*setting = drive->settings;
-	char		*out = page;
-	int		len, rc, mul_factor, div_factor;
-
-	out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
-	out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
-	while(setting) {
-		mul_factor = setting->mul_factor;
-		div_factor = setting->div_factor;
-		out += sprintf(out, "%-24s", setting->name);
-		if ((rc = ide_read_setting(drive, setting)) >= 0)
-			out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
-		else
-			out += sprintf(out, "%-16s", "write-only");
-		out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
-		if (setting->rw & SETTING_READ)
-			out += sprintf(out, "r");
-		if (setting->rw & SETTING_WRITE)
-			out += sprintf(out, "w");
-		out += sprintf(out, "\n");
-		setting = setting->next;
-	}
-	len = out - page;
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-#define MAX_LEN	30
-
-static int proc_ide_write_settings
-	(struct file *file, const char *buffer, unsigned long count, void *data)
-{
-	ide_drive_t	*drive = data;
-	char		name[MAX_LEN + 1];
-	int		for_real = 0, len;
-	unsigned long	n;
-	const char	*start = NULL;
-	ide_settings_t	*setting;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	/*
-	 * Skip over leading whitespace
-	 */
-	while (count && isspace(*buffer)) {
-		--count;
-		++buffer;
-	}
-	/*
-	 * Do one full pass to verify all parameters,
-	 * then do another to actually write the new settings.
-	 */
-	do {
-		const char *p;
-		p = buffer;
-		n = count;
-		while (n > 0) {
-			int d, digits;
-			unsigned int val = 0;
-			start = p;
-
-			while (n > 0 && *p != ':') {
-				--n;
-				p++;
-			}
-			if (*p != ':')
-				goto parse_error;
-			len = min(p - start, MAX_LEN);
-			strncpy(name, start, min(len, MAX_LEN));
-			name[len] = 0;
-
-			if (n > 0) {
-				--n;
-				p++;
-			} else
-				goto parse_error;
-
-			digits = 0;
-			while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
-				val = (val * 10) + d;
-				--n;
-				++p;
-				++digits;
-			}
-			if (n > 0 && !isspace(*p))
-				goto parse_error;
-			while (n > 0 && isspace(*p)) {
-				--n;
-				++p;
-			}
-
-			/* Find setting by name */
-			setting = drive->settings;
-
-			while (setting) {
-			    if (strcmp(setting->name, name) == 0)
-				break;
-			    setting = setting->next;
-			}
-			if (!setting)
-				goto parse_error;
-
-			if (for_real)
-				ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
-		}
-	} while (!for_real++);
-	return count;
-parse_error:
-	printk("proc_ide_write_settings(): parse error\n");
-	return -EINVAL;
-}
-
-int proc_ide_read_capacity
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t *drive = data;
-	struct ata_operations *driver = drive->driver;
-	int len;
-
-	if (!driver)
-		len = sprintf(page, "(none)\n");
-        else
-		len = sprintf(page,"%llu\n", (unsigned long long) ata_capacity(drive));
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-int proc_ide_read_geometry
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = data;
-	char		*out = page;
-	int		len;
-
-	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
-	len = out - page;
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_ide_read_dmodel
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = data;
-	struct hd_driveid *id = drive->id;
-	int		len;
-
-	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_ide_read_media
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = data;
-	const char	*type;
-	int		len;
-
-	switch (drive->type) {
-		case ATA_DISK:	type = "disk\n";
-				break;
-		case ATA_ROM:	type = "cdrom\n";
-				break;
-		case ATA_TAPE:	type = "tape\n";
-				break;
-		case ATA_FLOPPY:type = "floppy\n";
-				break;
-		default:	type = "UNKNOWN\n";
-				break;
-	}
-	strcpy(page,type);
-	len = strlen(type);
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static ide_proc_entry_t generic_drive_entries[] = {
-	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
-	{ "media",	S_IFREG|S_IRUGO,	proc_ide_read_media,	NULL },
-	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_dmodel,	NULL },
-	{ "settings",	S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings,	proc_ide_write_settings },
-	{ NULL,	0, NULL, NULL }
-};
-
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
-{
-	struct proc_dir_entry *ent;
-
-	if (!dir || !p)
-		return;
-	while (p->name != NULL) {
-		ent = create_proc_entry(p->name, p->mode, dir);
-		if (!ent) return;
-		ent->nlink = 1;
-		ent->data = data;
-		ent->read_proc = p->read_proc;
-		ent->write_proc = p->write_proc;
-		p++;
-	}
-}
-
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
-{
-	if (!dir || !p)
-		return;
-	while (p->name != NULL) {
-		remove_proc_entry(p->name, dir);
-		p++;
-	}
-}
-
-/* FIXME: we should iterate over the hwifs here as everywhere else.
- */
-static void create_proc_ide_drives(struct ata_channel *hwif)
-{
-	int	d;
-	struct proc_dir_entry *parent = hwif->proc;
-	char name[64];
-
-	for (d = 0; d < MAX_DRIVES; d++) {
-		ide_drive_t *drive = &hwif->drives[d];
-		struct ata_operations *driver = drive->driver;
-
-		if (!drive->present)
-			continue;
-		if (drive->proc)
-			continue;
-
-		drive->proc = proc_mkdir(drive->name, parent);
-		if (drive->proc) {
-			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
-			if (driver) {
-				ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
-				ide_add_proc_entries(drive->proc, driver->proc, drive);
-			}
-		}
-		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
-	}
-}
-
-static void destroy_proc_ide_device(struct ata_channel *hwif, ide_drive_t *drive)
-{
-	struct ata_operations *driver = drive->driver;
-
-	if (drive->proc) {
-		if (driver)
-			ide_remove_proc_entries(drive->proc, driver->proc);
-		ide_remove_proc_entries(drive->proc, generic_drive_entries);
-		remove_proc_entry(drive->name, proc_ide_root);
-		remove_proc_entry(drive->name, hwif->proc);
-		drive->proc = NULL;
-	}
-}
-
-void destroy_proc_ide_drives(struct ata_channel *hwif)
-{
-	int	d;
-
-	for (d = 0; d < MAX_DRIVES; d++) {
-		ide_drive_t *drive = &hwif->drives[d];
-
-		if (drive->proc)
-			destroy_proc_ide_device(hwif, drive);
-	}
-}
-
-static ide_proc_entry_t hwif_entries[] = {
-	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
-	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
-	{ NULL,	0, NULL, NULL }
-};
-
-void create_proc_ide_interfaces(void)
-{
-	int	h;
-
-	for (h = 0; h < MAX_HWIFS; h++) {
-		struct ata_channel *hwif = &ide_hwifs[h];
-
-		if (!hwif->present)
-			continue;
-		if (!hwif->proc) {
-			hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
-			if (!hwif->proc)
-				return;
-			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
-		}
-		create_proc_ide_drives(hwif);
-	}
-}
-
-static void destroy_proc_ide_interfaces(void)
-{
-	int	h;
-
-	for (h = 0; h < MAX_HWIFS; h++) {
-		struct ata_channel *hwif = &ide_hwifs[h];
-		int exist = (hwif->proc != NULL);
-#if 0
-		if (!hwif->present)
-			continue;
-#endif
-		if (exist) {
-			destroy_proc_ide_drives(hwif);
-			ide_remove_proc_entries(hwif->proc, hwif_entries);
-			remove_proc_entry(hwif->name, proc_ide_root);
-			hwif->proc = NULL;
-		} else
-			continue;
-	}
-}
-
-void proc_ide_create(void)
-{
-	proc_ide_root = proc_mkdir("ide", 0);
-	if (!proc_ide_root) return;
-
-	create_proc_ide_interfaces();
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-}
-
-void proc_ide_destroy(void)
-{
-	/*
-	 * Mmmm.. does this free up all resources,
-	 * or do we need to do a more proper cleanup here ??
-	 */
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		remove_proc_entry("ide/aec62xx",0);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		remove_proc_entry("ide/ali",0);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		remove_proc_entry("ide/amd74xx",0);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		remove_proc_entry("ide/cmd64x",0);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		remove_proc_entry("ide/cs5530",0);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		remove_proc_entry("ide/hpt34x",0);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		remove_proc_entry("ide/hpt366",0);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		remove_proc_entry("ide/pdc202xx",0);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		remove_proc_entry("ide/piix",0);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		remove_proc_entry("ide/svwks",0);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		remove_proc_entry("ide/sis", 0);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
-	remove_proc_entry("ide/drivers", 0);
-	destroy_proc_ide_interfaces();
-	remove_proc_entry("ide", 0);
-}
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Thu May  9 15:21:03 2002
+++ b/drivers/ide/ide-tape.c	Thu May  9 15:21:03 2002
@@ -4273,16 +4273,6 @@
 }
 
 /*
- *	idetape_pre_reset is called before an ATAPI/ATA software reset.
- */
-static void idetape_pre_reset (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	if (tape != NULL)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-}
-
-/*
  *	Character device interface functions
  */
 static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
@@ -6000,7 +5990,7 @@
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
 	drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 	if (!tape->onstream && drive->channel->pci_dev != NULL) {
 		/*
 		 * These two ide-pci host adapters appear to need DSC overlap disabled.
@@ -6009,10 +5999,10 @@
 		if ((drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
 		    (drive->channel->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
 			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-		    	drive->dsc_overlap = 0;
+			drive->dsc_overlap = 0;
 		}
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 	tape->drive = drive;
 	tape->minor = minor;
 	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
@@ -6118,31 +6108,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-
-static int proc_idetape_read_name
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = (ide_drive_t *) data;
-	idetape_tape_t	*tape = drive->driver_data;
-	char		*out = page;
-	int		len;
-
-	len = sprintf(out, "%s\n", tape->name);
-	PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
-}
-
-static ide_proc_entry_t idetape_proc[] = {
-	{ "name",	S_IFREG|S_IRUGO,	proc_idetape_read_name,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
-
-#else
-
-#define	idetape_proc	NULL
-
-#endif
-
 static void idetape_revalidate(ide_drive_t *_dummy)
 {
 	/* We don't have to handle any partition information here, which is the
@@ -6164,9 +6129,6 @@
 	release:		idetape_blkdev_release,
 	check_media_change:	NULL,
 	revalidate:		idetape_revalidate,
-	pre_reset:		idetape_pre_reset,
-	capacity:		NULL,
-	proc:			idetape_proc
 };
 
 /*
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Thu May  9 15:21:07 2002
+++ b/drivers/ide/ide-taskfile.c	Thu May  9 15:21:07 2002
@@ -39,8 +39,6 @@
 #define DTF(x...)
 #endif
 
-#define SUPPORT_VLB_SYNC 1
-
 /*
  * for now, taskfile requests are special :/
  */
@@ -468,10 +466,10 @@
 		/* for dma commands we don't set the handler */
 		if (args->taskfile.command == WIN_WRITEDMA
 		 || args->taskfile.command == WIN_WRITEDMA_EXT)
-			udma_write(drive, rq);
+			return !udma_write(drive, rq);
 		else if (args->taskfile.command == WIN_READDMA
 		      || args->taskfile.command == WIN_READDMA_EXT)
-			udma_read(drive, rq);
+			return !udma_read(drive, rq);
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
 		else if (args->taskfile.command == WIN_WRITEDMA_QUEUED
 		      || args->taskfile.command == WIN_WRITEDMA_QUEUED_EXT
@@ -489,40 +487,6 @@
 }
 
 /*
- * This is invoked on completion of a WIN_SETMULT cmd.
- */
-ide_startstop_t set_multmode_intr(struct ata_device *drive, struct request *__rq)
-{
-	u8 stat;
-
-	if (OK_STAT(stat = GET_STAT(),READY_STAT,BAD_STAT)) {
-		drive->mult_count = drive->mult_req;
-	} else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special_cmd |= ATA_SPECIAL_RECALIBRATE;
-		ide_dump_status(drive, "set_multmode", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * This is invoked on completion of a WIN_SPECIFY cmd.
- */
-ide_startstop_t set_geometry_intr(struct ata_device *drive, struct request *__rq)
-{
-	u8 stat;
-
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
-		return ide_stopped;
-
-	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
-
-	ide_set_handler(drive, set_geometry_intr, WAIT_CMD, NULL);
-	return ide_started;
-}
-
-/*
  * This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
 ide_startstop_t recal_intr(struct ata_device *drive, struct request *__rq)
@@ -729,11 +693,11 @@
 			args->command_type = IDE_DRIVE_TASK_IN;
 			return;
 
+		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_WRITE:
 		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
-		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_DOWNLOAD_MICROCODE:
 			args->prehandler = pre_task_out_intr;
 			args->handler = task_out_intr;
@@ -832,7 +796,7 @@
 			}
 
 		case WIN_SPECIFY:
-			args->handler = set_geometry_intr;
+			args->handler = task_no_data_intr;
 			args->command_type = IDE_DRIVE_TASK_NO_DATA;
 			return;
 
@@ -874,7 +838,7 @@
 			return;
 
 		case WIN_SETMULT:
-			args->handler = set_multmode_intr;
+			args->handler = task_no_data_intr;
 			args->command_type = IDE_DRIVE_TASK_NO_DATA;
 			return;
 
@@ -894,19 +858,19 @@
 	}
 }
 
-int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *args, byte *buf)
+int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *args)
 {
 	struct request rq;
 
 	memset(&rq, 0, sizeof(rq));
 	rq.flags = REQ_DRIVE_ACB;
-	rq.buffer = buf;
 
+#if 0
 	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
 		rq.current_nr_sectors = rq.nr_sectors
 			= (args->hobfile.sector_count << 8)
 			| args->taskfile.sector_count;
-
+#endif
 	rq.special = args;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
@@ -996,8 +960,6 @@
 EXPORT_SYMBOL(atapi_write);
 EXPORT_SYMBOL(ata_taskfile);
 EXPORT_SYMBOL(recal_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(set_multmode_intr);
 EXPORT_SYMBOL(task_no_data_intr);
 EXPORT_SYMBOL(ide_raw_taskfile);
 EXPORT_SYMBOL(ide_cmd_type_parser);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/ide.c	Thu May  9 15:21:06 2002
@@ -67,13 +67,11 @@
 #include <asm/bitops.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 /*
  * Those will be moved into separate header files eventually.
  */
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_probe_for_rz100x(void);
-#endif
 #ifdef CONFIG_ETRAX_IDE
 extern void init_e100_ide(void);
 #endif
@@ -123,7 +121,7 @@
  */
 spinlock_t ide_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
 #endif
 
@@ -193,7 +191,7 @@
 #ifdef CONFIG_BLK_DEV_HD
 	if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA)
 		ch->noprobe = 1; /* may be overridden by ide_setup() */
-#endif /* CONFIG_BLK_DEV_HD */
+#endif
 	ch->major = ide_major[index];
 	sprintf(ch->name, "ide%d", index);
 	ch->bus_state = BUSSTATE_ON;
@@ -201,15 +199,14 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		struct ata_device *drive = &ch->drives[unit];
 
-		drive->type			= ATA_DISK;
-		drive->select.all		= (unit<<4)|0xa0;
-		drive->channel			= ch;
-		drive->ctl			= 0x08;
-		drive->ready_stat		= READY_STAT;
-		drive->bad_wstat		= BAD_W_STAT;
-		drive->special_cmd = (ATA_SPECIAL_RECALIBRATE | ATA_SPECIAL_GEOMETRY);
+		drive->type		= ATA_DISK;
+		drive->select.all	= (unit<<4)|0xa0;
+		drive->channel		= ch;
+		drive->ctl		= 0x08;
+		drive->ready_stat	= READY_STAT;
+		drive->bad_wstat	= BAD_W_STAT;
 		sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit);
-		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		drive->max_failures	= IDE_DEFAULT_MAX_FAILURES;
 
 		init_waitqueue_head(&drive->wqueue);
 	}
@@ -354,11 +351,8 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static void ata_pre_reset(struct ata_device *drive)
+static void check_crc_errors(struct ata_device *drive)
 {
-	if (ata_ops(drive) && ata_ops(drive)->pre_reset)
-		ata_ops(drive)->pre_reset(drive);
-
 	if (!drive->using_dma)
 	    return;
 
@@ -392,38 +386,6 @@
 	return ~0UL;
 }
 
-/*
- * This is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT commands to
- * a drive.
- */
-static ide_startstop_t ata_special(struct ata_device *drive)
-{
-	unsigned char special_cmd = drive->special_cmd;
-
-#ifdef DEBUG
-	printk("%s: ata_special: 0x%02x\n", drive->name, special_cmd);
-#endif
-	if (special_cmd & ATA_SPECIAL_TUNE) {
-		drive->special_cmd &= ~ATA_SPECIAL_TUNE;
-		if (drive->channel->tuneproc != NULL)
-			drive->channel->tuneproc(drive, drive->tune_req);
-	} else if (drive->driver != NULL) {
-		if (ata_ops(drive)->special)
-			return ata_ops(drive)->special(drive);
-		else {
-			drive->special_cmd = 0;
-			drive->mult_req = 0;
-
-			return ide_stopped;
-		}
-	} else if (special_cmd) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, special_cmd);
-		drive->special_cmd = 0;
-	}
-
-	return ide_stopped;
-}
-
 extern struct block_device_operations ide_fops[];
 
 /*
@@ -460,24 +422,24 @@
  */
 static ide_startstop_t atapi_reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	byte stat;
+	struct ata_channel *ch = drive->channel;
+	u8 stat;
 
-	SELECT_DRIVE(drive->channel,drive);
+	SELECT_DRIVE(ch,drive);
 	udelay (10);
 
 	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
+		if (time_before(jiffies, ch->poll_timeout)) {
 			ide_set_handler (drive, atapi_reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
-		hwgroup->poll_timeout = 0;	/* end of polling */
-		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
+		ch->poll_timeout = 0;	/* end of polling */
+		printk("%s: ATAPI reset timed out, status=0x%02x\n", drive->name, stat);
 		return do_reset1 (drive, 1);	/* do it the old fashioned way */
 	}
-	hwgroup->poll_timeout = 0;	/* done polling */
+	ch->poll_timeout = 0;	/* done polling */
 
 	return ide_stopped;
 }
@@ -489,19 +451,18 @@
  */
 static ide_startstop_t reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct ata_channel *hwif = drive->channel;
+	struct ata_channel *ch = drive->channel;
 	u8 stat;
 
 	if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
+		if (time_before(jiffies, ch->poll_timeout)) {
 			ide_set_handler(drive, reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
-		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, stat);
+		printk("%s: reset timed out, status=0x%02x\n", ch->name, stat);
 		drive->failures++;
 	} else  {
-		printk("%s: reset: ", hwif->name);
+		printk("%s: reset: ", ch->name);
 		if ((stat = GET_ERR()) == 1) {
 			printk("success\n");
 			drive->failures = 0;
@@ -531,7 +492,8 @@
 			drive->failures++;
 		}
 	}
-	hwgroup->poll_timeout = 0;	/* done polling */
+	ch->poll_timeout = 0;	/* done polling */
+
 	return ide_stopped;
 }
 
@@ -555,21 +517,21 @@
 {
 	unsigned int unit;
 	unsigned long flags;
-	struct ata_channel *hwif = drive->channel;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct ata_channel *ch = drive->channel;
 
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
 
 	/* For an ATAPI device, first try an ATAPI SRST. */
 	if (drive->type != ATA_DISK && !do_not_try_atapi) {
-		ata_pre_reset(drive);
-		SELECT_DRIVE(hwif,drive);
+		check_crc_errors(drive);
+		SELECT_DRIVE(ch, drive);
 		udelay (20);
 		OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL);
 		__restore_flags(flags);	/* local CPU only */
+
 		return ide_started;
 	}
 
@@ -578,11 +540,12 @@
 	 * for any of the drives on this interface.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		ata_pre_reset(&hwif->drives[unit]);
+		check_crc_errors(&ch->drives[unit]);
 
 #if OK_TO_RESET_CONTROLLER
 	if (!IDE_CONTROL_REG) {
 		__restore_flags(flags);
+
 		return ide_stopped;
 	}
 	/*
@@ -601,7 +564,7 @@
 		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
 	}
 	udelay(10);			/* more than enough time */
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler(drive, reset_pollfunc, HZ/20, NULL);
 
 	/*
@@ -609,9 +572,10 @@
 	 * state when the disks are reset this way. At least, the Winbond
 	 * 553 documentation says that
 	 */
-	if (hwif->resetproc != NULL)
-		hwif->resetproc(drive);
+	if (ch->resetproc != NULL)
+		ch->resetproc(drive);
 
+	/* FIXME: we should handle mulit mode setting here as well ! */
 #endif
 
 	__restore_flags (flags);	/* local CPU only */
@@ -789,6 +753,36 @@
 	}
 }
 
+#ifdef CONFIG_BLK_DEV_PDC4030
+# define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
+#else
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+#endif
+
+/*
+ * We are still on the old request path here so issuing the recalibrate command
+ * directly should just work.
+ */
+static int do_recalibrate(struct ata_device *drive)
+{
+	printk(KERN_INFO "%s: recalibrating!\n", drive->name);
+
+	if (drive->type != ATA_DISK)
+		return ide_stopped;
+
+	if (!IS_PDC4030_DRIVE) {
+		struct ata_taskfile args;
+
+		memset(&args, 0, sizeof(args));
+		args.taskfile.sector_count = drive->sect;
+		args.taskfile.command = WIN_RESTORE;
+		args.handler = recal_intr;
+		ata_taskfile(drive, &args, NULL);
+	}
+
+	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
+}
+
 /*
  * Take action based on the error returned by the drive.
  */
@@ -835,13 +829,11 @@
 		else
 			ide_end_request(drive, rq, 0);
 	} else {
-		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-			++rq->errors;
+		++rq->errors;
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET)
 			return do_reset1(drive, 0);
-		}
 		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-			drive->special_cmd |= ATA_SPECIAL_RECALIBRATE;
-		++rq->errors;
+			return do_recalibrate(drive);
 	}
 	return ide_stopped;
 }
@@ -960,7 +952,7 @@
 		goto kill_rq;
 	}
 
-	block    = rq->sector;
+	block = rq->sector;
 
 	/* Strange disk manager remap.
 	 */
@@ -991,14 +983,6 @@
 		}
 	}
 
-	/* FIXME: We can see nicely here that all commands should be submitted
-	 * through the request queue and that the special field in drive should
-	 * go as soon as possible!
-	 */
-
-	if (drive->special_cmd)
-		return ata_special(drive);
-
 	/* This issues a special drive command, usually initiated by ioctl()
 	 * from the external hdparm program.
 	 */
@@ -1011,7 +995,7 @@
 		ata_taskfile(drive, args, NULL);
 
 		if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
-					(args->command_type == IDE_DRIVE_TASK_OUT)) &&
+		     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
 				args->prehandler && args->handler)
 			return args->prehandler(drive, rq);
 
@@ -1053,6 +1037,7 @@
 			return ata_ops(drive)->do_request(drive, rq, block);
 		else {
 			ide_end_request(drive, rq, 0);
+
 			return ide_stopped;
 		}
 	}
@@ -1499,7 +1484,7 @@
 			disable_irq(ch->irq);	/* disable_irq_nosync ?? */
 #endif
 			__cli();	/* local CPU only, as if we were handling an interrupt */
-			if (hwgroup->poll_timeout != 0) {
+			if (ch->poll_timeout != 0) {
 				startstop = handler(drive, ch->hwgroup->rq);
 			} else if (drive_is_ready(drive)) {
 				if (drive->waiting_for_dma)
@@ -1598,7 +1583,7 @@
 	if (!ide_ack_intr(ch))
 		goto out_lock;
 
-	if (handler == NULL || hwgroup->poll_timeout != 0) {
+	if (handler == NULL || ch->poll_timeout != 0) {
 #if 0
 		printk(KERN_INFO "ide: unexpected interrupt %d %d\n", ch->unit, irq);
 #endif
@@ -1614,7 +1599,7 @@
 		 * For PCI, we cannot tell the difference,
 		 * so in that case we just ignore it and hope it goes away.
 		 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 		if (ch->pci_dev && !ch->pci_dev->vendor)
 #endif
 		{
@@ -1622,7 +1607,7 @@
 			 * safely try to do something about it:
 			 */
 			unexpected_irq(irq);
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 		} else {
 			/*
 			 * Whack the status register, just in case we have a leftover pending IRQ.
@@ -1934,13 +1919,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-ide_proc_entry_t generic_subdriver_entries[] = {
-	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
-#endif
-
 void ide_unregister(struct ata_channel *ch)
 {
 	struct gendisk *gd;
@@ -1997,9 +1975,6 @@
 			}
 		}
 	}
-#ifdef CONFIG_PROC_FS
-	destroy_proc_ide_drives(ch);
-#endif
 	spin_lock_irqsave(&ide_lock, flags);
 
 	/*
@@ -2120,6 +2095,7 @@
 	ch->atapi_read = old.atapi_read;
 	ch->atapi_write = old.atapi_write;
 	ch->XXX_udma = old.XXX_udma;
+	ch->udma_enable = old.udma_enable;
 	ch->udma_start = old.udma_start;
 	ch->udma_stop = old.udma_stop;
 	ch->udma_read = old.udma_read;
@@ -2142,7 +2118,7 @@
 	ch->chipset = old.chipset;
 	ch->autodma = old.autodma;
 	ch->udma_four = old.udma_four;
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 	ch->pci_dev = old.pci_dev;
 #endif
 	ch->straight8 = old.straight8;
@@ -2222,9 +2198,6 @@
 	if (!initializing) {
 		ideprobe_init();
 		revalidate_drives();
-#ifdef CONFIG_PROC_FS
-		create_proc_ide_interfaces();
-#endif
 		/* FIXME: Do we really have to call it second time here?! */
 		ide_driver_module();
 	}
@@ -2328,23 +2301,24 @@
 int ide_spin_wait_hwgroup(struct ata_device *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long timeout = jiffies + (3 * HZ);
+
+	/* FIXME: Wait on a proper timer. Instead of playing games on the
+	 * spin_lock().
+	 */
+
+	unsigned long timeout = jiffies + (10 * HZ);
 
 	spin_lock_irq(&ide_lock);
 
 	while (test_bit(IDE_BUSY, &hwgroup->flags)) {
-		unsigned long lflags;
 		spin_unlock_irq(&ide_lock);
-		__save_flags(lflags);	/* local CPU only */
-		__sti();		/* local CPU only; needed for jiffies */
-		if (0 < (signed long)(jiffies - timeout)) {
-			__restore_flags(lflags);	/* local CPU only */
+		if (time_after(jiffies, timeout)) {
 			printk("%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		__restore_flags(lflags);	/* local CPU only */
 		spin_lock_irq(&ide_lock);
 	}
+
 	return 0;
 }
 
@@ -2412,18 +2386,17 @@
 
 static int set_pio_mode(struct ata_device *drive, int arg)
 {
-	struct request rq;
-
 	if (!drive->channel->tuneproc)
 		return -ENOSYS;
 
-	if (drive->special_cmd & ATA_SPECIAL_TUNE)
+	/* FIXME: This is very much the same kind of problem as we have with
+	 * set_mutlmode() see for a edscription there.
+	 */
+	if (HWGROUP(drive)->handler)
 		return -EBUSY;
 
-	ide_init_drive_cmd(&rq);
-	drive->tune_req = (u8) arg;
-	drive->special_cmd |= ATA_SPECIAL_TUNE;
-	ide_do_drive_cmd(drive, &rq, ide_wait);
+	if (drive->channel->tuneproc != NULL)
+		drive->channel->tuneproc(drive, (u8) arg);
 
 	return 0;
 }
@@ -2511,28 +2484,13 @@
 			return 0;
 		}
 
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-
-			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
-				return -EINVAL;
-
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
 		case HDIO_GETGEO_BIG_RAW:
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
 				return -EINVAL;
-			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2849,7 +2807,7 @@
 		return 1;
 	}
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 	if (!strcmp(s, "ide=reverse")) {
 		ide_scan_direction = 1;
 		printk(" : Enabled support for IDE inverse scan order.\n");
@@ -2996,7 +2954,7 @@
 				init_pdc4030();
 				goto done;
 			}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+#endif
 #ifdef CONFIG_BLK_DEV_ALI14XX
 			case -17: /* "ali14xx" */
 			{
@@ -3051,7 +3009,7 @@
 			case -8: /* minus8 */
 				goto bad_option;
 			case -7: /* ata66 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 				hwif->udma_four = 1;
 				goto done;
 #else
@@ -3212,11 +3170,7 @@
 	}
 	drive->revalidate = 1;
 	drive->suspend_reset = 0;
-#ifdef CONFIG_PROC_FS
-	ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
-	if (ata_ops(drive))
-		ide_add_proc_entries(drive->proc, ata_ops(drive)->proc, drive);
-#endif
+
 	return 0;
 }
 
@@ -3247,11 +3201,6 @@
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
 	pnpide_init(0);
 #endif
-#ifdef CONFIG_PROC_FS
-	if (ata_ops(drive))
-		ide_remove_proc_entries(drive->proc, ata_ops(drive)->proc);
-	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
-#endif
 	auto_remove_settings(drive);
 	drive->driver = NULL;
 	drive->present = 0;
@@ -3329,11 +3278,6 @@
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_delay_50ms);
 EXPORT_SYMBOL(ide_stall_queue);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(ide_add_proc_entries);
-EXPORT_SYMBOL(ide_remove_proc_entries);
-EXPORT_SYMBOL(proc_ide_read_geometry);
-#endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
 
@@ -3428,12 +3372,78 @@
 
 	initializing = 1;
 
+#ifdef CONFIG_PCI
+	/*
+	 * Register the host chip drivers.
+	 */
+# ifdef CONFIG_BLK_DEV_PIIX
+	init_piix();
+# endif
+# ifdef CONFIG_BLK_DEV_VIA82CXXX
+	init_via82cxxx();
+# endif
+# ifdef CONFIG_BLK_DEV_PDC202XX
+	init_pdc202xx();
+# endif
+# ifdef CONFIG_BLK_DEV_RZ1000
+	init_rz1000();
+# endif
+# ifdef CONFIG_BLK_DEV_SIS5513
+	init_sis5513();
+# endif
+# ifdef CONFIG_BLK_DEV_CMD64X
+	init_cmd64x();
+# endif
+# ifdef CONFIG_BLK_DEV_OPTI621
+	init_opti621();
+# endif
+# ifdef CONFIG_BLK_DEV_TRM290
+	init_trm290();
+# endif
+# ifdef CONFIG_BLK_DEV_NS87415
+	init_ns87415();
+# endif
+# ifdef CONFIG_BLK_DEV_AEC62XX
+	init_aec62xx();
+# endif
+# ifdef CONFIG_BLK_DEV_SL82C105
+	init_sl82c105();
+# endif
+# ifdef CONFIG_BLK_DEV_HPT34X
+	init_hpt34x();
+# endif
+# ifdef CONFIG_BLK_DEV_HPT366
+	init_hpt366();
+# endif
+# ifdef CONFIG_BLK_DEV_ALI15X3
+	init_ali15x3();
+# endif
+# ifdef CONFIG_BLK_DEV_CY82C693
+	init_cy82c693();
+# endif
+# ifdef CONFIG_BLK_DEV_CS5530
+	init_cs5530();
+# endif
+# ifdef CONFIG_BLK_DEV_AMD74XX
+	init_amd74xx();
+# endif
+# ifdef CONFIG_BLK_DEV_PDC_ADMA
+	init_pdcadma();
+# endif
+# ifdef CONFIG_BLK_DEV_SVWKS
+	init_svwks();
+# endif
+# ifdef CONFIG_BLK_DEV_IT8172
+	init_it8172();
+# endif
+
+	init_ata_pci_misc();
+
 	/*
 	 * Detect and initialize "known" IDE host chip types.
 	 */
-#ifdef CONFIG_PCI
 	if (pci_present()) {
-# ifdef CONFIG_BLK_DEV_IDEPCI
+# ifdef CONFIG_PCI
 		ide_scan_pcibus(ide_scan_direction);
 # else
 #  ifdef CONFIG_BLK_DEV_RZ1000
@@ -3499,10 +3509,6 @@
 # endif
 #endif
 
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
 	/*
 	 * Initialize all device type driver modules.
 	 */
@@ -3568,9 +3574,6 @@
 		ide_unregister(&ide_hwifs[h]);
 	}
 
-# ifdef CONFIG_PROC_FS
-	proc_ide_destroy();
-# endif
 	devfs_unregister(ide_devfs_handle);
 }
 
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Thu May  9 15:21:02 2002
+++ b/drivers/ide/it8172.c	Thu May  9 15:21:02 2002
@@ -37,11 +37,13 @@
 #include <linux/ide.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/it8172/it8172_int.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 /*
  * Prototypes
@@ -224,25 +226,25 @@
 #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
 
 
-unsigned int __init pci_init_it8172 (struct pci_dev *dev)
+static unsigned int __init pci_init_it8172 (struct pci_dev *dev)
 {
     unsigned char progif;
-    
+
     /*
      * Place both IDE interfaces into PCI "native" mode
      */
     (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);
 
     return IT8172_IDE_IRQ;
 }
 
 
-void __init ide_init_it8172(struct ata_channel *hwif)
+static void __init ide_init_it8172(struct ata_channel *hwif)
 {
     struct pci_dev* dev = hwif->pci_dev;
     unsigned long cmdBase, ctrlBase;
-    
+
     hwif->tuneproc = &it8172_tune_drive;
     hwif->drives[0].autotune = 1;
     hwif->drives[1].autotune = 1;
@@ -253,17 +255,35 @@
 #ifndef CONFIG_BLK_DEV_IDEDMA
     hwif->autodma = 0;
 #else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_IT8172_TUNING
+# ifdef CONFIG_IT8172_TUNING
     hwif->autodma = 1;
     hwif->dmaproc = &it8172_dmaproc;
     hwif->speedproc = &it8172_tune_chipset;
-#endif /* CONFIG_IT8172_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
+# endif
+#endif
 
     cmdBase = dev->resource[0].start;
     ctrlBase = dev->resource[1].start;
-    
+
     ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
     memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
     hwif->noprobe = 0;
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+        vendor:	PCI_VENDOR_ID_ITE,
+	device: PCI_DEVICE_ID_ITE_IT8172G,
+	init_chipset: pci_init_it8172,
+	init_channel: ide_init_it8172,
+	exnablebits: {{0x00,0x00,0x00}, {0x40,0x00,0x01} },
+	bootable: ON_BOARD
+};
+
+int __init init_it8172(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Thu May  9 15:21:05 2002
+++ b/drivers/ide/ns87415.c	Thu May  9 15:21:05 2002
@@ -19,11 +19,13 @@
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
+#include "pcihost.h"
+
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
 /*
@@ -134,7 +136,7 @@
 }
 #endif
 
-void __init ide_init_ns87415(struct ata_channel *hwif)
+static void __init ide_init_ns87415(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned int ctrl, using_inta;
@@ -236,4 +238,19 @@
 #endif
 
 	hwif->selectproc = &ns87415_selectproc;
+}
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_NS,
+	device: PCI_DEVICE_ID_NS_87415,
+	init_channel: ide_init_ns87415,
+	bootable: ON_BOARD,
+};
+
+int __init init_ns87415(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/opti621.c b/drivers/ide/opti621.c
--- a/drivers/ide/opti621.c	Thu May  9 15:21:03 2002
+++ b/drivers/ide/opti621.c	Thu May  9 15:21:03 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
  *
  * Authors:
@@ -92,12 +93,14 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #define OPTI621_MAX_PIO 3
 /* In fact, I do not have any PIO 4 drive
@@ -310,9 +313,38 @@
 /*
  * ide_init_opti621() is called once for each hwif found at boot.
  */
-void __init ide_init_opti621(struct ata_channel *hwif)
+static void __init ide_init_opti621(struct ata_channel *hwif)
 {
 	hwif->drives[0].drive_data = PIO_DONT_KNOW;
 	hwif->drives[1].drive_data = PIO_DONT_KNOW;
 	hwif->tuneproc = &opti621_tune_drive;
+}
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_OPTI,
+		device: PCI_DEVICE_ID_OPTI_82C621,
+		init_channel: ide_init_opti621,
+		enablebits: {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_OPTI,
+		device: PCI_DEVICE_ID_OPTI_82C825,
+		init_channel: ide_init_opti621,
+		enablebits: {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		bootable: ON_BOARD
+	},
+};
+
+int __init init_opti621(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
 }
diff -Nru a/drivers/ide/pcihost.h b/drivers/ide/pcihost.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pcihost.h	Thu May  9 15:21:10 2002
@@ -0,0 +1,136 @@
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
+ * Copyright (C) 2002 Marcin Dalecki <martin@dalecki.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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
+ */
+
+/*
+ * Declarations needed for the handling of PCI (mostly) based host chip set
+ * interfaces.
+ */
+
+#ifdef CONFIG_BLK_DEV_PIIX
+extern int init_piix(void);
+#endif
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern int init_via82cxxx(void);
+#endif
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern int init_pdc202xx(void);
+#endif
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern int init_rz1000(void);
+#endif
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern int init_sis5513(void);
+#endif
+#ifdef CONFIG_BLK_DEV_CMD64X
+extern int init_cmd64x(void);
+#endif
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern int init_opti621(void);
+#endif
+#ifdef CONFIG_BLK_DEV_TRM290
+extern int init_trm290(void);
+#endif
+#ifdef CONFIG_BLK_DEV_NS87415
+extern int init_ns87415(void);
+#endif
+#ifdef CONFIG_BLK_DEV_AEC62XX
+extern int init_aec62xx(void);
+#endif
+#ifdef CONFIG_BLK_DEV_SL82C105
+extern int init_sl82c105(void);
+#endif
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern int init_hpt34x(void);
+#endif
+#ifdef CONFIG_BLK_DEV_HPT366
+extern int init_hpt366(void);
+#endif
+#ifdef CONFIG_BLK_DEV_ALI15X3
+extern int init_ali15x3(void);
+#endif
+#ifdef CONFIG_BLK_DEV_CY82C693
+extern int init_cy82c693(void);
+#endif
+#ifdef CONFIG_BLK_DEV_CS5530
+extern int init_cs5530(void);
+#endif
+#ifdef CONFIG_BLK_DEV_AMD74XX
+extern int init_amd74xx(void);
+#endif
+#ifdef CONFIG_BLK_DEV_PDC_ADMA
+extern int init_pdcadma(void);
+#endif
+#ifdef CONFIG_BLK_DEV_SVWKS
+extern int init_svwks(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IT8172
+extern int init_it8172(void);
+#endif
+extern int init_ata_pci_misc(void);
+
+/*
+ * Some combi chips, which can be used on the PCI bus or the VL bus can be in
+ * some systems acessed either through the PCI config space or through the
+ * hosts IO bus.  If the corresponding initialization driver is using the host
+ * IO space to deal with them please define the following.
+ */
+
+#define	ATA_PCI_IGNORE	((void *)-1)
+
+/*
+ * Just to prevent us from having too many tinny headers we have consolidated
+ * all those declarations here.
+ */
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_probe_for_rz100x(void);
+#endif
+
+typedef struct ide_pci_enablebit_s {
+	u8	reg;	/* pci configuration register holding the enable-bit */
+	u8	mask;	/* mask used to isolate the enable-bit */
+	u8	val;	/* expected value of masked register when "enabled" */
+} ide_pci_enablebit_t;
+
+/* Flags used to untangle quirk handling.
+ */
+#define ATA_F_DMA	0x01
+#define ATA_F_NODMA	0x02	/* no DMA mode supported at all */
+#define ATA_F_NOADMA	0x04	/* DMA has to be enabled explicitely */
+#define ATA_F_FIXIRQ	0x08	/* fixed irq wiring */
+#define ATA_F_SER	0x10	/* serialize on first and second channel interrupts */
+#define ATA_F_IRQ	0x20	/* trust IRQ information from config */
+#define ATA_F_PHACK	0x40	/* apply PROMISE hacks */
+#define ATA_F_HPTHACK	0x80	/* apply HPT366 hacks */
+
+
+struct ata_pci_device {
+	unsigned short		vendor;
+	unsigned short		device;
+	unsigned int		(*init_chipset)(struct pci_dev *);
+	unsigned int		(*ata66_check)(struct ata_channel *);
+	void			(*init_channel)(struct ata_channel *);
+	void			(*init_dma)(struct ata_channel *, unsigned long);
+	ide_pci_enablebit_t	enablebits[2];
+	unsigned int		bootable;
+	unsigned int		extra;
+	unsigned int		flags;
+	struct ata_pci_device *next;	/* beware we link the netries in pleace */
+};
+
+extern void ata_register_chipset(struct ata_pci_device *d);
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Thu May  9 15:21:09 2002
+++ b/drivers/ide/pdc202xx.c	Thu May  9 15:21:09 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  *  linux/drivers/ide/pdc202xx.c	Version 0.30	Mar. 18, 2000
  *
  *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
@@ -47,11 +48,12 @@
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
 
-#define DISPLAY_PDC202XX_TIMINGS
+#undef DISPLAY_PDC202XX_TIMINGS
 
 #ifndef SPLIT_BYTE
 #define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
@@ -377,7 +379,7 @@
 
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+static int check_in_drive_lists(struct ata_device *drive, const char **list)
 {
 	struct hd_driveid *id = drive->id;
 
@@ -397,7 +399,7 @@
 	return 0;
 }
 
-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
+static int pdc202xx_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev = hwif->pci_dev;
@@ -521,7 +523,7 @@
 	return err;
 }
 
-static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
+static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed)
 {
 	struct ata_channel *hwif = drive->channel;
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -682,7 +684,7 @@
  * 180, 120,  90,  90,  90,  60,  30
  *  11,   5,   4,   3,   2,   1,   0
  */
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+static int config_chipset_for_pio(struct ata_device *drive, byte pio)
 {
 	byte speed = 0x00;
 
@@ -694,13 +696,13 @@
 	return ((int) pdc202xx_tune_chipset(drive, speed));
 }
 
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
+static void pdc202xx_tune_drive(struct ata_device *drive, byte pio)
 {
 	(void) config_chipset_for_pio(drive, pio);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+static int config_chipset_for_dma(struct ata_device *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
 	struct ata_channel *hwif = drive->channel;
@@ -921,7 +923,7 @@
 						     0);
 }
 
-static int config_drive_xfer_rate (ide_drive_t *drive)
+static int config_drive_xfer_rate(struct ata_device *drive)
 {
 	struct hd_driveid *id = drive->id;
 	struct ata_channel *hwif = drive->channel;
@@ -977,7 +979,7 @@
 	return 0;
 }
 
-int pdc202xx_quirkproc (ide_drive_t *drive)
+int pdc202xx_quirkproc(struct ata_device *drive)
 {
 	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
 }
@@ -1139,7 +1141,7 @@
 }
 #endif
 
-void pdc202xx_new_reset (ide_drive_t *drive)
+void pdc202xx_new_reset(struct ata_device *drive)
 {
 	OUT_BYTE(0x04,IDE_CONTROL_REG);
 	mdelay(1000);
@@ -1149,7 +1151,7 @@
 		drive->channel->unit ? "Secondary" : "Primary");
 }
 
-void pdc202xx_reset (ide_drive_t *drive)
+void pdc202xx_reset(struct ata_device *drive)
 {
 	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
 	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
@@ -1167,7 +1169,7 @@
  * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
  * HOTSWAP ATA Infrastructure.
  */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
+static int pdc202xx_tristate(struct ata_device * drive, int state)
 {
 #if 0
 	struct ata_channel *hwif = drive->channel;
@@ -1188,7 +1190,7 @@
 	return 0;
 }
 
-unsigned int __init pci_init_pdc202xx(struct pci_dev *dev)
+static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev)
 {
 	unsigned long high_16	= pci_resource_start(dev, 4);
 	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
@@ -1277,7 +1279,7 @@
 		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
 		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
-#endif /* CONFIG_PDC202XX_MASTER */
+#endif
 
 fttk_tx_series:
 
@@ -1287,11 +1289,11 @@
 		bmide_dev = dev;
 		pdc202xx_display_info = &pdc202xx_get_info;
 	}
-#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+#endif
 	return dev->irq;
 }
 
-unsigned int __init ata66_pdc202xx(struct ata_channel *hwif)
+static unsigned int __init ata66_pdc202xx(struct ata_channel *hwif)
 {
 	unsigned short mask = (hwif->unit) ? (1<<11) : (1<<10);
 	unsigned short CIS;
@@ -1310,7 +1312,7 @@
 	}
 }
 
-void __init ide_init_pdc202xx(struct ata_channel *hwif)
+static void __init ide_init_pdc202xx(struct ata_channel *hwif)
 {
 	hwif->tuneproc  = &pdc202xx_tune_drive;
 	hwif->quirkproc = &pdc202xx_quirkproc;
@@ -1362,4 +1364,156 @@
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
 #endif
+}
+
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+#ifdef CONFIG_PDC202XX_FORCE
+        {
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20246,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: NULL,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		extra: 16,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+        {
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20262,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA
+	},
+        {
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20265,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: ON_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA
+	},
+        {
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20267,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+#else
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20246,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: NULL,
+		init_channel: ide_init_pdc202xx,
+		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		bootable: OFF_BOARD,
+		extra: 16,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20262,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		bootable: OFF_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20265,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		enablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		bootable: OFF_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ | ATA_F_PHACK  | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20267,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		exnablebits: {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+		bootable: OFF_BOARD,
+		extra: 48,
+		flags: ATA_F_IRQ  | ATA_F_DMA
+	},
+#endif
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20268,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+	/* Promise used a different PCI identification for the raid card
+	 * apparently to try and prevent Linux detecting it and using our own
+	 * raid code. We want to detect it for the ataraid drivers, so we have
+	 * to list both here.. */
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20268R,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ  | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20269,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20275,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_PROMISE,
+		device: PCI_DEVICE_ID_PROMISE_20276,
+		init_chipset: pdc202xx_init_chipset,
+		ata66_check: ata66_pdc202xx,
+		init_channel: ide_init_pdc202xx,
+		bootable: OFF_BOARD,
+		flags: ATA_F_IRQ | ATA_F_DMA
+	},
+};
+
+int __init init_pdc202xx(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
 }
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/pdc4030.c	Thu May  9 15:21:04 2002
@@ -39,6 +39,7 @@
  *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
  *  Version 0.91	Bring in line with new bio code in 2.5.1
  *  Version 0.92	Update for IDE driver taskfile changes
+ *  Version 0.93	Sync with 2.5.10, minor taskfile changes
  */
 
 /*
@@ -380,6 +381,7 @@
 }
 
 /*
+ * promise_complete_pollfunc()
  * This is the polling function for waiting (nicely!) until drive stops
  * being busy. It is invoked at the end of a write, after the previous poll
  * has finished.
@@ -388,20 +390,20 @@
  */
 static ide_startstop_t promise_complete_pollfunc(struct ata_device *drive, struct request *rq)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct ata_channel *ch = drive->channel;
 
 	if (GET_STAT() & BUSY_STAT) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
+		if (time_before(jiffies, ch->poll_timeout)) {
 			ide_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
-		hwgroup->poll_timeout = 0;
+		ch->poll_timeout = 0;
 		printk(KERN_ERR "%s: completion timeout - still busy!\n",
 		       drive->name);
 		return ide_error(drive, "busy timeout", GET_STAT());
 	}
 
-	hwgroup->poll_timeout = 0;
+	ch->poll_timeout = 0;
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
 #endif
@@ -432,7 +434,7 @@
 			nsect = mcount;
 		mcount -= nsect;
 
-		buffer = bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -467,23 +469,23 @@
  */
 static ide_startstop_t promise_write_pollfunc(struct ata_device *drive, struct request *rq)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct ata_channel *ch = drive->channel;
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
+		if (time_before(jiffies, ch->poll_timeout)) {
 			ide_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		return ide_error (drive, "write timeout", GET_STAT());
+		ch->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed out!\n",drive->name);
+		return ide_error(drive, "write timeout", GET_STAT());
 	}
 
 	/*
 	 * Now write out last 4 sectors and poll for not BUSY
 	 */
 	promise_multwrite(drive, rq, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -501,7 +503,7 @@
  */
 static ide_startstop_t promise_write(struct ata_device *drive, struct request *rq)
 {
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct ata_channel *ch = drive->channel;
 
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
@@ -516,7 +518,7 @@
 	if (rq->nr_sectors > 4) {
 		if (promise_multwrite(drive, rq, rq->nr_sectors - 4))
 			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
 		return ide_started;
 	} else {
@@ -526,7 +528,7 @@
 	 */
 		if (promise_multwrite(drive, rq, rq->nr_sectors))
 			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		ch->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
@@ -537,13 +539,13 @@
 }
 
 /*
- * do_pdc4030_io() is called from do_rw_disk, having had the block number
- * already set up. It issues a READ or WRITE command to the Promise
+ * do_pdc4030_io() is called from promise_do_request, having had the block
+ * number already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *task, struct request *rq)
+ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *args, struct request *rq)
 {
-	struct hd_drive_task_hdr *taskfile = &task->taskfile;
+	struct hd_drive_task_hdr *taskfile = &(args->taskfile);
 	unsigned long timeout;
 	byte stat;
 
@@ -628,7 +630,7 @@
 	}
 }
 
-ide_startstop_t promise_rw_disk(struct ata_device *drive, struct request *rq, sector_t block)
+ide_startstop_t promise_do_request(struct ata_device *drive, struct request *rq, sector_t block)
 {
 	struct ata_taskfile args;
 
@@ -647,12 +649,12 @@
 	args.taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
 	args.taskfile.command		= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
 
-	ide_cmd_type_parser(&args);
-	/* We don't use the generic inerrupt handlers here? */
-	args.prehandler		= NULL;
+	/* We can't call ide_cmd_type_parser here, since it won't understand
+	   our command, but that doesn't matter, since we don't use the
+	   generic interrupt handlers either. Setup the bits of args that we
+	   will need. */
 	args.handler		= NULL;
 	rq->special		= &args;
 
 	return do_pdc4030_io(drive, &args, rq);
 }
-
diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
--- a/drivers/ide/pdcadma.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/pdcadma.c	Thu May  9 15:21:04 2002
@@ -25,6 +25,7 @@
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #undef DISPLAY_PDCADMA_TIMINGS
 
@@ -66,7 +67,7 @@
 }
 #endif
 
-unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
+static unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
 {
 #if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!pdcadma_proc) {
@@ -78,12 +79,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_pdcadma(struct ata_channel *channel)
+static unsigned int __init ata66_pdcadma(struct ata_channel *channel)
 {
 	return 1;
 }
 
-void __init ide_init_pdcadma(struct ata_channel *hwif)
+static void __init ide_init_pdcadma(struct ata_channel *hwif)
 {
 	hwif->autodma = 0;
 	hwif->dma_base = 0;
@@ -97,8 +98,31 @@
 //	}
 }
 
-void __init ide_dmacapable_pdcadma(struct ata_channel *hwif, unsigned long dmabase)
+static void __init ide_dmacapable_pdcadma(struct ata_channel *hwif, unsigned long dmabase)
 {
 //	ide_setup_dma(hwif, dmabase, 8);
 }
 
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841,
+	pci_init_pdcadma,
+	ata66_pdcadma,
+	ide_init_pdcadma,
+	ide_dmacapable_pdcadma,
+	{
+		{0x00,0x00,0x00},
+		{0x00,0x00,0x00}
+	},
+	OFF_BOARD,
+	0,
+	ATA_F_NODMA
+};
+
+int __init init_pdcadma(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
+}
diff -Nru a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c
--- a/drivers/ide/pdcraid.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/pdcraid.c	Thu May  9 15:21:06 2002
@@ -132,19 +132,6 @@
 			return 0;
 		}
 
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-			
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Thu May  9 15:21:06 2002
+++ b/drivers/ide/piix.c	Thu May  9 15:21:06 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * $Id: piix.c,v 1.3 2002/03/29 16:06:06 vojtech Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik
@@ -45,9 +46,11 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #define PIIX_IDETIM0		0x40
 #define PIIX_IDETIM1		0x42
@@ -110,7 +113,7 @@
  * PIIX/ICH /proc entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -401,8 +404,7 @@
  * The initialization callback. Here we determine the IDE chip type
  * and initialize its drive independent registers.
  */
-
-unsigned int __init pci_init_piix(struct pci_dev *dev, const char *name)
+static unsigned int __init piix_init_chipset(struct pci_dev *dev)
 {
 	unsigned int u;
 	unsigned short w;
@@ -520,7 +522,7 @@
  * Register /proc/ide/piix entry
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 	if (!piix_proc) {
 		piix_base = pci_resource_start(dev, 4);
 		bmide_dev = dev;
@@ -532,12 +534,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_piix(struct ata_channel *hwif)
+static unsigned int __init piix_ata66_check(struct ata_channel *hwif)
 {
 	return ((piix_enabled & piix_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_piix(struct ata_channel *hwif)
+static void __init piix_init_channel(struct ata_channel *hwif)
 {
 	int i;
 
@@ -567,10 +569,166 @@
  * We allow the BM-DMA driver only work on enabled interfaces,
  * and only if DMA is safe with the chip and bridge.
  */
-
-void __init ide_dmacapable_piix(struct ata_channel *hwif, unsigned long dmabase)
+static void __init piix_init_dma(struct ata_channel *hwif, unsigned long dmabase)
 {
 	if (((piix_enabled >> hwif->unit) & 1)
 		&& !(piix_config->flags & PIIX_NODMA))
-			ide_setup_dma(hwif, dmabase, 8);
+			ata_init_dma(hwif, dmabase);
+}
+
+
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82371FB_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82371SB_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82371AB,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82443MX_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82372FB_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801AA_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801AB_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801BA_9,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801BA_8,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801E_9,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801CA_10,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801CA_11,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_INTEL,
+		device: PCI_DEVICE_ID_INTEL_82801DB_9,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_EFAR,
+		device: PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		init_chipset: piix_init_chipset,
+		ata66_check: piix_ata66_check,
+		init_channel: piix_init_channel,
+		init_dma: piix_init_dma,
+		enablebits: {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable: ON_BOARD
+	},
+};
+
+int __init init_piix(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+	return 0;
 }
diff -Nru a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
--- a/drivers/ide/rz1000.c	Thu May  9 15:21:02 2002
+++ b/drivers/ide/rz1000.c	Thu May  9 15:21:02 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
  *
  *  Principal Author:  mlord@pobox.com (Mark Lord)
@@ -11,7 +12,7 @@
  *  Dunno if this fixes both ports, or only the primary port (?).
  */
 
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/config.h> /* for CONFIG_PCI */
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -21,14 +22,16 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
-#include <linux/ide.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
+
+#include "pcihost.h"
 
-void __init ide_init_rz1000(struct ata_channel *hwif)	/* called from ide-pci.c */
+static void __init rz1000_init_channel(struct ata_channel *hwif)
 {
 	unsigned short reg;
 	struct pci_dev *dev = hwif->pci_dev;
@@ -45,6 +48,33 @@
 	}
 }
 
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_PCTECH,
+		device:	PCI_DEVICE_ID_PCTECH_RZ1000,
+		init_channel: rz1000_init_channel,
+		bootable: ON_BOARD
+	},
+	{
+		vendor: PCI_VENDOR_ID_PCTECH,
+		device: PCI_DEVICE_ID_PCTECH_RZ1001,
+		init_channel: rz1000_init_channel,
+		bootable: ON_BOARD
+	},
+};
+
+int __init init_rz1000(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
+}
+
 #else
 
 static void __init init_rz1000 (struct pci_dev *dev, const char *name)
@@ -82,9 +112,9 @@
 	struct pci_dev *dev = NULL;
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		init_rz1000 (dev, "RZ1000");
+		rz1000_init (dev, "RZ1000");
 	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		init_rz1000 (dev, "RZ1001");
+		rz1000_init (dev, "RZ1001");
 }
 
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Thu May  9 15:21:08 2002
+++ b/drivers/ide/serverworks.c	Thu May  9 15:21:08 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
  *
  * May be copied or modified under the terms of the GNU General Public License
@@ -85,23 +86,25 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
-#include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
-#define DISPLAY_SVWKS_TIMINGS	1
+#undef DISPLAY_SVWKS_TIMINGS
 #undef SVWKS_DEBUG_DRIVE_INFO
 
+static u8 svwks_revision = 0;
+
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
 static struct pci_dev *bmide_dev;
-static byte svwks_revision = 0;
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -237,7 +240,7 @@
 
 static struct pci_dev *isa_dev;
 
-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
+static int svwks_tune_chipset(struct ata_device *drive, byte speed)
 {
 	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
 	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
@@ -346,7 +349,7 @@
 	pci_write_config_byte(dev, drive_pci2, dma_timing);
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
-	
+
 	if (speed > XFER_PIO_4)
 		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
 	else
@@ -358,7 +361,7 @@
 	return err;
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive)
+static void config_chipset_for_pio(struct ata_device *drive)
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
@@ -396,7 +399,7 @@
 	drive->current_speed = speed;
 }
 
-static void svwks_tune_drive (ide_drive_t *drive, byte pio)
+static void svwks_tune_drive(struct ata_device *drive, byte pio)
 {
 	byte speed;
 	switch(pio) {
@@ -410,7 +413,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(struct ata_device *drive)
 {
 	struct hd_driveid *id	= drive->id;
 	struct pci_dev *dev	= drive->channel->pci_dev;
@@ -535,7 +538,7 @@
 }
 #endif
 
-unsigned int __init pci_init_svwks(struct pci_dev *dev)
+static unsigned int __init svwks_init_chipset(struct pci_dev *dev)
 {
 	unsigned int reg;
 	byte btr;
@@ -620,7 +623,7 @@
 	return 0;
 }
 
-unsigned int __init ata66_svwks(struct ata_channel *hwif)
+static unsigned int __init svwks_ata66_check(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 
@@ -635,7 +638,7 @@
 	return 0;
 }
 
-void __init ide_init_svwks(struct ata_channel *hwif)
+static void __init ide_init_svwks(struct ata_channel *hwif)
 {
 	if (!hwif->irq)
 		hwif->irq = hwif->unit ? 15 : 14;
@@ -647,7 +650,7 @@
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
+#else
 	if (hwif->dma_base) {
 #ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
@@ -661,5 +664,38 @@
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
+#endif
+}
+
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+        {
+		vendor: PCI_VENDOR_ID_SERVERWORKS,
+		device: PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		init_chipset: svwks_init_chipset,
+		ata66_check: svwks_ata66_check,
+		init_channel: ide_init_svwks,
+		bootable: ON_BOARD,
+		flags: ATA_F_DMA
+	},
+	{
+		vendor: PCI_VENDOR_ID_SERVERWORKS,
+		device: PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		init_chipset: svwks_init_chipset,
+		ata66_check: svwks_ata66_check,
+		init_channel: ide_init_svwks,
+		bootable: ON_BOARD
+	},
+};
+
+int __init init_svwks(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+        return 0;
 }
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Thu May  9 15:21:05 2002
+++ b/drivers/ide/sis5513.c	Thu May  9 15:21:05 2002
@@ -40,17 +40,18 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
-#include <linux/hdreg.h>
 
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/hdreg.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 /* When DEBUG is defined it outputs initial PCI config register
    values and changes made to them by the driver */
@@ -58,7 +59,7 @@
 /* When BROKEN_LEVEL is defined it limits the DMA mode
    at boot time to its value */
 // #define BROKEN_LEVEL XFER_SW_DMA_0
-#define DISPLAY_SIS_TIMINGS
+#undef DISPLAY_SIS_TIMINGS
 
 /* Miscellaneaous flags */
 #define SIS5513_LATENCY		0x01
@@ -741,7 +742,7 @@
 #endif
 
 /* Chip detection and general config */
-unsigned int __init pci_init_sis5513(struct pci_dev *dev)
+static unsigned int __init pci_init_sis5513(struct pci_dev *dev)
 {
 	struct pci_dev *host;
 	int i = 0;
@@ -823,7 +824,7 @@
 	return 0;
 }
 
-unsigned int __init ata66_sis5513(struct ata_channel *hwif)
+static unsigned int __init ata66_sis5513(struct ata_channel *hwif)
 {
 	byte reg48h = 0, ata66 = 0;
 	byte mask = hwif->unit ? 0x20 : 0x10;
@@ -835,7 +836,7 @@
         return ata66;
 }
 
-void __init ide_init_sis5513(struct ata_channel *hwif)
+static void __init ide_init_sis5513(struct ata_channel *hwif)
 {
 
 	hwif->irq = hwif->unit ? 15 : 14;
@@ -860,4 +861,24 @@
 #endif
 	}
 	return;
+}
+
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_SI,
+	device: PCI_DEVICE_ID_SI_5513,
+	init_chipset: pci_init_sis5513,
+	ata66_check: ata66_sis5513,
+	init_channel: ide_init_sis5513,
+	enablebits: {{0x4a,0x02,0x02}, {0x4a,0x04,0x04} },
+	bootable: ON_BOARD,
+	flags: ATA_F_NOADMA
+};
+
+int __init init_sis5513(void)
+{
+	ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/sl82c105.c	Thu May  9 15:21:04 2002
@@ -23,6 +23,7 @@
 #include <asm/dma.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
@@ -212,7 +213,7 @@
 /*
  * Enable the PCI device
  */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev)
+static unsigned int __init sl82c105_init_chipset(struct pci_dev *dev)
 {
 	unsigned char ctrl_stat;
 
@@ -225,7 +226,7 @@
 	return dev->irq;
 }
 
-void __init dma_init_sl82c105(struct ata_channel *hwif, unsigned long dma_base)
+static void __init sl82c105_init_dma(struct ata_channel *hwif, unsigned long dma_base)
 {
 	unsigned int rev;
 	byte dma_state;
@@ -246,7 +247,7 @@
 	outb(dma_state, dma_base + 2);
 
 	hwif->XXX_udma = NULL;
-	ide_setup_dma(hwif, dma_base, 8);
+	ata_init_dma(hwif, dma_base);
 	if (hwif->XXX_udma)
 		hwif->XXX_udma = sl82c105_dmaproc;
 }
@@ -254,8 +255,26 @@
 /*
  * Initialise the chip
  */
-void __init ide_init_sl82c105(struct ata_channel *hwif)
+static void __init sl82c105_init_channel(struct ata_channel *hwif)
 {
 	hwif->tuneproc = tune_sl82c105;
 }
 
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_WINBOND,
+	device: PCI_DEVICE_ID_WINBOND_82C105,
+	init_chipset: sl82c105_init_chipset,
+	init_channel: sl82c105_init_channel,
+	init_dma: sl82c105_init_dma,
+	enablebits: { {0x40,0x01,0x01}, {0x40,0x10,0x10} },
+	bootable: ON_BOARD
+};
+
+int __init init_sl82c105(void)
+{
+	ata_register_chipset(&chipset);
+
+	return 0;
+}
diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c
--- a/drivers/ide/tcq.c	Thu May  9 15:21:09 2002
+++ b/drivers/ide/tcq.c	Thu May  9 15:21:09 2002
@@ -418,7 +418,7 @@
 	 * pass NOP with sub-code 0x01 to device, so the command will not
 	 * fail there
 	 */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_raw_taskfile(drive, &args);
 	if (args.taskfile.feature & ABRT_ERR)
 		return 1;
 
@@ -448,7 +448,7 @@
 	args.taskfile.command = WIN_SETFEATURES;
 	ide_cmd_type_parser(&args);
 
-	if (ide_raw_taskfile(drive, &args, NULL)) {
+	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: failed to enable write cache\n", drive->name);
 		return 1;
 	}
@@ -462,7 +462,7 @@
 	args.taskfile.command = WIN_SETFEATURES;
 	ide_cmd_type_parser(&args);
 
-	if (ide_raw_taskfile(drive, &args, NULL)) {
+	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: disabling release interrupt fail\n", drive->name);
 		return 1;
 	}
@@ -476,7 +476,7 @@
 	args.taskfile.command = WIN_SETFEATURES;
 	ide_cmd_type_parser(&args);
 
-	if (ide_raw_taskfile(drive, &args, NULL)) {
+	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: enabling service interrupt fail\n", drive->name);
 		return 1;
 	}
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Thu May  9 15:21:03 2002
+++ b/drivers/ide/trm290.c	Thu May  9 15:21:03 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
  *
  *  Copyright (c) 1997-1998  Mark Lord
@@ -139,6 +140,8 @@
 
 #include <asm/io.h>
 
+#include "pcihost.h"
+
 static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
 	struct ata_channel *hwif = drive->channel;
@@ -249,7 +252,7 @@
 /*
  * Invoked from ide-dma.c at boot time.
  */
-void __init ide_init_trm290(struct ata_channel *hwif)
+static void __init trm290_init_channel(struct ata_channel *hwif)
 {
 	unsigned int cfgbase = 0;
 	unsigned long flags;
@@ -293,7 +296,7 @@
 			hwif->irq = primary_irq;
 	}
 
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
+	ata_init_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	hwif->udma_start = trm290_udma_start;
@@ -326,4 +329,19 @@
 		}
 	}
 #endif
+}
+
+/* module data table */
+static struct ata_pci_device chipset __initdata = {
+	vendor: PCI_VENDOR_ID_TEKRAM,
+	device: PCI_DEVICE_ID_TEKRAM_DC290,
+	init_channel: trm290_init_channel,
+	bootable: ON_BOARD
+};
+
+int __init init_trm290(void)
+{
+        ata_register_chipset(&chipset);
+
+        return 0;
 }
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Thu May  9 15:21:04 2002
+++ b/drivers/ide/via82cxxx.c	Thu May  9 15:21:04 2002
@@ -1,4 +1,5 @@
-/*
+/**** vi:set ts=8 sts=8 sw=8:************************************************
+ *
  * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
@@ -65,9 +66,11 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
 
 #include "ata-timing.h"
+#include "pcihost.h"
 
 #define VIA_IDE_ENABLE		0x40
 #define VIA_IDE_CONFIG		0x41
@@ -136,7 +139,7 @@
  * VIA /proc entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -380,7 +383,7 @@
  * and initialize its drive independent registers.
  */
 
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev)
+static unsigned int __init via82cxxx_init_chipset(struct pci_dev *dev)
 {
 	struct pci_dev *isa = NULL;
 	unsigned char t, v;
@@ -497,7 +500,7 @@
  * Setup /proc/ide/via entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#if 0 && defined(CONFIG_PROC_FS)
 	if (!via_proc) {
 		via_base = pci_resource_start(dev, 4);
 		bmide_dev = dev;
@@ -510,12 +513,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_via82cxxx(struct ata_channel *hwif)
+static unsigned int __init via82cxxx_ata66_check(struct ata_channel *hwif)
 {
 	return ((via_enabled & via_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_via82cxxx(struct ata_channel *hwif)
+static void __init via82cxxx_init_channel(struct ata_channel *hwif)
 {
 	int i;
 
@@ -546,8 +549,45 @@
  * We allow the BM-DMA driver to only work on enabled interfaces.
  */
 
-void __init ide_dmacapable_via82cxxx(struct ata_channel *hwif, unsigned long dmabase)
+static void __init via82cxxx_init_dma(struct ata_channel *hwif, unsigned long dmabase)
 {
 	if ((via_enabled >> hwif->unit) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
+		ata_init_dma(hwif, dmabase);
+}
+
+/* module data table */
+static struct ata_pci_device chipsets[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_VIA,
+		device:	PCI_DEVICE_ID_VIA_82C576_1,
+		init_chipset: via82cxxx_init_chipset,
+		ata66_check: via82cxxx_ata66_check,
+		init_channel: via82cxxx_init_channel,
+		init_dma: via82cxxx_init_dma,
+		enablebits: {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		bootable: ON_BOARD,
+		flags: ATA_F_NOADMA
+	},
+	{
+		vendor:	PCI_VENDOR_ID_VIA,
+		device:	PCI_DEVICE_ID_VIA_82C586_1,
+		init_chipset: via82cxxx_init_chipset,
+		ata66_check: via82cxxx_ata66_check,
+		init_channel: via82cxxx_init_channel,
+		init_dma: via82cxxx_init_dma,
+		enablebits: {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		bootable: ON_BOARD,
+		flags: ATA_F_NOADMA
+	},
+};
+
+int __init init_via82cxxx(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chipsets); ++i) {
+		ata_register_chipset(&chipsets[i]);
+	}
+
+	return 0;
 }
diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	Thu May  9 15:21:09 2002
+++ b/drivers/isdn/capi/capi.c	Thu May  9 15:21:09 2002
@@ -413,26 +413,6 @@
 	kmem_cache_free(capidev_cachep, cdev);
 }
 
-static struct capidev *capidev_find(u16 applid)
-{
-	// FIXME this doesn't guarantee that the device won't go away shortly
-	struct list_head *l;
-	struct capidev *p = NULL;
-
-	read_lock(&capidev_list_lock);
-	list_for_each(l, &capidev_list) {
-		p = list_entry(l, struct capidev, list);
-		if (p->applid == applid)
-			break;
-	}
-	read_unlock(&capidev_list_lock);
-	
-	if (l == &capidev_list)
-		return NULL;
-	
-	return p;
-}
-
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 /* -------- handle data queue --------------------------------------- */
 
@@ -605,6 +585,16 @@
 		return;
 	}
 
+	BUG_ON(cdev->applid != applid);
+		
+	if (CAPIMSG_COMMAND(skb->data) == CAPI_CONNECT_B3_CONF) {
+		u16 info = CAPIMSG_U16(skb->data, 12); // Info field
+		if (info == 0)
+			capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
+	}
+	if (CAPIMSG_COMMAND(skb->data) == CAPI_CONNECT_B3_IND) {
+		capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
+	}
 	if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
 		skb_queue_tail(&cdev->recvqueue, skb);
 		wake_up_interruptible(&cdev->recvwait);
@@ -754,6 +744,11 @@
 	}
 	CAPIMSG_SETAPPID(skb->data, cdev->applid);
 
+	if (CAPIMSG_COMMAND(skb->data) == CAPI_DISCONNECT_B3_RESP) {
+		capincci_free(cdev, CAPIMSG_NCCI(skb->data));
+			
+	}
+
 	cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);
 
 	if (cdev->errcode) {
@@ -1601,36 +1596,8 @@
 	return 0;
 }
 
-static void lower_callback(unsigned int cmd, u32 contr, void *data)
-{
-	struct capi_ncciinfo *np;
-	struct capidev *cdev;
-
-	switch (cmd) {
-	case KCI_CONTRUP:
-		printk(KERN_INFO "capi: controller %hu up\n", contr);
-		break;
-	case KCI_CONTRDOWN:
-		printk(KERN_INFO "capi: controller %hu down\n", contr);
-		break;
-	case KCI_NCCIUP:
-		np = (struct capi_ncciinfo *)data;
-		if ((cdev = capidev_find(np->applid)) == 0)
-			return;
-		(void)capincci_alloc(cdev, np->ncci);
-		break;
-	case KCI_NCCIDOWN:
-		np = (struct capi_ncciinfo *)data;
-		if ((cdev = capidev_find(np->applid)) == 0)
-			return;
-		(void)capincci_free(cdev, np->ncci);
-		break;
-	}
-}
-
 static struct capi_interface_user cuser = {
 	name: "capi20",
-	callback: lower_callback,
 };
 
 static char rev[32];
diff -Nru a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
--- a/drivers/isdn/capi/kcapi.c	Thu May  9 15:21:09 2002
+++ b/drivers/isdn/capi/kcapi.c	Thu May  9 15:21:09 2002
@@ -9,6 +9,10 @@
  *
  */
 
+#define DBG(format, arg...) do { \
+printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+} while (0)
+
 #define CONFIG_AVMB1_COMPAT
 
 #include <linux/config.h>
@@ -36,7 +40,6 @@
 
 /* ------------------------------------------------------------- */
 
-#define CARD_FREE	0
 #define CARD_DETECTED	1
 #define CARD_LOADING	2
 #define CARD_RUNNING	3
@@ -72,7 +75,6 @@
 struct capi_appl {
 	u16 applid;
 	capi_register_params rparam;
-	int releasing;
 	void *param;
 	void (*signal) (u16 applid, void *param);
 	struct sk_buff_head recv_queue;
@@ -99,40 +101,73 @@
 static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
 static char capi_manufakturer[64] = "AVM Berlin";
 
-#define APPL(a)		   (&applications[(a)-1])
-#define	VALID_APPLID(a)	   ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
-#define APPL_IS_FREE(a)    (APPL(a)->applid == 0)
-#define APPL_MARK_FREE(a)  do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0)
-#define APPL_MARK_USED(a)  do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0)
-
 #define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
 
-#define VALID_CARD(c)	   ((c) > 0 && (c) <= CAPI_MAXCONTR)
-#define CARD(c)		   (&cards[(c)-1])
-#define CARDNR(cp)	   (((cp)-cards)+1)
-
-static struct capi_appl applications[CAPI_MAXAPPL];
-static struct capi_ctr cards[CAPI_MAXCONTR];
-static int ncards = 0;
+static struct capi_appl *applications[CAPI_MAXAPPL];
+static struct capi_ctr *cards[CAPI_MAXCONTR];
+static int ncards;
 static struct sk_buff_head recv_queue;
-static struct capi_interface_user *capi_users = 0;
-static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
-static struct capi_driver *drivers;
+
+static LIST_HEAD(users);
+static spinlock_t users_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(drivers);
 static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
 
 static struct tq_struct tq_state_notify;
 static struct tq_struct tq_recv_notify;
 
+/* -------- ref counting -------------------------------------- */
+
+static inline struct capi_ctr *
+capi_ctr_get(struct capi_ctr *card)
+{
+	if (card->driver->owner) {
+		if (try_inc_mod_count(card->driver->owner)) {
+			DBG("MOD_COUNT INC");
+			return card;
+		} else
+			return NULL;
+	}
+	DBG("MOD_COUNT INC");
+	return card;
+}
+
+static inline void
+capi_ctr_put(struct capi_ctr *card)
+{
+	if (card->driver->owner)
+		__MOD_DEC_USE_COUNT(card->driver->owner);
+	DBG("MOD_COUNT DEC");
+}
+
+/* ------------------------------------------------------------- */
+
+static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
+{
+	if (contr - 1 >= CAPI_MAXCONTR)
+		return NULL;
+
+	return cards[contr - 1];
+}
+
+static inline struct capi_appl *get_capi_appl_by_nr(u16 applid)
+{
+	if (applid - 1 >= CAPI_MAXAPPL)
+		return NULL;
+
+	return applications[applid - 1];
+}
+
 /* -------- util functions ------------------------------------ */
 
 static char *cardstate2str(unsigned short cardstate)
 {
 	switch (cardstate) {
-        	default:
-		case CARD_FREE:		return "free";
-		case CARD_DETECTED:	return "detected";
-		case CARD_LOADING:	return "loading";
-		case CARD_RUNNING:	return "running";
+	case CARD_DETECTED:	return "detected";
+	case CARD_LOADING:	return "loading";
+	case CARD_RUNNING:	return "running";
+	default:	        return "???";
 	}
 }
 
@@ -183,9 +218,9 @@
 	int i;
 	int len = 0;
 
-	for (i=0; i < CAPI_MAXAPPL; i++) {
-		ap = &applications[i];
-		if (ap->applid == 0) continue;
+	for (i=1; i <= CAPI_MAXAPPL; i++) {
+		ap = get_capi_appl_by_nr(i);
+		if (!ap) continue;
 		len += sprintf(page+len, "%u %d %d %d %d %d\n",
 			ap->applid,
 			ap->rparam.level3cnt,
@@ -222,9 +257,9 @@
 	int i;
 	int len = 0;
 
-	for (i=0; i < CAPI_MAXAPPL; i++) {
-		ap = &applications[i];
-		if (ap->applid == 0) continue;
+	for (i=1; i <= CAPI_MAXAPPL; i++) {
+		ap = get_capi_appl_by_nr(i);
+		if (!ap) continue;
 		for (np = ap->nccilist; np; np = np->next) {
 			len += sprintf(page+len, "%d 0x%x %d %d\n",
 				np->applid,
@@ -256,11 +291,14 @@
 static int proc_driver_read_proc(char *page, char **start, off_t off,
                                        int count, int *eof, void *data)
 {
+	struct list_head *l;
 	struct capi_driver *driver;
 	int len = 0;
 
 	spin_lock(&drivers_lock);
-	for (driver = drivers; driver; driver = driver->next) {
+	list_for_each(l, &drivers) {
+		driver = list_entry(l, struct capi_driver, driver_list);
+
 		len += sprintf(page+len, "%-32s %d %s\n",
 					driver->name,
 					driver->ncontroller,
@@ -290,11 +328,13 @@
 static int proc_users_read_proc(char *page, char **start, off_t off,
                                        int count, int *eof, void *data)
 {
+	struct list_head *l;
         struct capi_interface_user *cp;
 	int len = 0;
 
-	spin_lock(&capi_users_lock);
-        for (cp = capi_users; cp ; cp = cp->next) {
+	spin_lock(&users_lock);
+	list_for_each(l, &users) {
+		cp = list_entry(l, struct capi_interface_user, user_list);
 		len += sprintf(page+len, "%s\n", cp->name);
 		if (len <= off) {
 			off -= len;
@@ -305,7 +345,7 @@
 		}
 	}
 endloop:
-	spin_unlock(&capi_users_lock);
+	spin_unlock(&users_lock);
 	*start = page+off;
 	if (len < count)
 		*eof = 1;
@@ -326,8 +366,10 @@
 	int len = 0;
 
 	for (i=0; i < CAPI_MAXCONTR; i++) {
-		cp = &cards[i];
-		if (cp->cardstate == CARD_FREE) continue;
+		cp = cards[i];
+		if (!cp)
+			continue;
+
 		len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n",
 			cp->cnr, cp->driver->name, 
 			cardstate2str(cp->cardstate),
@@ -362,9 +404,9 @@
 	int i;
 	int len = 0;
 
-	for (i=0; i < CAPI_MAXAPPL; i++) {
-		ap = &applications[i];
-		if (ap->applid == 0) continue;
+	for (i=1; i <= CAPI_MAXAPPL; i++) {
+		ap = get_capi_appl_by_nr(i);
+		if (!ap) continue;
 		len += sprintf(page+len, "%u %lu %lu %lu %lu\n",
 			ap->applid,
 			ap->nrecvctlpkt,
@@ -400,8 +442,9 @@
 	int len = 0;
 
 	for (i=0; i < CAPI_MAXCONTR; i++) {
-		cp = &cards[i];
-		if (cp->cardstate == CARD_FREE) continue;
+		cp = cards[i];
+		if (!cp)
+			continue;
 		len += sprintf(page+len, "%d %lu %lu %lu %lu\n",
 			cp->cnr, 
 			cp->nrecvctlpkt,
@@ -470,6 +513,42 @@
     }
 }
 
+/* ------------------------------------------------------------ */
+
+static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
+{
+	card = capi_ctr_get(card);
+
+	card->driver->register_appl(card, applid, rparam);
+}
+
+
+static void release_appl(struct capi_ctr *card, u16 applid)
+{
+	struct capi_appl *ap = get_capi_appl_by_nr(applid);
+	struct capi_ncci **pp, **nextpp;
+	
+	DBG("");
+	
+	for (pp = &ap->nccilist; *pp; pp = nextpp) {
+		if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+			struct capi_ncci *np = *pp;
+			*pp = np->next;
+			printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", applid, np->ncci);
+			kfree(np);
+			ap->nncci--;
+			nextpp = pp;
+		} else {
+			nextpp = &(*pp)->next;
+		}
+	}
+
+	card->driver->release_appl(card, applid);
+
+	capi_ctr_put(card);
+}
+
+
 /* -------- Notifier handling --------------------------------- */
 
 static struct capi_notifier_list{
@@ -543,65 +622,37 @@
 
 static void notify_up(u32 contr)
 {
+	struct list_head *l;
 	struct capi_interface_user *p;
+	struct capi_ctr *card = get_capi_ctr_by_nr(contr);
 
         printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
-	spin_lock(&capi_users_lock);
-	for (p = capi_users; p; p = p->next) {
+	spin_lock(&users_lock);
+	list_for_each(l, &users) {
+		p = list_entry(l, struct capi_interface_user, user_list);
 		if (!p->callback) continue;
-		(*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+		(*p->callback) (KCI_CONTRUP, contr, &card->profile);
 	}
-	spin_unlock(&capi_users_lock);
+	spin_unlock(&users_lock);
 }
 
 /* -------- KCI_CONTRDOWN ------------------------------------- */
 
 static void notify_down(u32 contr)
 {
+	struct list_head *l;
 	struct capi_interface_user *p;
+
         printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
-	spin_lock(&capi_users_lock);
-	for (p = capi_users; p; p = p->next) {
+	spin_lock(&users_lock);
+	list_for_each(l, &users) {
+		p = list_entry(l, struct capi_interface_user, user_list);
 		if (!p->callback) continue;
 		(*p->callback) (KCI_CONTRDOWN, contr, 0);
 	}
-	spin_unlock(&capi_users_lock);
+	spin_unlock(&users_lock);
 }
 
-/* -------- KCI_NCCIUP ---------------------------------------- */
-
-static void notify_ncciup(u32 contr, u16 applid, u32 ncci)
-{
-	struct capi_interface_user *p;
-	struct capi_ncciinfo n;
-	n.applid = applid;
-	n.ncci = ncci;
-        /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
-	spin_lock(&capi_users_lock);
-	for (p = capi_users; p; p = p->next) {
-		if (!p->callback) continue;
-		(*p->callback) (KCI_NCCIUP, contr, &n);
-	}
-	spin_unlock(&capi_users_lock);
-};
-
-/* -------- KCI_NCCIDOWN -------------------------------------- */
-
-static void notify_nccidown(u32 contr, u16 applid, u32 ncci)
-{
-	struct capi_interface_user *p;
-	struct capi_ncciinfo n;
-	n.applid = applid;
-	n.ncci = ncci;
-        /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
-	spin_lock(&capi_users_lock);
-	for (p = capi_users; p; p = p->next) {
-		if (!p->callback) continue;
-		(*p->callback) (KCI_NCCIDOWN, contr, &n);
-	}
-	spin_unlock(&capi_users_lock);
-};
-
 /* ------------------------------------------------------------ */
 
 static void inline notify_doit(struct capi_notifier *np)
@@ -613,12 +664,6 @@
 		case KCI_CONTRDOWN:
 			notify_down(np->controller);
 			break;
-		case KCI_NCCIUP:
-			notify_ncciup(np->controller, np->applid, np->ncci);
-			break;
-		case KCI_NCCIDOWN:
-			notify_nccidown(np->controller, np->applid, np->ncci);
-			break;
 	}
 }
 
@@ -685,32 +730,6 @@
 	return 0;
 }
 
-static void controllercb_appl_registered(struct capi_ctr * card, u16 appl)
-{
-}
-
-static void controllercb_appl_released(struct capi_ctr * card, u16 appl)
-{
-	struct capi_ncci **pp, **nextpp;
-	for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
-		if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
-			struct capi_ncci *np = *pp;
-			*pp = np->next;
-			printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", appl, np->ncci);
-			kfree(np);
-			APPL(appl)->nncci--;
-			nextpp = pp;
-		} else {
-			nextpp = &(*pp)->next;
-		}
-	}
-	APPL(appl)->releasing--;
-	if (APPL(appl)->releasing <= 0) {
-		APPL(appl)->signal = 0;
-		APPL_MARK_FREE(appl);
-		printk(KERN_INFO "kcapi: appl %d down\n", appl);
-	}
-}
 /*
  * ncci management
  */
@@ -719,7 +738,9 @@
 					u16 appl, u32 ncci, u32 winsize)
 {
 	struct capi_ncci *np;
-	if (!VALID_APPLID(appl)) {
+	struct capi_appl *ap = get_capi_appl_by_nr(appl);
+
+	if (!ap) {
 		printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
 		return;
 	}
@@ -736,30 +757,28 @@
 	np->ncci = ncci;
 	np->winsize = winsize;
 	mq_init(np);
-	np->next = APPL(appl)->nccilist;
-	APPL(appl)->nccilist = np;
-	APPL(appl)->nncci++;
+	np->next = ap->nccilist;
+	ap->nccilist = np;
+	ap->nncci++;
 	printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
-
-	notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
 }
 
 static void controllercb_free_ncci(struct capi_ctr * card,
 				u16 appl, u32 ncci)
 {
 	struct capi_ncci **pp;
-	if (!VALID_APPLID(appl)) {
+	struct capi_appl *ap = get_capi_appl_by_nr(appl);
+	if (!ap) {
 		printk(KERN_ERR "free_ncci: illegal appl %d\n", appl);
 		return;
 	}
-	for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) {
+	for (pp = &ap->nccilist; *pp; pp = &(*pp)->next) {
 		if ((*pp)->ncci == ncci) {
 			struct capi_ncci *np = *pp;
 			*pp = np->next;
 			kfree(np);
-			APPL(appl)->nncci--;
+			ap->nncci--;
 			printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
-			notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
 			return;
 		}
 	}
@@ -782,37 +801,38 @@
 static void recv_handler(void *dummy)
 {
 	struct sk_buff *skb;
+	struct capi_appl *ap;
+	struct capi_ncci *np;
 
 	while ((skb = skb_dequeue(&recv_queue)) != 0) {
-		u16 appl = CAPIMSG_APPID(skb->data);
-		struct capi_ncci *np;
-		if (!VALID_APPLID(appl)) {
+		ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
+		if (!ap) {
 			printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n",
-			       appl, capi_message2str(skb->data));
+			       ap->applid, capi_message2str(skb->data));
 			kfree_skb(skb);
 			continue;
 		}
-		if (APPL(appl)->signal == 0) {
+		if (ap->signal == 0) {
 			printk(KERN_ERR "kcapi: recv_handler: applid %d has no signal function\n",
-			       appl);
+			       ap->applid);
 			kfree_skb(skb);
 			continue;
 		}
 		if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
 		    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
-	            && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0
+	            && (np = find_ncci(ap, CAPIMSG_NCCI(skb->data))) != 0
 		    && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
 			printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
 				CAPIMSG_MSGID(skb->data), np->ncci);
 		}
 		if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
 		    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
-			APPL(appl)->nrecvdatapkt++;
+			ap->nrecvdatapkt++;
 		} else {
-			APPL(appl)->nrecvctlpkt++;
+			ap->nrecvctlpkt++;
 		}
-		skb_queue_tail(&APPL(appl)->recv_queue, skb);
-		(APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param);
+		skb_queue_tail(&ap->recv_queue, skb);
+		(ap->signal) (ap->applid, ap->param);
 	}
 }
 
@@ -863,27 +883,28 @@
 static void controllercb_ready(struct capi_ctr * card)
 {
 	u16 appl;
+	struct capi_appl *ap;
 
 	card->cardstate = CARD_RUNNING;
 
 	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-		if (!VALID_APPLID(appl)) continue;
-		if (APPL(appl)->releasing) continue;
-		card->driver->register_appl(card, appl, &APPL(appl)->rparam);
+		ap = get_capi_appl_by_nr(appl);
+		if (!ap) continue;
+		register_appl(card, appl, &ap->rparam);
 	}
 
         printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
-		CARDNR(card), card->name);
+	       card->cnr, card->name);
 
-	notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
+	notify_push(KCI_CONTRUP, card->cnr, 0, 0);
 }
 
 static void controllercb_reseted(struct capi_ctr * card)
 {
 	u16 appl;
 
-        if (card->cardstate == CARD_FREE)
-		return;
+	DBG("");
+
         if (card->cardstate == CARD_DETECTED)
 		return;
 
@@ -895,30 +916,35 @@
 	memset(card->serial, 0, sizeof(card->serial));
 
 	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+		struct capi_appl *ap = get_capi_appl_by_nr(appl);
 		struct capi_ncci **pp, **nextpp;
-		for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+
+		if (!ap)
+			continue;
+
+		for (pp = &ap->nccilist; *pp; pp = nextpp) {
 			if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
 				struct capi_ncci *np = *pp;
 				*pp = np->next;
 				printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
-				notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
 				kfree(np);
 				nextpp = pp;
 			} else {
 				nextpp = &(*pp)->next;
 			}
 		}
+		capi_ctr_put(card);
 	}
 
-	printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
+	printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr);
 
-	notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
+	notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
 }
 
 static void controllercb_suspend_output(struct capi_ctr *card)
 {
 	if (!card->blocked) {
-		printk(KERN_DEBUG "kcapi: card %d suspend\n", CARDNR(card));
+		printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
 		card->blocked = 1;
 	}
 }
@@ -926,7 +952,7 @@
 static void controllercb_resume_output(struct capi_ctr *card)
 {
 	if (card->blocked) {
-		printk(KERN_DEBUG "kcapi: card %d resume\n", CARDNR(card));
+		printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
 		card->blocked = 0;
 	}
 }
@@ -935,21 +961,27 @@
 
 
 struct capi_ctr *
-drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata)
+attach_capi_ctr(struct capi_driver *driver, char *name, void *driverdata)
 {
-	struct capi_ctr *card, **pp;
+	struct capi_ctr *card;
 	int i;
 
-	for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ;
-   
+	for (i=0; i < CAPI_MAXCONTR; i++) {
+		if (cards[i] == NULL)
+			break;
+	}
 	if (i == CAPI_MAXCONTR) {
 		printk(KERN_ERR "kcapi: out of controller slots\n");
-	   	return 0;
+	   	return NULL;
 	}
-	card = &cards[i];
+	card = kmalloc(sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return NULL;
+
+	cards[i] = card;
 	memset(card, 0, sizeof(struct capi_ctr));
 	card->driver = driver;
-	card->cnr = CARDNR(card);
+	card->cnr = i + 1;
 	strncpy(card->name, name, sizeof(card->name));
 	card->cardstate = CARD_DETECTED;
 	card->blocked = 0;
@@ -961,14 +993,10 @@
         card->suspend_output = controllercb_suspend_output;
         card->resume_output = controllercb_resume_output;
         card->handle_capimsg = controllercb_handle_capimsg;
-	card->appl_registered = controllercb_appl_registered;
-	card->appl_released = controllercb_appl_released;
         card->new_ncci = controllercb_new_ncci;
         card->free_ncci = controllercb_free_ncci;
 
-	for (pp = &driver->controller; *pp; pp = &(*pp)->next) ;
-	card->next = 0;
-	*pp = card;
+	list_add_tail(&card->driver_list, &driver->contr_head);
 	driver->ncontroller++;
 	sprintf(card->procfn, "capi/controllers/%d", card->cnr);
 	card->procent = create_proc_entry(card->procfn, 0, 0);
@@ -985,33 +1013,33 @@
 	return card;
 }
 
-static int drivercb_detach_ctr(struct capi_ctr *card)
+EXPORT_SYMBOL(attach_capi_ctr);
+
+int detach_capi_ctr(struct capi_ctr *card)
 {
 	struct capi_driver *driver = card->driver;
-	struct capi_ctr **pp;
 
-        if (card->cardstate == CARD_FREE)
-		return 0;
         if (card->cardstate != CARD_DETECTED)
 		controllercb_reseted(card);
-	for (pp = &driver->controller; *pp ; pp = &(*pp)->next) {
-        	if (*pp == card) {
-	        	*pp = card->next;
-			driver->ncontroller--;
-			ncards--;
-	        	break;
-		}
-	}
+
+	list_del(&card->driver_list);
+	driver->ncontroller--;
+	ncards--;
+
 	if (card->procent) {
 	   remove_proc_entry(card->procfn, 0);
 	   card->procent = 0;
 	}
-	card->cardstate = CARD_FREE;
+	cards[card->cnr - 1] = NULL;
 	printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
 			card->cnr, card->name);
+	kfree(card);
+
 	return 0;
 }
 
+EXPORT_SYMBOL(detach_capi_ctr);
+
 /* ------------------------------------------------------------- */
 
 /* fallback if no driver read_proc function defined by driver */
@@ -1034,21 +1062,14 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface di = {
-    drivercb_attach_ctr,
-    drivercb_detach_ctr,
-};
-
-struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
+void attach_capi_driver(struct capi_driver *driver)
 {
-	struct capi_driver **pp;
+	INIT_LIST_HEAD(&driver->contr_head);
 
-	MOD_INC_USE_COUNT;
 	spin_lock(&drivers_lock);
-	for (pp = &drivers; *pp; pp = &(*pp)->next) ;
-	driver->next = 0;
-	*pp = driver;
+	list_add_tail(&driver->driver_list, &drivers);
 	spin_unlock(&drivers_lock);
+
 	printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
 	sprintf(driver->procfn, "capi/drivers/%s", driver->name);
 	driver->procent = create_proc_entry(driver->procfn, 0, 0);
@@ -1062,28 +1083,25 @@
 	   }
 	   driver->procent->data = driver;
 	}
-	return &di;
 }
 
+EXPORT_SYMBOL(attach_capi_driver);
+
 void detach_capi_driver(struct capi_driver *driver)
 {
-	struct capi_driver **pp;
 	spin_lock(&drivers_lock);
-	for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
-	if (*pp) {
-		*pp = (*pp)->next;
-		printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
-	} else {
-		printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
-	}
+	list_del(&driver->driver_list);
 	spin_unlock(&drivers_lock);
+
+	printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
 	if (driver->procent) {
 	   remove_proc_entry(driver->procfn, 0);
 	   driver->procent = 0;
 	}
-	MOD_DEC_USE_COUNT;
 }
 
+EXPORT_SYMBOL(detach_capi_driver);
+
 /* ------------------------------------------------------------- */
 /* -------- CAPI2.0 Interface ---------------------------------- */
 /* ------------------------------------------------------------- */
@@ -1092,7 +1110,7 @@
 {
 	int i;
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (cards[i].cardstate == CARD_RUNNING)
+		if (cards[i] && cards[i]->cardstate == CARD_RUNNING)
 			return CAPI_NOERROR;
 	}
 	return CAPI_REGNOTINSTALLED;
@@ -1100,30 +1118,39 @@
 
 static u16 capi_register(capi_register_params * rparam, u16 * applidp)
 {
+	struct capi_appl *ap;
 	int appl;
 	int i;
 
+	DBG("");
+
 	if (rparam->datablklen < 128)
 		return CAPI_LOGBLKSIZETOSMALL;
 
 	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-		if (APPL_IS_FREE(appl))
+		if (applications[appl - 1] == NULL)
 			break;
 	}
 	if (appl > CAPI_MAXAPPL)
 		return CAPI_TOOMANYAPPLS;
 
-	APPL_MARK_USED(appl);
-	skb_queue_head_init(&APPL(appl)->recv_queue);
-	APPL(appl)->nncci = 0;
+	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return CAPI_REGOSRESOURCEERR;
+
+	memset(ap, 0, sizeof(*ap));
+	ap->applid = appl;
+	applications[appl - 1] = ap;
+	
+	skb_queue_head_init(&ap->recv_queue);
+	ap->nncci = 0;
 
-	memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
+	memcpy(&ap->rparam, rparam, sizeof(capi_register_params));
 
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (cards[i].cardstate != CARD_RUNNING)
+		if (!cards[i] || cards[i]->cardstate != CARD_RUNNING)
 			continue;
-		cards[i].driver->register_appl(&cards[i], appl,
-						&APPL(appl)->rparam);
+		register_appl(cards[i], appl, &ap->rparam);
 	}
 	*applidp = appl;
 	printk(KERN_INFO "kcapi: appl %d up\n", appl);
@@ -1133,92 +1160,97 @@
 
 static u16 capi_release(u16 applid)
 {
+	struct capi_appl *ap = get_capi_appl_by_nr(applid);
 	int i;
 
-	if (!VALID_APPLID(applid) || APPL(applid)->releasing)
+	DBG("applid %#x", applid);
+
+	if (!ap)
 		return CAPI_ILLAPPNR;
-	APPL(applid)->releasing++;
-	skb_queue_purge(&APPL(applid)->recv_queue);
+
+	skb_queue_purge(&ap->recv_queue);
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
-		if (cards[i].cardstate != CARD_RUNNING)
+		if (!cards[i] || cards[i]->cardstate != CARD_RUNNING)
 			continue;
-		APPL(applid)->releasing++;
-		cards[i].driver->release_appl(&cards[i], applid);
-	}
-	APPL(applid)->releasing--;
-	if (APPL(applid)->releasing <= 0) {
-	        APPL(applid)->signal = 0;
-		APPL_MARK_FREE(applid);
-		printk(KERN_INFO "kcapi: appl %d down\n", applid);
+		release_appl(cards[i], applid);
 	}
+	applications[applid - 1] = NULL;
+	kfree(ap);
+	printk(KERN_INFO "kcapi: appl %d down\n", applid);
+
 	return CAPI_NOERROR;
 }
 
 static u16 capi_put_message(u16 applid, struct sk_buff *skb)
 {
+	struct capi_ctr *card;
+	struct capi_appl *ap;
 	struct capi_ncci *np;
-	u32 contr;
 	int showctl = 0;
 	u8 cmd, subcmd;
 
+	DBG("applid %#x", applid);
+ 
 	if (ncards == 0)
 		return CAPI_REGNOTINSTALLED;
-	if (!VALID_APPLID(applid))
+	ap = get_capi_appl_by_nr(applid);
+	if (!ap)
 		return CAPI_ILLAPPNR;
 	if (skb->len < 12
 	    || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
 	    || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
 		return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
-	contr = CAPIMSG_CONTROLLER(skb->data);
-	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) {
-		contr = 1;
-	        if (CARD(contr)->cardstate != CARD_RUNNING) 
+	card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
+	if (!card || card->cardstate != CARD_RUNNING) {
+		card = get_capi_ctr_by_nr(1); // XXX why?
+	        if (!card || card->cardstate != CARD_RUNNING) 
 			return CAPI_REGNOTINSTALLED;
 	}
-	if (CARD(contr)->blocked)
+	if (card->blocked)
 		return CAPI_SENDQUEUEFULL;
 
 	cmd = CAPIMSG_COMMAND(skb->data);
         subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 
 	if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
-	    	if ((np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0
+	    	if ((np = find_ncci(ap, CAPIMSG_NCCI(skb->data))) != 0
 	            && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
 			return CAPI_SENDQUEUEFULL;
-		CARD(contr)->nsentdatapkt++;
-		APPL(applid)->nsentdatapkt++;
-	        if (CARD(contr)->traceflag > 2) showctl |= 2;
+		card->nsentdatapkt++;
+		ap->nsentdatapkt++;
+	        if (card->traceflag > 2) showctl |= 2;
 	} else {
-		CARD(contr)->nsentctlpkt++;
-		APPL(applid)->nsentctlpkt++;
-	        if (CARD(contr)->traceflag) showctl |= 2;
+		card->nsentctlpkt++;
+		ap->nsentctlpkt++;
+	        if (card->traceflag) showctl |= 2;
 	}
-	showctl |= (CARD(contr)->traceflag & 1);
+	showctl |= (card->traceflag & 1);
 	if (showctl & 2) {
 		if (showctl & 1) {
-			printk(KERN_DEBUG "kcapi: put [0x%lx] id#%d %s len=%u\n",
-			       (unsigned long) contr,
+			printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n",
+			       CAPIMSG_CONTROLLER(skb->data),
 			       CAPIMSG_APPID(skb->data),
 			       capi_cmd2str(cmd, subcmd),
 			       CAPIMSG_LEN(skb->data));
 		} else {
-			printk(KERN_DEBUG "kcapi: put [0x%lx] %s\n",
-					(unsigned long) contr,
-					capi_message2str(skb->data));
+			printk(KERN_DEBUG "kcapi: put [%#x] %s\n",
+			       CAPIMSG_CONTROLLER(skb->data),
+			       capi_message2str(skb->data));
 		}
 
 	}
-	CARD(contr)->driver->send_message(CARD(contr), skb);
+	card->driver->send_message(card, skb);
 	return CAPI_NOERROR;
 }
 
 static u16 capi_get_message(u16 applid, struct sk_buff **msgp)
 {
+	struct capi_appl *ap = get_capi_appl_by_nr(applid);
 	struct sk_buff *skb;
 
-	if (!VALID_APPLID(applid))
+	if (!ap)
 		return CAPI_ILLAPPNR;
-	if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0)
+	if ((skb = skb_dequeue(&ap->recv_queue)) == 0)
 		return CAPI_RECEIVEQUEUEEMPTY;
 	*msgp = skb;
 	return CAPI_NOERROR;
@@ -1228,73 +1260,92 @@
 			     void (*signal) (u16 applid, void *param),
 			     void *param)
 {
-	if (!VALID_APPLID(applid))
+	struct capi_appl *ap = get_capi_appl_by_nr(applid);
+
+	if (!ap)
 		return CAPI_ILLAPPNR;
-	APPL(applid)->signal = signal;
-	APPL(applid)->param = param;
+	ap->signal = signal;
+	ap->param = param;
 	return CAPI_NOERROR;
 }
 
 static u16 capi_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
 {
+	struct capi_ctr *card;
+
 	if (contr == 0) {
 		strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
 		return CAPI_NOERROR;
 	}
-	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+	card = get_capi_ctr_by_nr(contr);
+	if (!card || card->cardstate != CARD_RUNNING) 
 		return CAPI_REGNOTINSTALLED;
 
-	strncpy(buf, CARD(contr)->manu, CAPI_MANUFACTURER_LEN);
+	strncpy(buf, card->manu, CAPI_MANUFACTURER_LEN);
 	return CAPI_NOERROR;
 }
 
 static u16 capi_get_version(u32 contr, struct capi_version *verp)
 {
+	struct capi_ctr *card;
+
 	if (contr == 0) {
 		*verp = driver_version;
 		return CAPI_NOERROR;
 	}
-	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+	card = get_capi_ctr_by_nr(contr);
+	if (!card || card->cardstate != CARD_RUNNING) 
 		return CAPI_REGNOTINSTALLED;
 
-	memcpy((void *) verp, &CARD(contr)->version, sizeof(capi_version));
+	memcpy((void *) verp, &card->version, sizeof(capi_version));
 	return CAPI_NOERROR;
 }
 
 static u16 capi_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN])
 {
+	struct capi_ctr *card;
+
 	if (contr == 0) {
 		strncpy(serial, driver_serial, CAPI_SERIAL_LEN);
 		return CAPI_NOERROR;
 	}
-	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+	card = get_capi_ctr_by_nr(contr);
+	if (!card || card->cardstate != CARD_RUNNING) 
 		return CAPI_REGNOTINSTALLED;
 
-	strncpy((void *) serial, CARD(contr)->serial, CAPI_SERIAL_LEN);
+	strncpy((void *) serial, card->serial, CAPI_SERIAL_LEN);
 	return CAPI_NOERROR;
 }
 
 static u16 capi_get_profile(u32 contr, struct capi_profile *profp)
 {
+	struct capi_ctr *card;
+
 	if (contr == 0) {
 		profp->ncontroller = ncards;
 		return CAPI_NOERROR;
 	}
-	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+	card = get_capi_ctr_by_nr(contr);
+	if (!card || card->cardstate != CARD_RUNNING) 
 		return CAPI_REGNOTINSTALLED;
 
-	memcpy((void *) profp, &CARD(contr)->profile,
+	memcpy((void *) profp, &card->profile,
 			sizeof(struct capi_profile));
 	return CAPI_NOERROR;
 }
 
 static struct capi_driver *find_driver(char *name)
 {
+	struct list_head *l;
 	struct capi_driver *dp;
 	spin_lock(&drivers_lock);
-	for (dp = drivers; dp; dp = dp->next)
+	list_for_each(l, &drivers) {
+		dp = list_entry(l, struct capi_driver, driver_list);
 		if (strcmp(dp->name, name) == 0)
-			break;
+			goto found;
+	}
+	dp = NULL;
+ found:
 	spin_unlock(&drivers_lock);
 	return dp;
 }
@@ -1365,11 +1416,8 @@
 					    	sizeof(avmb1_loadandconfigdef))))
 				return retval;
 		}
-		if (!VALID_CARD(ldef.contr))
-			return -ESRCH;
-
-		card = CARD(ldef.contr);
-		if (card->cardstate == CARD_FREE)
+		card = get_capi_ctr_by_nr(ldef.contr);
+		if (!card)
 			return -ESRCH;
 		if (card->driver->load_firmware == 0) {
 			printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
@@ -1419,12 +1467,10 @@
 		if ((retval = copy_from_user((void *) &rdef, data,
 					 sizeof(avmb1_resetdef))))
 			return retval;
-		if (!VALID_CARD(rdef.contr))
+		card = get_capi_ctr_by_nr(rdef.contr);
+		if (!card)
 			return -ESRCH;
-		card = CARD(rdef.contr);
 
-		if (card->cardstate == CARD_FREE)
-			return -ESRCH;
 		if (card->cardstate == CARD_DETECTED)
 			return 0;
 
@@ -1445,12 +1491,8 @@
 					 sizeof(avmb1_getdef))))
 			return retval;
 
-		if (!VALID_CARD(gdef.contr))
-			return -ESRCH;
-
-		card = CARD(gdef.contr);
-
-		if (card->cardstate == CARD_FREE)
+		card = get_capi_ctr_by_nr(gdef.contr);
+		if (!card)
 			return -ESRCH;
 
 		gdef.cardstate = card->cardstate;
@@ -1469,11 +1511,8 @@
 					 sizeof(avmb1_resetdef))))
 			return retval;
 
-		if (!VALID_CARD(rdef.contr))
-			return -ESRCH;
-		card = CARD(rdef.contr);
-
-		if (card->cardstate == CARD_FREE)
+		card = get_capi_ctr_by_nr(rdef.contr);
+		if (!card)
 			return -ESRCH;
 
 		if (card->cardstate != CARD_DETECTED)
@@ -1481,7 +1520,7 @@
 
 		card->driver->remove_ctr(card);
 
-		while (card->cardstate != CARD_FREE) {
+		while (cards[rdef.contr]) {
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ/10);	/* 0.1 sec */
@@ -1519,11 +1558,10 @@
 					 sizeof(kcapi_flagdef))))
 			return retval;
 
-		if (!VALID_CARD(fdef.contr))
-			return -ESRCH;
-		card = CARD(fdef.contr);
-		if (card->cardstate == CARD_FREE)
+		card = get_capi_ctr_by_nr(fdef.contr);
+		if (!card)
 			return -ESRCH;
+
 		card->traceflag = fdef.flag;
 		printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
 			card->cnr, card->traceflag);
@@ -1591,55 +1629,30 @@
 
 struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
 {
-	struct capi_interface_user *p;
 
-	MOD_INC_USE_COUNT;
-	spin_lock(&capi_users_lock);
-	for (p = capi_users; p; p = p->next) {
-		if (p == userp) {
-			spin_unlock(&capi_users_lock);
-			printk(KERN_ERR "kcapi: double attach from %s\n",
-			       userp->name);
-			MOD_DEC_USE_COUNT;
-			return 0;
-		}
-	}
-	userp->next = capi_users;
-	capi_users = userp;
-	spin_unlock(&capi_users_lock);
+	spin_lock(&users_lock);
+	list_add_tail(&userp->user_list, &users);
+	spin_unlock(&users_lock);
 	printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
 
 	return &avmb1_interface;
 }
 
+EXPORT_SYMBOL(attach_capi_interface);
+
 int detach_capi_interface(struct capi_interface_user *userp)
 {
-	struct capi_interface_user **pp;
-
-	spin_lock(&capi_users_lock);
-	for (pp = &capi_users; *pp; pp = &(*pp)->next) {
-		if (*pp == userp) {
-			*pp = userp->next;
-			spin_unlock(&capi_users_lock);
-			userp->next = 0;
-			printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
-			MOD_DEC_USE_COUNT;
-			return 0;
-		}
-	}
-	spin_unlock(&capi_users_lock);
-	printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
-	return -1;
+	spin_lock(&users_lock);
+	list_del(&userp->user_list);
+	printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+	return 0;
 }
 
+EXPORT_SYMBOL(detach_capi_interface);
+
 /* ------------------------------------------------------------- */
 /* -------- Init & Cleanup ------------------------------------- */
 /* ------------------------------------------------------------- */
-
-EXPORT_SYMBOL(attach_capi_interface);
-EXPORT_SYMBOL(detach_capi_interface);
-EXPORT_SYMBOL(attach_capi_driver);
-EXPORT_SYMBOL(detach_capi_driver);
 
 /*
  * init / exit functions
diff -Nru a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
--- a/drivers/isdn/hardware/avm/b1.c	Thu May  9 15:21:05 2002
+++ b/drivers/isdn/hardware/avm/b1.c	Thu May  9 15:21:05 2002
@@ -357,8 +357,6 @@
 	b1_put_word(port, rp->datablkcnt);
 	b1_put_word(port, rp->datablklen);
 	restore_flags(flags);
-
-	ctrl->appl_registered(ctrl, appl);
 }
 
 void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
@@ -548,7 +546,7 @@
 
 		if (NCCI != 0xffffffff)
 			ctrl->free_ncci(ctrl, ApplId, NCCI);
-		else ctrl->appl_released(ctrl, ApplId);
+
 		break;
 
 	case RECEIVE_START:
diff -Nru a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
--- a/drivers/isdn/hardware/avm/b1dma.c	Thu May  9 15:21:08 2002
+++ b/drivers/isdn/hardware/avm/b1dma.c	Thu May  9 15:21:08 2002
@@ -509,7 +509,7 @@
 
 		if (NCCI != 0xffffffff)
 			ctrl->free_ncci(ctrl, ApplId, NCCI);
-		else ctrl->appl_released(ctrl, ApplId);
+
 		break;
 
 	case RECEIVE_START:
@@ -774,8 +774,6 @@
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	b1dma_queue_tx(card, skb);
-
-	ctrl->appl_registered(ctrl, appl);
 }
 
 /* ------------------------------------------------------------- */
diff -Nru a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
--- a/drivers/isdn/hardware/avm/b1isa.c	Thu May  9 15:21:06 2002
+++ b/drivers/isdn/hardware/avm/b1isa.c	Thu May  9 15:21:06 2002
@@ -34,10 +34,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static void b1isa_remove_ctr(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -47,7 +43,7 @@
 	b1_reset(port);
 	b1_reset(port);
 
-	di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	b1_free_card(card);
@@ -111,7 +107,7 @@
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "b1isa: attach controller failed.\n");
 		retval = -EBUSY;
@@ -154,27 +150,27 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1isa_driver = {
-    name: "b1isa",
-    revision: "0.0",
-    load_firmware: b1_load_firmware,
-    reset_ctr: b1_reset_ctr,
-    remove_ctr: b1isa_remove_ctr,
-    register_appl: b1_register_appl,
-    release_appl: b1_release_appl,
-    send_message: b1_send_message,
-
-    procinfo: b1isa_procinfo,
-    ctr_read_proc: b1ctl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: b1isa_add_card,
+	owner: THIS_MODULE,
+	name: "b1isa",
+	revision: "0.0",
+	load_firmware: b1_load_firmware,
+	reset_ctr: b1_reset_ctr,
+	remove_ctr: b1isa_remove_ctr,
+	register_appl: b1_register_appl,
+	release_appl: b1_release_appl,
+	send_message: b1_send_message,
+	
+	procinfo: b1isa_procinfo,
+	ctr_read_proc: b1ctl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: b1isa_add_card,
 };
 
 static int __init b1isa_init(void)
 {
 	struct capi_driver *driver = &b1isa_driver;
 	char *p;
-	int retval = 0;
 
 	MOD_INC_USE_COUNT;
 
@@ -187,15 +183,9 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(driver);
-
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		retval = -EIO;
-	}
+        attach_capi_driver(driver);
 	MOD_DEC_USE_COUNT;
-	return retval;
+	return 0;
 }
 
 static void __exit b1isa_exit(void)
diff -Nru a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
--- a/drivers/isdn/hardware/avm/b1pci.c	Thu May  9 15:21:01 2002
+++ b/drivers/isdn/hardware/avm/b1pci.c	Thu May  9 15:21:01 2002
@@ -42,10 +42,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static char *b1pci_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -113,7 +109,7 @@
 		goto err_release_region;
 	}
 	
-	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
 		       driver->name);
@@ -153,7 +149,7 @@
 	b1_reset(port);
 	b1_reset(port);
 
-	di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
@@ -165,29 +161,26 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1pci_driver = {
-    name: "b1pci",
-    revision: "0.0",
-    load_firmware: b1_load_firmware,
-    reset_ctr: b1_reset_ctr,
-    remove_ctr: b1pci_remove_ctr,
-    register_appl: b1_register_appl,
-    release_appl: b1_release_appl,
-    send_message: b1_send_message,
-
-    procinfo: b1pci_procinfo,
-    ctr_read_proc: b1ctl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: 0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "b1pci",
+	revision: "0.0",
+	load_firmware: b1_load_firmware,
+	reset_ctr: b1_reset_ctr,
+	remove_ctr: b1pci_remove_ctr,
+	register_appl: b1_register_appl,
+	release_appl: b1_release_appl,
+	send_message: b1_send_message,
+	
+	procinfo: b1pci_procinfo,
+	ctr_read_proc: b1ctl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: 0, /* no add_card function */
 };
 
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *div4;
-
-/* ------------------------------------------------------------- */
-
 static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,7 +267,7 @@
 		goto err_unmap;
 	}
 
-	cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
 		retval = -EBUSY;
@@ -312,7 +305,7 @@
 
  	b1dma_reset(card);
 
-	div4->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
@@ -327,20 +320,21 @@
 
 
 static struct capi_driver b1pciv4_driver = {
-    name: "b1pciv4",
-    revision: "0.0",
-    load_firmware: b1dma_load_firmware,
-    reset_ctr: b1dma_reset_ctr,
-    remove_ctr: b1pciv4_remove_ctr,
-    register_appl: b1dma_register_appl,
-    release_appl: b1dma_release_appl,
-    send_message: b1dma_send_message,
-
-    procinfo: b1pciv4_procinfo,
-    ctr_read_proc: b1dmactl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: 0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "b1pciv4",
+	revision: "0.0",
+	load_firmware: b1dma_load_firmware,
+	reset_ctr: b1dma_reset_ctr,
+	remove_ctr: b1pciv4_remove_ctr,
+	register_appl: b1dma_register_appl,
+	release_appl: b1dma_release_appl,
+	send_message: b1dma_send_message,
+	
+	procinfo: b1pciv4_procinfo,
+	ctr_read_proc: b1dmactl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: 0, /* no add_card function */
 };
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
@@ -432,25 +426,12 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(driver);
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		MOD_DEC_USE_COUNT;
-		return -ENODEV;
-	}
+        attach_capi_driver(driver);
 
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
 	printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision);
 
-        div4 = attach_capi_driver(driverv4);
-	if (!div4) {
-    		detach_capi_driver(driver);
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driverv4->name);
-		MOD_DEC_USE_COUNT;
-		return -ENODEV;
-	}
+        attach_capi_driver(driverv4);
 #endif
 
 	ncards = pci_register_driver(&b1pci_pci_driver);
diff -Nru a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
--- a/drivers/isdn/hardware/avm/b1pcmcia.c	Thu May  9 15:21:00 2002
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c	Thu May  9 15:21:00 2002
@@ -35,10 +35,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -48,7 +44,7 @@
 	b1_reset(port);
 	b1_reset(port);
 
-	di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	b1_free_card(card);
 
@@ -103,7 +99,7 @@
 	b1_reset(card->port);
 	b1_getrevision(card);
 
-	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
 				driver->name);
@@ -152,20 +148,21 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1pcmcia_driver = {
-    name: "b1pcmcia",
-    revision: "0.0",
-    load_firmware: b1_load_firmware,
-    reset_ctr: b1_reset_ctr,
-    remove_ctr: b1pcmcia_remove_ctr,
-    register_appl: b1_register_appl,
-    release_appl: b1_release_appl,
-    send_message: b1_send_message,
-
-    procinfo: b1pcmcia_procinfo,
-    ctr_read_proc: b1ctl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
+	owner: THIS_MODULE,
+	name: "b1pcmcia",
+	revision: "0.0",
+	load_firmware: b1_load_firmware,
+	reset_ctr: b1_reset_ctr,
+	remove_ctr: b1pcmcia_remove_ctr,
+	register_appl: b1_register_appl,
+	release_appl: b1_release_appl,
+	send_message: b1_send_message,
+	
+	procinfo: b1pcmcia_procinfo,
+	ctr_read_proc: b1ctl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    add_card: 0,
+	add_card: 0,
 };
 
 /* ------------------------------------------------------------- */
@@ -187,10 +184,12 @@
 
 int b1pcmcia_delcard(unsigned int port, unsigned irq)
 {
+	struct list_head *l;
 	struct capi_ctr *ctrl;
 	avmcard *card;
-
-	for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
+	
+	list_for_each(l, &b1pcmcia_driver.contr_head) {
+		ctrl = list_entry(l, struct capi_ctr, driver_list);
 		card = ((avmctrl_info *)(ctrl->driverdata))->card;
 		if (card->port == port && card->irq == irq) {
 			b1pcmcia_remove_ctr(ctrl);
@@ -224,13 +223,8 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(driver);
+        attach_capi_driver(driver);
 
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		retval = -EIO;
-	}
 	MOD_DEC_USE_COUNT;
 	return retval;
 }
diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c	Thu May  9 15:21:01 2002
+++ b/drivers/isdn/hardware/avm/c4.c	Thu May  9 15:21:01 2002
@@ -52,10 +52,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static void c4_dispatch_tx(avmcard *card);
 
 /* ------------------------------------------------------------- */
@@ -587,12 +583,6 @@
 			ctrl = card->ctrlinfo[cidx].capi_ctrl;
 			if (ctrl)
 				ctrl->free_ncci(ctrl, ApplId, NCCI);
-		} else {
-			for (cidx=0; cidx < 4; cidx++) {
-				ctrl = card->ctrlinfo[cidx].capi_ctrl;
-				if (ctrl)
-					ctrl->appl_released(ctrl, ApplId);
-			}
 		}
 		break;
 
@@ -918,7 +908,7 @@
         for (i=0; i < 4; i++) {
 		cinfo = &card->ctrlinfo[i];
 		if (cinfo->capi_ctrl) {
-			di->detach_ctr(cinfo->capi_ctrl);
+			detach_capi_ctr(cinfo->capi_ctrl);
 			cinfo->capi_ctrl = NULL;
 		}
 	}
@@ -973,8 +963,6 @@
 		skb_queue_tail(&card->dma->send_queue, skb);
 		c4_dispatch_tx(card);
 	}
-
-	ctrl->appl_registered(ctrl, appl);
 }
 
 /* ------------------------------------------------------------- */
@@ -1170,13 +1158,13 @@
 
 	for (i=0; i < nr_controllers ; i++) {
 		cinfo = &card->ctrlinfo[i];
-		cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+		cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 		if (!cinfo->capi_ctrl) {
 			printk(KERN_ERR "%s: attach controller failed (%d).\n",
 					driver->name, i);
 			for (i--; i >= 0; i--) {
 				cinfo = &card->ctrlinfo[i];
-				di->detach_ctr(cinfo->capi_ctrl);
+				detach_capi_ctr(cinfo->capi_ctrl);
 			}
 			goto err_free_irq;
 		}
@@ -1208,37 +1196,39 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver c2_driver = {
-    name: "c2",
-    revision: "0.0",
-    load_firmware: c4_load_firmware,
-    reset_ctr: c4_reset_ctr,
-    remove_ctr: c4_remove_ctr,
-    register_appl: c4_register_appl,
-    release_appl: c4_release_appl,
-    send_message: c4_send_message,
-
-    procinfo: c4_procinfo,
-    ctr_read_proc: c4_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: 0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "c2",
+	revision: "0.0",
+	load_firmware: c4_load_firmware,
+	reset_ctr: c4_reset_ctr,
+	remove_ctr: c4_remove_ctr,
+	register_appl: c4_register_appl,
+	release_appl: c4_release_appl,
+	send_message: c4_send_message,
+
+	procinfo: c4_procinfo,
+	ctr_read_proc: c4_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: 0, /* no add_card function */
 };
 
 static struct capi_driver c4_driver = {
-    name: "c4",
-    revision: "0.0",
-    load_firmware: c4_load_firmware,
-    reset_ctr: c4_reset_ctr,
-    remove_ctr: c4_remove_ctr,
-    register_appl: c4_register_appl,
-    release_appl: c4_release_appl,
-    send_message: c4_send_message,
-
-    procinfo: c4_procinfo,
-    ctr_read_proc: c4_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: 0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "c4",
+	revision: "0.0",
+	load_firmware: c4_load_firmware,
+	reset_ctr: c4_reset_ctr,
+	remove_ctr: c4_remove_ctr,
+	register_appl: c4_register_appl,
+	release_appl: c4_release_appl,
+	send_message: c4_send_message,
+	
+	procinfo: c4_procinfo,
+	ctr_read_proc: c4_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: 0, /* no add_card function */
 };
 
 static int c4_attach_driver (struct capi_driver * driver)
@@ -1253,13 +1243,7 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(driver);
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		MOD_DEC_USE_COUNT;
-		return -ENODEV;
-	}
+        attach_capi_driver(driver);
 	return 0;
 }
 
diff -Nru a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
--- a/drivers/isdn/hardware/avm/t1isa.c	Thu May  9 15:21:08 2002
+++ b/drivers/isdn/hardware/avm/t1isa.c	Thu May  9 15:21:08 2002
@@ -35,10 +35,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static int hema_irq_table[16] =
 {0,
  0,
@@ -199,7 +195,7 @@
 
 			if (NCCI != 0xffffffff)
 				ctrl->free_ncci(ctrl, ApplId, NCCI);
-			else ctrl->appl_released(ctrl, ApplId);
+
 			break;
 
 		case RECEIVE_START:
@@ -331,7 +327,7 @@
 	b1_reset(port);
 	t1_reset(port);
 
-	di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	b1_free_card(card);
@@ -344,6 +340,7 @@
 static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
 	struct capi_ctr *ctrl;
+	struct list_head *l;
 	avmctrl_info *cinfo;
 	avmcard *card;
 	int retval;
@@ -376,8 +373,11 @@
 		retval = -EINVAL;
 		goto err_free;
 	}
-	for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
-	        avmcard *cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
+	list_for_each(l, &driver->contr_head) {
+	        avmcard *cardp;
+
+		ctrl = list_entry(l, struct capi_ctr, driver_list);
+		cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
 		if (cardp->cardnr == card->cardnr) {
 			printk(KERN_WARNING "%s: card with number %d already installed at 0x%x.\n",
 					driver->name, card->cardnr, cardp->port);
@@ -408,7 +408,7 @@
 	t1_disable_irq(card->port);
 	b1_reset(card->port);
 
-	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
 				driver->name);
@@ -479,20 +479,21 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver t1isa_driver = {
-    name: "t1isa",
-    revision: "0.0",
-    load_firmware: t1isa_load_firmware,
-    reset_ctr: t1isa_reset_ctr,
-    remove_ctr: t1isa_remove_ctr,
-    register_appl: b1_register_appl,
-    release_appl: b1_release_appl,
-    send_message: t1isa_send_message,
-
-    procinfo: t1isa_procinfo,
-    ctr_read_proc: b1ctl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: t1isa_add_card,
+	owner: THIS_MODULE,
+	name: "t1isa",
+	revision: "0.0",
+	load_firmware: t1isa_load_firmware,
+	reset_ctr: t1isa_reset_ctr,
+	remove_ctr: t1isa_remove_ctr,
+	register_appl: b1_register_appl,
+	release_appl: b1_release_appl,
+	send_message: t1isa_send_message,
+	
+	procinfo: t1isa_procinfo,
+	ctr_read_proc: b1ctl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: t1isa_add_card,
 };
 
 static int __init t1isa_init(void)
@@ -512,13 +513,7 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(driver);
-
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		retval = -EIO;
-	}
+        attach_capi_driver(driver);
 
 	MOD_DEC_USE_COUNT;
 	return retval;
diff -Nru a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
--- a/drivers/isdn/hardware/avm/t1pci.c	Thu May  9 15:21:02 2002
+++ b/drivers/isdn/hardware/avm/t1pci.c	Thu May  9 15:21:02 2002
@@ -45,10 +45,6 @@
 
 /* ------------------------------------------------------------- */
 
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
 static int t1pci_add_card(struct capi_driver *driver,
                           struct capicardparams *p,
 	                  struct pci_dev *dev)
@@ -119,7 +115,7 @@
 		goto err_unmap;
 	}
 
-	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	cinfo->capi_ctrl = attach_capi_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
 		retval = -EBUSY;
@@ -157,7 +153,7 @@
 
  	b1dma_reset(card);
 
-	di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	free_irq(card->irq, card);
 	iounmap(card->mbase);
 	release_region(card->port, AVMB1_PORTLEN);
@@ -189,20 +185,21 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver t1pci_driver = {
-    name: "t1pci",
-    revision: "0.0",
-    load_firmware: b1dma_load_firmware,
-    reset_ctr: b1dma_reset_ctr,
-    remove_ctr: t1pci_remove_ctr,
-    register_appl: b1dma_register_appl,
-    release_appl: b1dma_release_appl,
-    send_message: b1dma_send_message,
-
-    procinfo: t1pci_procinfo,
-    ctr_read_proc: b1dmactl_read_proc,
-    driver_read_proc: 0,	/* use standard driver_read_proc */
-
-    add_card: 0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "t1pci",
+	revision: "0.0",
+	load_firmware: b1dma_load_firmware,
+	reset_ctr: b1dma_reset_ctr,
+	remove_ctr: t1pci_remove_ctr,
+	register_appl: b1dma_register_appl,
+	release_appl: b1dma_release_appl,
+	send_message: b1dma_send_message,
+	
+	procinfo: t1pci_procinfo,
+	ctr_read_proc: b1dmactl_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+	
+	add_card: 0, /* no add_card function */
 };
 
 /* ------------------------------------------------------------- */
@@ -261,13 +258,7 @@
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
 
-        di = attach_capi_driver(&t1pci_driver);
-	if (!di) {
-		printk(KERN_ERR "%s: failed to attach capi_driver\n",
-				driver->name);
-		MOD_DEC_USE_COUNT;
-		return -EIO;
-	}
+        attach_capi_driver(&t1pci_driver);
 
 	ncards = pci_register_driver(&t1pci_pci_driver);
 	if (ncards) {
diff -Nru a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
--- a/drivers/isdn/hysdn/hycapi.c	Thu May  9 15:21:02 2002
+++ b/drivers/isdn/hysdn/hycapi.c	Thu May  9 15:21:02 2002
@@ -98,7 +98,7 @@
 			hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL;
 		}
 	}
-	hy_di->detach_ctr(ctrl);
+	detach_capi_ctr(ctrl);
 	ctrl->driverdata = 0;
 	kfree(card->hyctrlinfo);
 
@@ -252,7 +252,6 @@
 	       rp, sizeof(capi_register_params));
 	
 /*        MOD_INC_USE_COUNT; */
-	ctrl->appl_registered(ctrl, appl);
 }
 
 /*********************************************************************
@@ -313,7 +312,6 @@
 	{
 		hycapi_release_internal(ctrl, appl);
 	}
-	ctrl->appl_released(ctrl, appl);
 /*        MOD_DEC_USE_COUNT;  */
 }
 
@@ -666,18 +664,21 @@
 
 
 static struct capi_driver hycapi_driver = {
-	"hysdn",
-	"0.0",
-	hycapi_load_firmware, 
-	hycapi_reset_ctr,
-	hycapi_remove_ctr,
-	hycapi_register_appl,
-	hycapi_release_appl,
-	hycapi_send_message,
-	hycapi_procinfo,
-	hycapi_read_proc,
-	0,	/* use standard driver_read_proc */
-	0, /* no add_card function */
+	owner: THIS_MODULE,
+	name: "hysdn",
+	revision: "0.0",
+	load_firmware: hycapi_load_firmware, 
+	reset_ctr: hycapi_reset_ctr,
+	remove_ctr: hycapi_remove_ctr,
+	register_appl: hycapi_register_appl,
+	release_appl: hycapi_release_appl,
+	send_message: hycapi_send_message,
+
+	procinfo: hycapi_procinfo,
+	ctr_read_proc: hycapi_read_proc,
+	driver_read_proc: 0,	/* use standard driver_read_proc */
+
+	add_card: 0, /* no add_card function */
 };
 
 
@@ -698,11 +699,8 @@
 	}
 	driver = &hycapi_driver;
 	printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n");
-	hy_di = attach_capi_driver(driver);
-	if (!hy_di) {
-		printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n");
-		return(-1);
-	}
+	attach_capi_driver(driver);
+
 	for(i=0;i<CAPI_MAXAPPL;i++) {
 		memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
 	}
@@ -798,8 +796,8 @@
 			default: strcpy(cinfo->cardname,"HYSDN ???"); break;
 		}
 
-		cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, 
-						     cinfo->cardname, cinfo);
+		cinfo->capi_ctrl = attach_capi_ctr(&hycapi_driver, 
+						   cinfo->cardname, cinfo);
 		ctrl = cinfo->capi_ctrl;
 		if (!ctrl) {
 			printk(KERN_ERR "%s: attach controller failed.\n",
diff -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c
--- a/drivers/media/video/meye.c	Thu May  9 15:21:08 2002
+++ b/drivers/media/video/meye.c	Thu May  9 15:21:08 2002
@@ -1242,7 +1242,6 @@
 	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1);
 
 	meye.mchip_dev = pcidev;
-	meye.mchip_irq = pcidev->irq;
 	memcpy(&meye.video_dev, &meye_template, sizeof(meye_template));
 
 	if (mchip_dma_alloc()) {
@@ -1256,6 +1255,7 @@
 		goto out3;
 	}
 
+	meye.mchip_irq = pcidev->irq;
 	mchip_adr = pci_resource_start(meye.mchip_dev,0);
 	if (!mchip_adr) {
 		printk(KERN_ERR "meye: mchip has no device base address\n");
@@ -1419,6 +1419,27 @@
 static void __exit meye_cleanup_module(void) {
 	pci_unregister_driver(&meye_driver);
 }
+
+#ifndef MODULE
+static int __init meye_setup(char *str) {
+	int ints[4];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+	if (ints[0] <= 0) 
+		goto out;
+	gbuffers = ints[1];
+	if (ints[0] == 1)
+		goto out;
+	gbufsize = ints[2];
+	if (ints[0] == 2)
+		goto out;
+	video_nr = ints[3];
+out:
+	return 1;
+}
+
+__setup("meye=", meye_setup);
+#endif
 
 MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
 MODULE_DESCRIPTION("video4linux driver for the MotionEye camera");
diff -Nru a/drivers/media/video/meye.h b/drivers/media/video/meye.h
--- a/drivers/media/video/meye.h	Thu May  9 15:21:01 2002
+++ b/drivers/media/video/meye.h	Thu May  9 15:21:01 2002
@@ -29,7 +29,7 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	1
-#define MEYE_DRIVER_MINORVERSION	3
+#define MEYE_DRIVER_MINORVERSION	4
 
 /****************************************************************************/
 /* Motion JPEG chip registers                                               */
diff -Nru a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
--- a/drivers/media/video/zr36120.c	Thu May  9 15:21:07 2002
+++ b/drivers/media/video/zr36120.c	Thu May  9 15:21:07 2002
@@ -1291,11 +1291,7 @@
 	 case VIDIOCSFBUF:
 	 {
 		struct video_buffer v;
-#if LINUX_VERSION_CODE >= 0x020100
-			if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN))
-#else
-			if(!suser())
-#endif
+		if(!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		if (copy_from_user(&v, arg,sizeof(v)))
 			return -EFAULT;
diff -Nru a/drivers/message/Makefile b/drivers/message/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/message/Makefile	Thu May  9 15:21:10 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for MPT based block devices
+#
+
+O_TARGET := message.o
+
+mod-subdirs := i2o fusion 
+
+subdir-$(CONFIG_I2O)		+= i2o
+ifeq ($(CONFIG_I2O),y)
+  obj-y += i2o/i2o.o
+endif
+
+subdir-$(CONFIG_FUSION)		+= fusion
+ifeq ($(CONFIG_FUSION),y)
+  obj-y += fusion/fusion.o
+endif
+
+include $(TOPDIR)/Rules.make
+
diff -Nru a/drivers/message/fusion/Config.in b/drivers/message/fusion/Config.in
--- a/drivers/message/fusion/Config.in	Thu May  9 15:21:04 2002
+++ b/drivers/message/fusion/Config.in	Thu May  9 15:21:04 2002
@@ -5,34 +5,20 @@
 
 if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
 
-  if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
-    define_bool CONFIG_FUSION_BOOT y
+  if [ "$CONFIG_FUSION" = "y" ]; then
     comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
   else
-    define_bool CONFIG_FUSION_BOOT n
     comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
   fi
 
-  if [ "$CONFIG_MODULES" = "y" ]; then
-    #  How can we force these options to module or nothing?
-    dep_tristate "  Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
-    dep_tristate "  Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
-  fi
+  # Modular only
+  dep_tristate "  Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
+  dep_tristate "  Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
 
   dep_tristate "  Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET
   if [ "$CONFIG_FUSION_LAN" != "n" ]; then
     define_bool CONFIG_NET_FC y
   fi
-
-else
-
-  define_bool CONFIG_FUSION_BOOT n
-  # These <should> be define_tristate, but we leave them define_bool
-  # for backward compatibility with pre-linux-2.2.15 kernels.
-  # (Bugzilla:fibrebugs, #384)
-  define_bool CONFIG_FUSION_ISENSE n
-  define_bool CONFIG_FUSION_CTL n
-  define_bool CONFIG_FUSION_LAN n
 
 fi
 
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Thu May  9 15:21:04 2002
+++ b/drivers/net/Makefile	Thu May  9 15:21:04 2002
@@ -8,7 +8,8 @@
 obj-n           :=
 obj-            :=
 
-mod-subdirs     := appletalk arcnet fc irda tokenring tulip pcmcia wireless wan
+mod-subdirs     := appletalk arcnet fc irda tokenring tulip pcmcia wireless \
+		   wan ../acorn/net
 
 O_TARGET := net.o
 
@@ -20,30 +21,22 @@
 			net_init.o mii.o
 rcpci-objs	:=	rcpci45.o rclanmtl.o
 
-ifeq ($(CONFIG_E100),y)
-  obj-y += e100/e100.o
-endif
-ifeq ($(CONFIG_E1000),y)
-  obj-y += e1000/e1000.o
-endif
-
 ifeq ($(CONFIG_ISDN_PPP),y)
   obj-$(CONFIG_ISDN) += slhc.o
 endif
 
 subdir-$(CONFIG_NET_PCMCIA) += pcmcia
 subdir-$(CONFIG_NET_WIRELESS) += wireless
-subdir-$(CONFIG_NET_TULIP) += tulip
+
 subdir-$(CONFIG_E100) += e100
+ifeq ($(CONFIG_E100),y)
+  obj-y += e100/e100.o
+endif
+
 subdir-$(CONFIG_E1000) += e1000
-subdir-$(CONFIG_IRDA) += irda
-subdir-$(CONFIG_TR) += tokenring
-subdir-$(CONFIG_WAN) += wan
-subdir-$(CONFIG_NET_FC) += fc
-subdir-$(CONFIG_ARCNET) += arcnet
-subdir-$(CONFIG_DEV_APPLETALK) += appletalk
-subdir-$(CONFIG_SK98LIN) += sk98lin
-subdir-$(CONFIG_SKFP) += skfp
+ifeq ($(CONFIG_E1000),y)
+  obj-y += e1000/e1000.o
+endif
 
 #
 # link order important here
@@ -83,10 +76,12 @@
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_TC35815) += tc35815.o
 
+subdir-$(CONFIG_SK98LIN) += sk98lin
 ifeq ($(CONFIG_SK98LIN),y)
 obj-y += sk98lin/sk98lin.o
 endif
 
+subdir-$(CONFIG_SKFP) += skfp
 ifeq ($(CONFIG_SKFP),y)
   obj-y += skfp/skfp.o
 endif
@@ -215,10 +210,59 @@
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_DL2K) += dl2k.o
 
+subdir-$(CONFIG_ARCH_ACORN) += ../acorn/net
 ifeq ($(CONFIG_ARCH_ACORN),y)
-mod-subdirs	+= ../acorn/net
-subdir-y	+= ../acorn/net
-obj-y		+= ../acorn/net/acorn-net.o
+  obj-y		+= ../acorn/net/acorn-net.o
+endif
+
+subdir-$(CONFIG_NET_FC) += fc
+ifeq ($(CONFIG_NET_FC),y)
+  obj-y		+= fc/fc.o
+endif
+
+subdir-$(CONFIG_DEV_APPLETALK) += appletalk
+ifeq ($(CONFIG_DEV_APPLETALK),y)
+  obj-y		+= appletalk/appletalk.o
+endif
+
+subdir-$(CONFIG_TR) += tokenring
+ifeq ($(CONFIG_TR),y)
+  obj-y		+= tokenring/tr.o
+endif
+
+subdir-$(CONFIG_WAN) += wan
+ifeq ($(CONFIG_WAN),y)
+  obj-y		+= wan/wan.o
+endif
+
+subdir-$(CONFIG_ARCNET) += arcnet
+ifeq ($(CONFIG_ARCNET),y)
+  obj-y		+= arcnet/arcnetdrv.o
+endif
+
+subdir-$(CONFIG_NET_PCMCIA) += pcmcia
+ifeq ($(CONFIG_NET_PCMCIA),y)
+  obj-y		+= pcmcia/pcmcia_net.o
+endif
+
+subdir-$(CONFIG_NET_WIRELESS) += wireless
+ifeq ($(CONFIG_NET_WIRELESS),y)
+  obj-y		+= wireless/wireless_net.o
+endif
+
+subdir-$(CONFIG_NET_TULIP) += tulip
+ifeq ($(CONFIG_NET_TULIP),y)
+  obj-y		+= tulip/tulip_net.o
+endif
+
+subdir-$(CONFIG_HAMRADIO) += hamradio
+ifeq ($(CONFIG_HAMRADIO),y)
+  obj-y		+= hamradio/hamradio.o
+endif
+
+subdir-$(CONFIG_IRDA) += irda
+ifeq ($(CONFIG_IRDA),y)
+  obj-y		+= irda/irda.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c
--- a/drivers/net/acenic.c	Thu May  9 15:21:07 2002
+++ b/drivers/net/acenic.c	Thu May  9 15:21:07 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 -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Thu May  9 15:21:08 2002
+++ b/drivers/net/tg3.c	Thu May  9 15:21:08 2002
@@ -1,4 +1,4 @@
-/* $Id: tg3.c,v 1.43.2.79 2002/03/12 07:11:17 davem Exp $
+/* $Id: tg3.c,v 1.43.2.80 2002/03/14 00:10:04 davem Exp $
  * tg3.c: Broadcom Tigon3 ethernet driver.
  *
  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
@@ -956,6 +956,17 @@
 		     tp->link_config.active_speed == SPEED_10))
 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
 	}
+
+	/* ??? Without this setting Netgear GA302T PHY does not
+	 * ??? send/receive packets...
+	 */
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
+	    tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
+		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
+		tw32(MAC_MI_MODE, tp->mi_mode);
+		udelay(40);
+	}
+
 	tw32(MAC_MODE, tp->mac_mode);
 
 	if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
@@ -1200,7 +1211,7 @@
 		if (ap->rxconfig & ANEG_CFG_FD)
 			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
 		if (ap->rxconfig & ANEG_CFG_HD)
-			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
+			ap->flags |= MR_LP_ADV_HALF_DUPLEX;
 		if (ap->rxconfig & ANEG_CFG_PS1)
 			ap->flags |= MR_LP_ADV_SYM_PAUSE;
 		if (ap->rxconfig & ANEG_CFG_PS2)
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Thu May  9 15:21:03 2002
+++ b/drivers/net/tg3.h	Thu May  9 15:21:03 2002
@@ -99,6 +99,8 @@
 #define  CHIPREV_ID_5700_A1		 0x7001
 #define  CHIPREV_ID_5700_B0		 0x7100
 #define  CHIPREV_ID_5700_B1		 0x7101
+#define  CHIPREV_ID_5700_B3		 0x7102
+#define  CHIPREV_ID_5700_ALTIMA		 0x7104
 #define  CHIPREV_ID_5700_C0		 0x7200
 #define  CHIPREV_ID_5701_A0		 0x0000
 #define  CHIPREV_ID_5701_B0		 0x0100
@@ -1843,6 +1845,7 @@
 #define PHY_REV_BCM5401_B0		0x1
 #define PHY_REV_BCM5401_B2		0x3
 #define PHY_REV_BCM5401_C0		0x6
+#define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
 
 	enum phy_led_mode		led_mode;
 
diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile	Thu May  9 15:21:09 2002
+++ b/drivers/pci/Makefile	Thu May  9 15:21:09 2002
@@ -11,9 +11,11 @@
 
 O_TARGET := driver.o
 
-export-objs := pci.o
+obj-y		+= access.o probe.o pci.o pool.o quirks.o \
+			compat.o names.o pci-driver.o search.o
+obj-$(CONFIG_PM)  += power.o
+obj-$(CONFIG_HOTPLUG)  += hotplug.o
 
-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o pci-driver.o
 obj-$(CONFIG_PROC_FS) += proc.o
 
 ifndef CONFIG_SPARC64
@@ -27,13 +29,15 @@
 obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
 obj-$(CONFIG_PARISC) += setup-bus.o
 obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
-obj-$(CONFIG_ALL_PPC) += setup-bus.o
+obj-$(CONFIG_PPC32) += setup-irq.o
 obj-$(CONFIG_DDB5476) += setup-bus.o
 obj-$(CONFIG_SGI_IP27) += setup-irq.o
 
 ifndef CONFIG_X86
 obj-y += syscall.o
 endif
+
+export-objs := $(obj-y)
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/pci/access.c b/drivers/pci/access.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/access.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,46 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+
+static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *  Wrappers for all PCI configuration access functions.  They just check
+ *  alignment, do locking and call the low-level functions pointed to
+ *  by pci_dev->ops.
+ */
+
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_OP(rw,size,type) \
+int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
+{									\
+	int res;							\
+	unsigned long flags;						\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	spin_lock_irqsave(&pci_lock, flags);				\
+	res = dev->bus->ops->rw##_##size(dev, pos, value);		\
+	spin_unlock_irqrestore(&pci_lock, flags);			\
+	return res;							\
+}
+
+PCI_OP(read, byte, u8 *)
+PCI_OP(read, word, u16 *)
+PCI_OP(read, dword, u32 *)
+PCI_OP(write, byte, u8)
+PCI_OP(write, word, u16)
+PCI_OP(write, dword, u32)
+
+EXPORT_SYMBOL(pci_read_config_byte);
+EXPORT_SYMBOL(pci_read_config_word);
+EXPORT_SYMBOL(pci_read_config_dword);
+EXPORT_SYMBOL(pci_write_config_byte);
+EXPORT_SYMBOL(pci_write_config_word);
+EXPORT_SYMBOL(pci_write_config_dword);
diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,132 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/kmod.h>		/* for hotplug_path */
+
+extern struct list_head pci_drivers;
+extern int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev);
+
+#ifndef FALSE
+#define FALSE	(0)
+#define TRUE	(!FALSE)
+#endif
+
+static void
+run_sbin_hotplug(struct pci_dev *pdev, int insert)
+{
+	int i;
+	char *argv[3], *envp[8];
+	char id[20], sub_id[24], bus_id[24], class_id[20];
+
+	if (!hotplug_path[0])
+		return;
+
+	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
+	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "pci";
+	argv[i] = 0;
+
+	i = 0;
+	/* minimal command environment */
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	
+	/* other stuff we want to pass to /sbin/hotplug */
+	envp[i++] = class_id;
+	envp[i++] = id;
+	envp[i++] = sub_id;
+	envp[i++] = bus_id;
+	if (insert)
+		envp[i++] = "ACTION=add";
+	else
+		envp[i++] = "ACTION=remove";
+	envp[i] = 0;
+
+	call_usermodehelper (argv [0], argv, envp);
+}
+
+/**
+ * pci_announce_device_to_drivers - tell the drivers a new device has appeared
+ * @dev: the device that has shown up
+ *
+ * Notifys the drivers that a new device has appeared, and also notifys
+ * userspace through /sbin/hotplug.
+ */
+void
+pci_announce_device_to_drivers(struct pci_dev *dev)
+{
+	struct list_head *ln;
+
+	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+		if (drv->remove && pci_announce_device(drv, dev))
+			break;
+	}
+
+	/* notify userspace of new hotplug device */
+	run_sbin_hotplug(dev, TRUE);
+}
+
+/**
+ * pci_insert_device - insert a hotplug device
+ * @dev: the device to insert
+ * @bus: where to insert it
+ *
+ * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ */
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	pci_announce_device_to_drivers(dev);
+}
+
+static void
+pci_free_resources(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = dev->resource + i;
+		if (res->parent)
+			release_resource(res);
+	}
+}
+
+/**
+ * pci_remove_device - remove a hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and 
+ * notify userspace (/sbin/hotplug).
+ */
+void
+pci_remove_device(struct pci_dev *dev)
+{
+	if (dev->driver) {
+		if (dev->driver->remove)
+			dev->driver->remove(dev);
+		dev->driver = NULL;
+	}
+	list_del(&dev->bus_list);
+	list_del(&dev->global_list);
+	pci_free_resources(dev);
+#ifdef CONFIG_PROC_FS
+	pci_proc_detach_device(dev);
+#endif
+
+	/* notify userspace of hotplug device removal */
+	run_sbin_hotplug(dev, FALSE);
+}
+
+EXPORT_SYMBOL(pci_insert_device);
+EXPORT_SYMBOL(pci_remove_device);
+EXPORT_SYMBOL(pci_announce_device_to_drivers);
diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
--- a/drivers/pci/pci-driver.c	Thu May  9 15:21:08 2002
+++ b/drivers/pci/pci-driver.c	Thu May  9 15:21:08 2002
@@ -1,9 +1,138 @@
 /*
- * drivers/pci/pci-driver.c - default PCI driver.
+ * drivers/pci/pci-driver.c
  *
  */
 
 #include <linux/pci.h>
+#include <linux/module.h>
+
+/*
+ *  Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+LIST_HEAD(pci_drivers);
+
+/**
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * 
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
+const struct pci_device_id *
+pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
+{
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+		    (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+		    (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
+		    (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
+		    !((ids->class ^ dev->class) & ids->class_mask))
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+int
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+	const struct pci_device_id *id;
+	int ret = 0;
+
+	if (drv->id_table) {
+		id = pci_match_device(drv->id_table, dev);
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
+	} else
+		id = NULL;
+
+	dev_probe_lock();
+	if (drv->probe(dev, id) >= 0) {
+		dev->driver = drv;
+		ret = 1;
+	}
+	dev_probe_unlock();
+out:
+	return ret;
+}
+
+/**
+ * pci_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int
+pci_register_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0;
+
+	list_add_tail(&drv->node, &pci_drivers);
+	pci_for_each_dev(dev) {
+		if (!pci_dev_driver(dev))
+			count += pci_announce_device(drv, dev);
+	}
+	return count;
+}
+
+/**
+ * pci_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PCI drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	pci_for_each_dev(dev) {
+		if (dev->driver == drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+}
+
+static struct pci_driver pci_compat_driver = {
+	name: "compat"
+};
+
+/**
+ * pci_dev_driver - get the pci_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate pci_driver structure or %NULL if there is no 
+ * registered driver for the device.
+ */
+struct pci_driver *
+pci_dev_driver(const struct pci_dev *dev)
+{
+	if (dev->driver)
+		return dev->driver;
+	else {
+		int i;
+		for(i=0; i<=PCI_ROM_RESOURCE; i++)
+			if (dev->resource[i].flags & IORESOURCE_BUSY)
+				return &pci_compat_driver;
+	}
+	return NULL;
+}
 
 static int pci_device_suspend(struct device * dev, u32 state, u32 level)
 {
@@ -34,3 +163,8 @@
 	suspend:	pci_device_suspend,
 	resume:		pci_device_resume,
 };
+
+EXPORT_SYMBOL(pci_match_device);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
+EXPORT_SYMBOL(pci_dev_driver);
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Thu May  9 15:21:04 2002
+++ b/drivers/pci/pci.c	Thu May  9 15:21:04 2002
@@ -9,23 +9,11 @@
  *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/string.h>
+#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <linux/kmod.h>		/* for hotplug_path */
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/cache.h>
-
-#include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 
 #undef DEBUG
@@ -36,114 +24,6 @@
 #define DBG(x...)
 #endif
 
-LIST_HEAD(pci_root_buses);
-LIST_HEAD(pci_devices);
-
-extern struct device_driver pci_device_driver;
-
-/**
- * pci_find_slot - locate PCI device from a given PCI slot
- * @bus: number of PCI bus on which desired PCI device resides
- * @devfn: encodes number of PCI slot in which the desired PCI 
- * device resides and the logical device number within that slot 
- * in case of multi-function devices.
- *
- * Given a PCI bus and slot/function number, the desired PCI device 
- * is located in system global list of PCI devices.  If the device
- * is found, a pointer to its data structure is returned.  If no 
- * device is found, %NULL is returned.
- */
-struct pci_dev *
-pci_find_slot(unsigned int bus, unsigned int devfn)
-{
-	struct pci_dev *dev;
-
-	pci_for_each_dev(dev) {
-		if (dev->bus->number == bus && dev->devfn == devfn)
-			return dev;
-	}
-	return NULL;
-}
-
-/**
- * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices.  If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
- * device structure is returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
- */
-struct pci_dev *
-pci_find_subsys(unsigned int vendor, unsigned int device,
-		unsigned int ss_vendor, unsigned int ss_device,
-		const struct pci_dev *from)
-{
-	struct list_head *n = from ? from->global_list.next : pci_devices.next;
-
-	while (n != &pci_devices) {
-		struct pci_dev *dev = pci_dev_g(n);
-		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
-		    (device == PCI_ANY_ID || dev->device == device) &&
-		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
-		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
-			return dev;
-		n = n->next;
-	}
-	return NULL;
-}
-
-
-/**
- * pci_find_device - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices.  If a PCI device is
- * found with a matching @vendor and @device, a pointer to its device structure is
- * returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
- */
-struct pci_dev *
-pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
-	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
-}
-
-
-/**
- * pci_find_class - begin or continue searching for a PCI device by class
- * @class: search for a PCI device with this class designation
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices.  If a PCI device is
- * found with a matching @class, a pointer to its device structure is
- * returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device
- * on the global list.
- */
-struct pci_dev *
-pci_find_class(unsigned int class, const struct pci_dev *from)
-{
-	struct list_head *n = from ? from->global_list.next : pci_devices.next;
-
-	while (n != &pci_devices) {
-		struct pci_dev *dev = pci_dev_g(n);
-		if (dev->class == class)
-			return dev;
-		n = n->next;
-	}
-	return NULL;
-}
-
 /**
  * pci_find_capability - query for devices' capabilities 
  * @dev: PCI device to query
@@ -536,298 +416,6 @@
 	return -EBUSY;
 }
 
-
-/*
- *  Registration of PCI drivers and handling of hot-pluggable devices.
- */
-
-static LIST_HEAD(pci_drivers);
-
-/**
- * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
- * @ids: array of PCI device id structures to search in
- * @dev: the PCI device structure to match against
- * 
- * Used by a driver to check whether a PCI device present in the
- * system is in its list of supported devices.Returns the matching
- * pci_device_id structure or %NULL if there is no match.
- */
-const struct pci_device_id *
-pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
-{
-	while (ids->vendor || ids->subvendor || ids->class_mask) {
-		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
-		    (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
-		    (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
-		    (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
-		    !((ids->class ^ dev->class) & ids->class_mask))
-			return ids;
-		ids++;
-	}
-	return NULL;
-}
-
-static int
-pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
-{
-	const struct pci_device_id *id;
-	int ret = 0;
-
-	if (drv->id_table) {
-		id = pci_match_device(drv->id_table, dev);
-		if (!id) {
-			ret = 0;
-			goto out;
-		}
-	} else
-		id = NULL;
-
-	dev_probe_lock();
-	if (drv->probe(dev, id) >= 0) {
-		dev->driver = drv;
-		ret = 1;
-	}
-	dev_probe_unlock();
-out:
-	return ret;
-}
-
-/**
- * pci_register_driver - register a new pci driver
- * @drv: the driver structure to register
- * 
- * Adds the driver structure to the list of registered drivers
- * Returns the number of pci devices which were claimed by the driver
- * during registration.  The driver remains registered even if the
- * return value is zero.
- */
-int
-pci_register_driver(struct pci_driver *drv)
-{
-	struct pci_dev *dev;
-	int count = 0;
-
-	list_add_tail(&drv->node, &pci_drivers);
-	pci_for_each_dev(dev) {
-		if (!pci_dev_driver(dev))
-			count += pci_announce_device(drv, dev);
-	}
-	return count;
-}
-
-/**
- * pci_unregister_driver - unregister a pci driver
- * @drv: the driver structure to unregister
- * 
- * Deletes the driver structure from the list of registered PCI drivers,
- * gives it a chance to clean up by calling its remove() function for
- * each device it was responsible for, and marks those devices as
- * driverless.
- */
-
-void
-pci_unregister_driver(struct pci_driver *drv)
-{
-	struct pci_dev *dev;
-
-	list_del(&drv->node);
-	pci_for_each_dev(dev) {
-		if (dev->driver == drv) {
-			if (drv->remove)
-				drv->remove(dev);
-			dev->driver = NULL;
-		}
-	}
-}
-
-#ifdef CONFIG_HOTPLUG
-
-#ifndef FALSE
-#define FALSE	(0)
-#define TRUE	(!FALSE)
-#endif
-
-static void
-run_sbin_hotplug(struct pci_dev *pdev, int insert)
-{
-	int i;
-	char *argv[3], *envp[8];
-	char id[20], sub_id[24], bus_id[24], class_id[20];
-
-	if (!hotplug_path[0])
-		return;
-
-	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
-	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
-	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
-	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
-
-	i = 0;
-	argv[i++] = hotplug_path;
-	argv[i++] = "pci";
-	argv[i] = 0;
-
-	i = 0;
-	/* minimal command environment */
-	envp[i++] = "HOME=/";
-	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-	
-	/* other stuff we want to pass to /sbin/hotplug */
-	envp[i++] = class_id;
-	envp[i++] = id;
-	envp[i++] = sub_id;
-	envp[i++] = bus_id;
-	if (insert)
-		envp[i++] = "ACTION=add";
-	else
-		envp[i++] = "ACTION=remove";
-	envp[i] = 0;
-
-	call_usermodehelper (argv [0], argv, envp);
-}
-
-/**
- * pci_announce_device_to_drivers - tell the drivers a new device has appeared
- * @dev: the device that has shown up
- *
- * Notifys the drivers that a new device has appeared, and also notifys
- * userspace through /sbin/hotplug.
- */
-void
-pci_announce_device_to_drivers(struct pci_dev *dev)
-{
-	struct list_head *ln;
-
-	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
-		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
-		if (drv->remove && pci_announce_device(drv, dev))
-			break;
-	}
-
-	/* notify userspace of new hotplug device */
-	run_sbin_hotplug(dev, TRUE);
-}
-
-/**
- * pci_insert_device - insert a hotplug device
- * @dev: the device to insert
- * @bus: where to insert it
- *
- * Add a new device to the device lists and notify userspace (/sbin/hotplug).
- */
-void
-pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
-{
-	list_add_tail(&dev->bus_list, &bus->devices);
-	list_add_tail(&dev->global_list, &pci_devices);
-#ifdef CONFIG_PROC_FS
-	pci_proc_attach_device(dev);
-#endif
-	pci_announce_device_to_drivers(dev);
-}
-
-static void
-pci_free_resources(struct pci_dev *dev)
-{
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		struct resource *res = dev->resource + i;
-		if (res->parent)
-			release_resource(res);
-	}
-}
-
-/**
- * pci_remove_device - remove a hotplug device
- * @dev: the device to remove
- *
- * Delete the device structure from the device lists and 
- * notify userspace (/sbin/hotplug).
- */
-void
-pci_remove_device(struct pci_dev *dev)
-{
-	if (dev->driver) {
-		if (dev->driver->remove)
-			dev->driver->remove(dev);
-		dev->driver = NULL;
-	}
-	list_del(&dev->bus_list);
-	list_del(&dev->global_list);
-	pci_free_resources(dev);
-#ifdef CONFIG_PROC_FS
-	pci_proc_detach_device(dev);
-#endif
-
-	/* notify userspace of hotplug device removal */
-	run_sbin_hotplug(dev, FALSE);
-}
-
-#endif
-
-static struct pci_driver pci_compat_driver = {
-	name: "compat"
-};
-
-/**
- * pci_dev_driver - get the pci_driver of a device
- * @dev: the device to query
- *
- * Returns the appropriate pci_driver structure or %NULL if there is no 
- * registered driver for the device.
- */
-struct pci_driver *
-pci_dev_driver(const struct pci_dev *dev)
-{
-	if (dev->driver)
-		return dev->driver;
-	else {
-		int i;
-		for(i=0; i<=PCI_ROM_RESOURCE; i++)
-			if (dev->resource[i].flags & IORESOURCE_BUSY)
-				return &pci_compat_driver;
-	}
-	return NULL;
-}
-
-
-/*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
- */
-
-static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- *  Wrappers for all PCI configuration access functions.  They just check
- *  alignment, do locking and call the low-level functions pointed to
- *  by pci_dev->ops.
- */
-
-#define PCI_byte_BAD 0
-#define PCI_word_BAD (pos & 1)
-#define PCI_dword_BAD (pos & 3)
-
-#define PCI_OP(rw,size,type) \
-int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
-{									\
-	int res;							\
-	unsigned long flags;						\
-	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
-	spin_lock_irqsave(&pci_lock, flags);				\
-	res = dev->bus->ops->rw##_##size(dev, pos, value);		\
-	spin_unlock_irqrestore(&pci_lock, flags);			\
-	return res;							\
-}
-
-PCI_OP(read, byte, u8 *)
-PCI_OP(read, word, u16 *)
-PCI_OP(read, dword, u32 *)
-PCI_OP(write, byte, u8)
-PCI_OP(write, word, u16)
-PCI_OP(write, dword, u32)
-
 /**
  * pci_set_master - enables bus-mastering for device dev
  * @dev: the PCI device to enable
@@ -966,1080 +554,14 @@
 
 	return 0;
 }
-    
-/*
- * Translate the low bits of the PCI base
- * to the resource type
- */
-static inline unsigned int pci_calc_resource_flags(unsigned int flags)
-{
-	if (flags & PCI_BASE_ADDRESS_SPACE_IO)
-		return IORESOURCE_IO;
-
-	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
-		return IORESOURCE_MEM | IORESOURCE_PREFETCH;
-
-	return IORESOURCE_MEM;
-}
-
-/*
- * Find the extent of a PCI decode..
- */
-static u32 pci_size(u32 base, unsigned long mask)
-{
-	u32 size = mask & base;		/* Find the significant bits */
-	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */
-	return size-1;			/* extent = size - 1 */
-}
-
-static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
-{
-	unsigned int pos, reg, next;
-	u32 l, sz;
-	struct resource *res;
-
-	for(pos=0; pos<howmany; pos = next) {
-		next = pos+1;
-		res = &dev->resource[pos];
-		res->name = dev->name;
-		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
-		pci_read_config_dword(dev, reg, &l);
-		pci_write_config_dword(dev, reg, ~0);
-		pci_read_config_dword(dev, reg, &sz);
-		pci_write_config_dword(dev, reg, l);
-		if (!sz || sz == 0xffffffff)
-			continue;
-		if (l == 0xffffffff)
-			l = 0;
-		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
-			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
-			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
-		} else {
-			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
-			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
-		}
-		res->end = res->start + (unsigned long) sz;
-		res->flags |= pci_calc_resource_flags(l);
-		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
-			pci_read_config_dword(dev, reg+4, &l);
-			next++;
-#if BITS_PER_LONG == 64
-			res->start |= ((unsigned long) l) << 32;
-			res->end = res->start + sz;
-			pci_write_config_dword(dev, reg+4, ~0);
-			pci_read_config_dword(dev, reg+4, &sz);
-			pci_write_config_dword(dev, reg+4, l);
-			if (~sz)
-				res->end = res->start + 0xffffffff +
-						(((unsigned long) ~sz) << 32);
-#else
-			if (l) {
-				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
-				res->start = 0;
-				res->flags = 0;
-				continue;
-			}
-#endif
-		}
-	}
-	if (rom) {
-		dev->rom_base_reg = rom;
-		res = &dev->resource[PCI_ROM_RESOURCE];
-		pci_read_config_dword(dev, rom, &l);
-		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
-		pci_read_config_dword(dev, rom, &sz);
-		pci_write_config_dword(dev, rom, l);
-		if (l == 0xffffffff)
-			l = 0;
-		if (sz && sz != 0xffffffff) {
-			res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
-			  IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
-			res->start = l & PCI_ROM_ADDRESS_MASK;
-			sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
-			res->end = res->start + (unsigned long) sz;
-		}
-		res->name = dev->name;
-	}
-}
-
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
-{
-	struct pci_dev *dev = child->self;
-	u8 io_base_lo, io_limit_lo;
-	u16 mem_base_lo, mem_limit_lo;
-	unsigned long base, limit;
-	struct resource *res;
-	int i;
-
-	if (!dev)		/* It's a host bus, nothing to read */
-		return;
-
-	for(i=0; i<3; i++)
-		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-
-	res = child->resource[0];
-	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
-	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
-	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
-	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
-
-	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
-		u16 io_base_hi, io_limit_hi;
-		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
-		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
-		base |= (io_base_hi << 16);
-		limit |= (io_limit_hi << 16);
-	}
-
-	if (base && base <= limit) {
-		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
-		res->start = base;
-		res->end = limit + 0xfff;
-		res->name = child->name;
-	} else {
-		/*
-		 * Ugh. We don't know enough about this bridge. Just assume
-		 * that it's entirely transparent.
-		 */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
-		child->resource[0] = child->parent->resource[0];
-	}
-
-	res = child->resource[1];
-	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
-	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
-	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
-	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
-	if (base && base <= limit) {
-		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
-		res->start = base;
-		res->end = limit + 0xfffff;
-		res->name = child->name;
-	} else {
-		/* See comment above. Same thing */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
-		child->resource[1] = child->parent->resource[1];
-	}
-
-	res = child->resource[2];
-	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
-	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
-	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
-	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
-
-	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
-		u32 mem_base_hi, mem_limit_hi;
-		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
-		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
-#if BITS_PER_LONG == 64
-		base |= ((long) mem_base_hi) << 32;
-		limit |= ((long) mem_limit_hi) << 32;
-#else
-		if (mem_base_hi || mem_limit_hi) {
-			printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
-			return;
-		}
-#endif
-	}
-	if (base && base <= limit) {
-		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
-		res->start = base;
-		res->end = limit + 0xfffff;
-		res->name = child->name;
-	} else {
-		/* See comments above */
-		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
-		child->resource[2] = child->parent->resource[2];
-	}
-}
-
-static struct pci_bus * __devinit pci_alloc_bus(void)
-{
-	struct pci_bus *b;
-
-	b = kmalloc(sizeof(*b), GFP_KERNEL);
-	if (b) {
-		memset(b, 0, sizeof(*b));
-		INIT_LIST_HEAD(&b->children);
-		INIT_LIST_HEAD(&b->devices);
-	}
-	return b;
-}
-
-struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
-{
-	struct pci_bus *child;
-	int i;
-
-	/*
-	 * Allocate a new bus, and inherit stuff from the parent..
-	 */
-	child = pci_alloc_bus();
-
-	list_add_tail(&child->node, &parent->children);
-	child->self = dev;
-	dev->subordinate = child;
-	child->parent = parent;
-	child->ops = parent->ops;
-	child->sysdata = parent->sysdata;
-	child->dev = &dev->dev;
-
-	/*
-	 * Set up the primary, secondary and subordinate
-	 * bus numbers.
-	 */
-	child->number = child->secondary = busnr;
-	child->primary = parent->secondary;
-	child->subordinate = 0xff;
-
-	/* Set up default resource pointers.. */
-	for (i = 0; i < 4; i++)
-		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-
-	return child;
-}
-
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus);
-
-/*
- * If it's a bridge, configure it and scan the bus behind it.
- * For CardBus bridges, we don't scan behind as the devices will
- * be handled by the bridge driver itself.
- *
- * We need to process bridges in two passes -- first we scan those
- * already configured by the BIOS and after we are done with all of
- * them, we proceed to assigning numbers to the remaining buses in
- * order to avoid overlaps between old and new bus numbers.
- */
-static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
-{
-	unsigned int buses;
-	unsigned short cr;
-	struct pci_bus *child;
-	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
-
-	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
-	DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
-	if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
-		/*
-		 * Bus already configured by firmware, process it in the first
-		 * pass and just note the configuration.
-		 */
-		if (pass)
-			return max;
-		child = pci_add_new_bus(bus, dev, 0);
-		child->primary = buses & 0xFF;
-		child->secondary = (buses >> 8) & 0xFF;
-		child->subordinate = (buses >> 16) & 0xFF;
-		child->number = child->secondary;
-		if (!is_cardbus) {
-			unsigned int cmax = pci_do_scan_bus(child);
-			if (cmax > max) max = cmax;
-		} else {
-			unsigned int cmax = child->subordinate;
-			if (cmax > max) max = cmax;
-		}
-	} else {
-		/*
-		 * We need to assign a number to this bus which we always
-		 * do in the second pass. We also keep all address decoders
-		 * on the bridge disabled during scanning.  FIXME: Why?
-		 */
-		if (!pass)
-			return max;
-		pci_read_config_word(dev, PCI_COMMAND, &cr);
-		pci_write_config_word(dev, PCI_COMMAND, 0x0000);
-		pci_write_config_word(dev, PCI_STATUS, 0xffff);
-
-		child = pci_add_new_bus(bus, dev, ++max);
-		buses = (buses & 0xff000000)
-		      | ((unsigned int)(child->primary)     <<  0)
-		      | ((unsigned int)(child->secondary)   <<  8)
-		      | ((unsigned int)(child->subordinate) << 16);
-		/*
-		 * We need to blast all three values with a single write.
-		 */
-		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
-		if (!is_cardbus) {
-			/* Now we can scan all subordinate buses... */
-			max = pci_do_scan_bus(child);
-		} else {
-			/*
-			 * For CardBus bridges, we leave 4 bus numbers
-			 * as cards with a PCI-to-PCI bridge can be
-			 * inserted later.
-			 */
-			max += 3;
-		}
-		/*
-		 * Set the subordinate bus number to its real value.
-		 */
-		child->subordinate = max;
-		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
-		pci_write_config_word(dev, PCI_COMMAND, cr);
-	}
-	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
-
-	return max;
-}
-
-/*
- * Read interrupt line and base address registers.
- * The architecture-dependent code can tweak these, of course.
- */
-static void pci_read_irq(struct pci_dev *dev)
-{
-	unsigned char irq;
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
-	if (irq)
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-	dev->irq = irq;
-}
-
-/**
- * pci_setup_device - fill in class and map information of a device
- * @dev: the device structure to fill
- *
- * Initialize the device structure with information about the device's 
- * vendor,class,memory and IO-space addresses,IRQ lines etc.
- * Called at initialisation of the PCI subsystem and by CardBus services.
- * Returns 0 on success and -1 if unknown type of device (not normal, bridge
- * or CardBus).
- */
-int pci_setup_device(struct pci_dev * dev)
-{
-	u32 class;
-
-	sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-	sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
-	
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
-	class >>= 8;				    /* upper 3 bytes */
-	dev->class = class;
-	class >>= 8;
-
-	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
-
-	/* "Unknown power state" */
-	dev->current_state = 4;
-
-	switch (dev->hdr_type) {		    /* header type */
-	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
-		if (class == PCI_CLASS_BRIDGE_PCI)
-			goto bad;
-		pci_read_irq(dev);
-		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
-		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
-		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
-		break;
-
-	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
-		if (class != PCI_CLASS_BRIDGE_PCI)
-			goto bad;
-		pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
-		break;
-
-	case PCI_HEADER_TYPE_CARDBUS:		    /* CardBus bridge header */
-		if (class != PCI_CLASS_BRIDGE_CARDBUS)
-			goto bad;
-		pci_read_irq(dev);
-		pci_read_bases(dev, 1, 0);
-		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
-		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
-		break;
-
-	default:				    /* unknown header */
-		printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
-			dev->slot_name, dev->hdr_type);
-		return -1;
-
-	bad:
-		printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
-		       dev->slot_name, class, dev->hdr_type);
-		dev->class = PCI_CLASS_NOT_DEFINED;
-	}
-
-	/* We found a fine healthy device, go go go... */
-	return 0;
-}
-
-/*
- * Read the config data for a PCI device, sanity-check it
- * and fill in the dev structure...
- */
-struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
-{
-	struct pci_dev *dev;
-	u32 l;
-
-	if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
-		return NULL;
-
-	/* some broken boards return 0 or ~0 if a slot is empty: */
-	if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
-		return NULL;
-
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return NULL;
-
-	memcpy(dev, temp, sizeof(*dev));
-	dev->vendor = l & 0xffff;
-	dev->device = (l >> 16) & 0xffff;
-
-	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
-	   set this higher, assuming the system even supports it.  */
-	dev->dma_mask = 0xffffffff;
-	if (pci_setup_device(dev) < 0) {
-		kfree(dev);
-		return NULL;
-	}
-
-	/* now put in global tree */
-	strcpy(dev->dev.name,dev->name);
-	strcpy(dev->dev.bus_id,dev->slot_name);
-
-	device_register(&dev->dev);
-	return dev;
-}
-
-struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
-{
-	struct pci_bus *bus = temp->bus;
-	struct pci_dev *dev;
-	struct pci_dev *first_dev = NULL;
-	int func = 0;
-	int is_multi = 0;
-	u8 hdr_type;
-
-	for (func = 0; func < 8; func++, temp->devfn++) {
-		if (func && !is_multi)		/* not a multi-function device */
-			continue;
-		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
-			continue;
-		temp->hdr_type = hdr_type & 0x7f;
-
-		dev = pci_scan_device(temp);
-		if (!dev)
-			continue;
-		pci_name_device(dev);
-		if (!func) {
-			is_multi = hdr_type & 0x80;
-			first_dev = dev;
-		}
-
-		/*
-		 * Link the device to both the global PCI device chain and
-		 * the per-bus list of devices.
-		 */
-		list_add_tail(&dev->global_list, &pci_devices);
-		list_add_tail(&dev->bus_list, &bus->devices);
-
-		/* Fix up broken headers */
-		pci_fixup_device(PCI_FIXUP_HEADER, dev);
-	}
-	return first_dev;
-}
-
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
-{
-	unsigned int devfn, max, pass;
-	struct list_head *ln;
-	struct pci_dev *dev, dev0;
-
-	DBG("Scanning bus %02x\n", bus->number);
-	max = bus->secondary;
-
-	/* Create a device template */
-	memset(&dev0, 0, sizeof(dev0));
-	dev0.bus = bus;
-	dev0.sysdata = bus->sysdata;
-	dev0.dev.parent = bus->dev;
-	dev0.dev.driver = &pci_device_driver;
-
-	/* Go find them, Rover! */
-	for (devfn = 0; devfn < 0x100; devfn += 8) {
-		dev0.devfn = devfn;
-		pci_scan_slot(&dev0);
-	}
-
-	/*
-	 * After performing arch-dependent fixup of the bus, look behind
-	 * all PCI-to-PCI bridges on this bus.
-	 */
-	DBG("Fixups for bus %02x\n", bus->number);
-	pcibios_fixup_bus(bus);
-	for (pass=0; pass < 2; pass++)
-		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-			dev = pci_dev_b(ln);
-			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
-				max = pci_scan_bridge(bus, dev, max, pass);
-		}
-
-	/*
-	 * We've scanned the bus and so we know all about what's on
-	 * the other side of any bridges that may be on this bus plus
-	 * any devices.
-	 *
-	 * Return how far we've got finding sub-buses.
-	 */
-	DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
-	return max;
-}
-
-int __devinit pci_bus_exists(const struct list_head *list, int nr)
-{
-	const struct list_head *l;
-
-	for(l=list->next; l != list; l = l->next) {
-		const struct pci_bus *b = pci_bus_b(l);
-		if (b->number == nr || pci_bus_exists(&b->children, nr))
-			return 1;
-	}
-	return 0;
-}
-
-struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
-{
-	struct pci_bus *b;
-
-	if (pci_bus_exists(&pci_root_buses, bus)) {
-		/* If we already got to this bus through a different bridge, ignore it */
-		DBG("PCI: Bus %02x already known\n", bus);
-		return NULL;
-	}
-
-	b = pci_alloc_bus();
-	if (!b)
-		return NULL;
-	list_add_tail(&b->node, &pci_root_buses);
-
-	b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
-	memset(b->dev,0,sizeof(*(b->dev)));
-	sprintf(b->dev->bus_id,"pci%d",bus);
-	strcpy(b->dev->name,"Host/PCI Bridge");
-	device_register(b->dev);
-
-	b->number = b->secondary = bus;
-	b->resource[0] = &ioport_resource;
-	b->resource[1] = &iomem_resource;
-	return b;
-}
-
-struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
-{
-	struct pci_bus *b = pci_alloc_primary_bus(bus);
-	if (b) {
-		b->sysdata = sysdata;
-		b->ops = ops;
-		b->subordinate = pci_do_scan_bus(b);
-	}
-	return b;
-}
-
-#ifdef CONFIG_PM
-
-/*
- * PCI Power management..
- *
- * This needs to be done centralized, so that we power manage PCI
- * devices in the right order: we should not shut down PCI bridges
- * before we've shut down the devices behind them, and we should
- * not wake up devices before we've woken up the bridge to the
- * device.. Eh?
- *
- * We do not touch devices that don't have a driver that exports
- * a suspend/resume function. That is just too dangerous. If the default
- * PCI suspend/resume functions work for a device, the driver can
- * easily implement them (ie just have a suspend function that calls
- * the pci_set_power_state() function).
- */
-
-static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
-{
-	int error = 0;
-	if (dev) {
-		struct pci_driver *driver = dev->driver;
-		if (driver && driver->save_state) 
-			error = driver->save_state(dev,state);
-	}
-	return error;
-}
-
-static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
-{
-	int error = 0;
-	if (dev) {
-		struct pci_driver *driver = dev->driver;
-		if (driver && driver->suspend)
-			error = driver->suspend(dev,state);
-	}
-	return error;
-}
-
-static int pci_pm_resume_device(struct pci_dev *dev)
-{
-	int error = 0;
-	if (dev) {
-		struct pci_driver *driver = dev->driver;
-		if (driver && driver->resume)
-			error = driver->resume(dev);
-	}
-	return error;
-}
-
-static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
-{
-	struct list_head *list;
-	int error = 0;
-
-	list_for_each(list, &bus->children) {
-		error = pci_pm_save_state_bus(pci_bus_b(list),state);
-		if (error) return error;
-	}
-	list_for_each(list, &bus->devices) {
-		error = pci_pm_save_state_device(pci_dev_b(list),state);
-		if (error) return error;
-	}
-	return 0;
-}
-
-static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
-{
-	struct list_head *list;
-
-	/* Walk the bus children list */
-	list_for_each(list, &bus->children) 
-		pci_pm_suspend_bus(pci_bus_b(list),state);
-
-	/* Walk the device children list */
-	list_for_each(list, &bus->devices)
-		pci_pm_suspend_device(pci_dev_b(list),state);
-	return 0;
-}
-
-static int pci_pm_resume_bus(struct pci_bus *bus)
-{
-	struct list_head *list;
-
-	/* Walk the device children list */
-	list_for_each(list, &bus->devices)
-		pci_pm_resume_device(pci_dev_b(list));
-
-	/* And then walk the bus children */
-	list_for_each(list, &bus->children)
-		pci_pm_resume_bus(pci_bus_b(list));
-	return 0;
-}
-
-static int pci_pm_save_state(u32 state)
-{
-	struct list_head *list;
-	struct pci_bus *bus;
-	int error = 0;
-
-	list_for_each(list, &pci_root_buses) {
-		bus = pci_bus_b(list);
-		error = pci_pm_save_state_bus(bus,state);
-		if (!error)
-			error = pci_pm_save_state_device(bus->self,state);
-	}
-	return error;
-}
-
-static int pci_pm_suspend(u32 state)
-{
-	struct list_head *list;
-	struct pci_bus *bus;
-
-	list_for_each(list, &pci_root_buses) {
-		bus = pci_bus_b(list);
-		pci_pm_suspend_bus(bus,state);
-		pci_pm_suspend_device(bus->self,state);
-	}
-	return 0;
-}
-
-static int pci_pm_resume(void)
-{
-	struct list_head *list;
-	struct pci_bus *bus;
-
-	list_for_each(list, &pci_root_buses) {
-		bus = pci_bus_b(list);
-		pci_pm_resume_device(bus->self);
-		pci_pm_resume_bus(bus);
-	}
-	return 0;
-}
-
-static int 
-pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
-{
-	int error = 0;
-
-	switch (rqst) {
-	case PM_SAVE_STATE:
-		error = pci_pm_save_state((unsigned long)data);
-		break;
-	case PM_SUSPEND:
-		error = pci_pm_suspend((unsigned long)data);
-		break;
-	case PM_RESUME:
-		error = pci_pm_resume();
-		break;
-	default: break;
-	}
-	return error;
-}
-
-#endif
-
-/*
- * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct pci_pool {	/* the pool */
-	struct list_head	page_list;
-	spinlock_t		lock;
-	size_t			blocks_per_page;
-	size_t			size;
-	struct pci_dev		*dev;
-	size_t			allocation;
-	char			name [32];
-	wait_queue_head_t	waitq;
-};
-
-struct pci_page {	/* cacheable header for 'allocation' bytes */
-	struct list_head	page_list;
-	void			*vaddr;
-	dma_addr_t		dma;
-	unsigned long		bitmap [0];
-};
-
-#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
-#define	POOL_POISON_BYTE	0xa7
-
-
-/**
- * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @pdev: pci device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- * @mem_flags: SLAB_* flags.
- *
- * Returns a pci allocation pool with the requested characteristics, or
- * null if one can't be created.  Given one of these pools, pci_pool_alloc()
- * may be used to allocate memory.  Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives.  The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from pci_pool_alloc() won't
- * cross that size boundary.  This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct pci_pool *
-pci_pool_create (const char *name, struct pci_dev *pdev,
-	size_t size, size_t align, size_t allocation, int mem_flags)
-{
-	struct pci_pool		*retval;
-
-	if (align == 0)
-		align = 1;
-	if (size == 0)
-		return 0;
-	else if (size < align)
-		size = align;
-	else if ((size % align) != 0) {
-		size += align + 1;
-		size &= ~(align - 1);
-	}
-
-	if (allocation == 0) {
-		if (PAGE_SIZE < size)
-			allocation = size;
-		else
-			allocation = PAGE_SIZE;
-		// FIXME: round up for less fragmentation
-	} else if (allocation < size)
-		return 0;
-
-	if (!(retval = kmalloc (sizeof *retval, mem_flags)))
-		return retval;
-
-	strncpy (retval->name, name, sizeof retval->name);
-	retval->name [sizeof retval->name - 1] = 0;
-
-	retval->dev = pdev;
-	INIT_LIST_HEAD (&retval->page_list);
-	spin_lock_init (&retval->lock);
-	retval->size = size;
-	retval->allocation = allocation;
-	retval->blocks_per_page = allocation / size;
-	init_waitqueue_head (&retval->waitq);
-
-	return retval;
-}
-
-
-static struct pci_page *
-pool_alloc_page (struct pci_pool *pool, int mem_flags)
-{
-	struct pci_page	*page;
-	int		mapsize;
-
-	mapsize = pool->blocks_per_page;
-	mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
-	mapsize *= sizeof (long);
-
-	page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
-	if (!page)
-		return 0;
-	page->vaddr = pci_alloc_consistent (pool->dev,
-					    pool->allocation,
-					    &page->dma);
-	if (page->vaddr) {
-		memset (page->bitmap, 0xff, mapsize);	// bit set == free
-#ifdef	CONFIG_DEBUG_SLAB
-		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
-#endif
-		list_add (&page->page_list, &pool->page_list);
-	} else {
-		kfree (page);
-		page = 0;
-	}
-	return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
-	while (blocks > 0) {
-		if (*bitmap++ != ~0UL)
-			return 1;
-		blocks -= BITS_PER_LONG;
-	}
-	return 0;
-}
-
-static void
-pool_free_page (struct pci_pool *pool, struct pci_page *page)
-{
-	dma_addr_t	dma = page->dma;
-
-#ifdef	CONFIG_DEBUG_SLAB
-	memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
-#endif
-	pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
-	list_del (&page->page_list);
-	kfree (page);
-}
-
-
-/**
- * pci_pool_destroy - destroys a pool of pci memory blocks.
- * @pool: pci pool that will be destroyed
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-pci_pool_destroy (struct pci_pool *pool)
-{
-	unsigned long		flags;
-
-	spin_lock_irqsave (&pool->lock, flags);
-	while (!list_empty (&pool->page_list)) {
-		struct pci_page		*page;
-		page = list_entry (pool->page_list.next,
-				struct pci_page, page_list);
-		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
-			printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
-				pool->dev ? pool->dev->slot_name : NULL,
-				pool->name, page->vaddr);
-			/* leak the still-in-use consistent memory */
-			list_del (&page->page_list);
-			kfree (page);
-		} else
-			pool_free_page (pool, page);
-	}
-	spin_unlock_irqrestore (&pool->lock, flags);
-	kfree (pool);
-}
-
-
-/**
- * pci_pool_alloc - get a block of consistent memory
- * @pool: pci pool that will produce the block
- * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
-{
-	unsigned long		flags;
-	struct list_head	*entry;
-	struct pci_page		*page;
-	int			map, block;
-	size_t			offset;
-	void			*retval;
-
-restart:
-	spin_lock_irqsave (&pool->lock, flags);
-	list_for_each (entry, &pool->page_list) {
-		int		i;
-		page = list_entry (entry, struct pci_page, page_list);
-		/* only cachable accesses here ... */
-		for (map = 0, i = 0;
-				i < pool->blocks_per_page;
-				i += BITS_PER_LONG, map++) {
-			if (page->bitmap [map] == 0)
-				continue;
-			block = ffz (~ page->bitmap [map]);
-			if ((i + block) < pool->blocks_per_page) {
-				clear_bit (block, &page->bitmap [map]);
-				offset = (BITS_PER_LONG * map) + block;
-				offset *= pool->size;
-				goto ready;
-			}
-		}
-	}
-	if (!(page = pool_alloc_page (pool, mem_flags))) {
-		if (mem_flags == SLAB_KERNEL) {
-			DECLARE_WAITQUEUE (wait, current);
-
-			current->state = TASK_INTERRUPTIBLE;
-			add_wait_queue (&pool->waitq, &wait);
-			spin_unlock_irqrestore (&pool->lock, flags);
-
-			schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
-			current->state = TASK_RUNNING;
-			remove_wait_queue (&pool->waitq, &wait);
-			goto restart;
-		}
-		retval = 0;
-		goto done;
-	}
-
-	clear_bit (0, &page->bitmap [0]);
-	offset = 0;
-ready:
-	retval = offset + page->vaddr;
-	*handle = offset + page->dma;
-done:
-	spin_unlock_irqrestore (&pool->lock, flags);
-	return retval;
-}
-
-
-static struct pci_page *
-pool_find_page (struct pci_pool *pool, dma_addr_t dma)
-{
-	unsigned long		flags;
-	struct list_head	*entry;
-	struct pci_page		*page;
-
-	spin_lock_irqsave (&pool->lock, flags);
-	list_for_each (entry, &pool->page_list) {
-		page = list_entry (entry, struct pci_page, page_list);
-		if (dma < page->dma)
-			continue;
-		if (dma < (page->dma + pool->allocation))
-			goto done;
-	}
-	page = 0;
-done:
-	spin_unlock_irqrestore (&pool->lock, flags);
-	return page;
-}
-
-
-/**
- * pci_pool_free - put block back into pci pool
- * @pool: the pci pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
-{
-	struct pci_page		*page;
-	unsigned long		flags;
-	int			map, block;
-
-	if ((page = pool_find_page (pool, dma)) == 0) {
-		printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
-			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, (unsigned long) dma);
-		return;
-	}
-
-	block = dma - page->dma;
-	block /= pool->size;
-	map = block / BITS_PER_LONG;
-	block %= BITS_PER_LONG;
-
-#ifdef	CONFIG_DEBUG_SLAB
-	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
-		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
-			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, (unsigned long) dma);
-		return;
-	}
-	if (page->bitmap [map] & (1UL << block)) {
-		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
-			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, dma);
-		return;
-	}
-	memset (vaddr, POOL_POISON_BYTE, pool->size);
-#endif
-
-	spin_lock_irqsave (&pool->lock, flags);
-	set_bit (block, &page->bitmap [map]);
-	if (waitqueue_active (&pool->waitq))
-		wake_up (&pool->waitq);
-	/*
-	 * Resist a temptation to do
-	 *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
-	 * it is not interrupt safe. Better have empty pages hang around.
-	 */
-	spin_unlock_irqrestore (&pool->lock, flags);
-}
-
 
 static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
 
-	pcibios_init();
-
 	pci_for_each_dev(dev) {
 		pci_fixup_device(PCI_FIXUP_FINAL, dev);
 	}
-
-#ifdef CONFIG_PM
-	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
-#endif
 	return 0;
 }
 
@@ -2058,55 +580,23 @@
 	return 1;
 }
 
-subsys_initcall(pci_init);
+device_initcall(pci_init);
 
 __setup("pci=", pci_setup);
 
-EXPORT_SYMBOL(pci_read_config_byte);
-EXPORT_SYMBOL(pci_read_config_word);
-EXPORT_SYMBOL(pci_read_config_dword);
-EXPORT_SYMBOL(pci_write_config_byte);
-EXPORT_SYMBOL(pci_write_config_word);
-EXPORT_SYMBOL(pci_write_config_dword);
-EXPORT_SYMBOL(pci_devices);
-EXPORT_SYMBOL(pci_root_buses);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_disable_device);
 EXPORT_SYMBOL(pci_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
-EXPORT_SYMBOL(pci_find_class);
-EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_slot);
-EXPORT_SYMBOL(pci_find_subsys);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
 EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
-EXPORT_SYMBOL(pci_register_driver);
-EXPORT_SYMBOL(pci_unregister_driver);
-EXPORT_SYMBOL(pci_dev_driver);
-EXPORT_SYMBOL(pci_match_device);
 EXPORT_SYMBOL(pci_find_parent_resource);
 
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_setup_device);
-EXPORT_SYMBOL(pci_insert_device);
-EXPORT_SYMBOL(pci_remove_device);
-EXPORT_SYMBOL(pci_announce_device_to_drivers);
-EXPORT_SYMBOL(pci_add_new_bus);
-EXPORT_SYMBOL(pci_do_scan_bus);
-EXPORT_SYMBOL(pci_scan_slot);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(pci_proc_attach_device);
-EXPORT_SYMBOL(pci_proc_detach_device);
-EXPORT_SYMBOL(pci_proc_attach_bus);
-EXPORT_SYMBOL(pci_proc_detach_bus);
-#endif
-#endif
-
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
@@ -2128,11 +618,3 @@
 
 EXPORT_SYMBOL(isa_dma_bridge_buggy);
 EXPORT_SYMBOL(pci_pci_problems);
-
-/* Pool allocator */
-
-EXPORT_SYMBOL (pci_pool_create);
-EXPORT_SYMBOL (pci_pool_destroy);
-EXPORT_SYMBOL (pci_pool_alloc);
-EXPORT_SYMBOL (pci_pool_free);
-
diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/pool.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,336 @@
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+/*
+ * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
+ * small blocks are easily used by drivers for bus mastering controllers.
+ * This should probably be sharing the guts of the slab allocator.
+ */
+
+struct pci_pool {	/* the pool */
+	struct list_head	page_list;
+	spinlock_t		lock;
+	size_t			blocks_per_page;
+	size_t			size;
+	struct pci_dev		*dev;
+	size_t			allocation;
+	char			name [32];
+	wait_queue_head_t	waitq;
+};
+
+struct pci_page {	/* cacheable header for 'allocation' bytes */
+	struct list_head	page_list;
+	void			*vaddr;
+	dma_addr_t		dma;
+	unsigned long		bitmap [0];
+};
+
+#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
+#define	POOL_POISON_BYTE	0xa7
+
+
+/**
+ * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @pdev: pci device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ * @mem_flags: SLAB_* flags.
+ *
+ * Returns a pci allocation pool with the requested characteristics, or
+ * null if one can't be created.  Given one of these pools, pci_pool_alloc()
+ * may be used to allocate memory.  Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives.  The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If allocation is nonzero, objects returned from pci_pool_alloc() won't
+ * cross that size boundary.  This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct pci_pool *
+pci_pool_create (const char *name, struct pci_dev *pdev,
+	size_t size, size_t align, size_t allocation, int mem_flags)
+{
+	struct pci_pool		*retval;
+
+	if (align == 0)
+		align = 1;
+	if (size == 0)
+		return 0;
+	else if (size < align)
+		size = align;
+	else if ((size % align) != 0) {
+		size += align + 1;
+		size &= ~(align - 1);
+	}
+
+	if (allocation == 0) {
+		if (PAGE_SIZE < size)
+			allocation = size;
+		else
+			allocation = PAGE_SIZE;
+		// FIXME: round up for less fragmentation
+	} else if (allocation < size)
+		return 0;
+
+	if (!(retval = kmalloc (sizeof *retval, mem_flags)))
+		return retval;
+
+	strncpy (retval->name, name, sizeof retval->name);
+	retval->name [sizeof retval->name - 1] = 0;
+
+	retval->dev = pdev;
+	INIT_LIST_HEAD (&retval->page_list);
+	spin_lock_init (&retval->lock);
+	retval->size = size;
+	retval->allocation = allocation;
+	retval->blocks_per_page = allocation / size;
+	init_waitqueue_head (&retval->waitq);
+
+	return retval;
+}
+
+
+static struct pci_page *
+pool_alloc_page (struct pci_pool *pool, int mem_flags)
+{
+	struct pci_page	*page;
+	int		mapsize;
+
+	mapsize = pool->blocks_per_page;
+	mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	mapsize *= sizeof (long);
+
+	page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+	if (!page)
+		return 0;
+	page->vaddr = pci_alloc_consistent (pool->dev,
+					    pool->allocation,
+					    &page->dma);
+	if (page->vaddr) {
+		memset (page->bitmap, 0xff, mapsize);	// bit set == free
+#ifdef	CONFIG_DEBUG_SLAB
+		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
+		list_add (&page->page_list, &pool->page_list);
+	} else {
+		kfree (page);
+		page = 0;
+	}
+	return page;
+}
+
+
+static inline int
+is_page_busy (int blocks, unsigned long *bitmap)
+{
+	while (blocks > 0) {
+		if (*bitmap++ != ~0UL)
+			return 1;
+		blocks -= BITS_PER_LONG;
+	}
+	return 0;
+}
+
+static void
+pool_free_page (struct pci_pool *pool, struct pci_page *page)
+{
+	dma_addr_t	dma = page->dma;
+
+#ifdef	CONFIG_DEBUG_SLAB
+	memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
+	pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
+	list_del (&page->page_list);
+	kfree (page);
+}
+
+
+/**
+ * pci_pool_destroy - destroys a pool of pci memory blocks.
+ * @pool: pci pool that will be destroyed
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void
+pci_pool_destroy (struct pci_pool *pool)
+{
+	unsigned long		flags;
+
+	spin_lock_irqsave (&pool->lock, flags);
+	while (!list_empty (&pool->page_list)) {
+		struct pci_page		*page;
+		page = list_entry (pool->page_list.next,
+				struct pci_page, page_list);
+		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
+			printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
+				pool->dev ? pool->dev->slot_name : NULL,
+				pool->name, page->vaddr);
+			/* leak the still-in-use consistent memory */
+			list_del (&page->page_list);
+			kfree (page);
+		} else
+			pool_free_page (pool, page);
+	}
+	spin_unlock_irqrestore (&pool->lock, flags);
+	kfree (pool);
+}
+
+
+/**
+ * pci_pool_alloc - get a block of consistent memory
+ * @pool: pci pool that will produce the block
+ * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, null is returned.
+ */
+void *
+pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+	int			map, block;
+	size_t			offset;
+	void			*retval;
+
+restart:
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		int		i;
+		page = list_entry (entry, struct pci_page, page_list);
+		/* only cachable accesses here ... */
+		for (map = 0, i = 0;
+				i < pool->blocks_per_page;
+				i += BITS_PER_LONG, map++) {
+			if (page->bitmap [map] == 0)
+				continue;
+			block = ffz (~ page->bitmap [map]);
+			if ((i + block) < pool->blocks_per_page) {
+				clear_bit (block, &page->bitmap [map]);
+				offset = (BITS_PER_LONG * map) + block;
+				offset *= pool->size;
+				goto ready;
+			}
+		}
+	}
+	if (!(page = pool_alloc_page (pool, mem_flags))) {
+		if (mem_flags == SLAB_KERNEL) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			current->state = TASK_INTERRUPTIBLE;
+			add_wait_queue (&pool->waitq, &wait);
+			spin_unlock_irqrestore (&pool->lock, flags);
+
+			schedule_timeout (POOL_TIMEOUT_JIFFIES);
+
+			current->state = TASK_RUNNING;
+			remove_wait_queue (&pool->waitq, &wait);
+			goto restart;
+		}
+		retval = 0;
+		goto done;
+	}
+
+	clear_bit (0, &page->bitmap [0]);
+	offset = 0;
+ready:
+	retval = offset + page->vaddr;
+	*handle = offset + page->dma;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return retval;
+}
+
+
+static struct pci_page *
+pool_find_page (struct pci_pool *pool, dma_addr_t dma)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		page = list_entry (entry, struct pci_page, page_list);
+		if (dma < page->dma)
+			continue;
+		if (dma < (page->dma + pool->allocation))
+			goto done;
+	}
+	page = 0;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return page;
+}
+
+
+/**
+ * pci_pool_free - put block back into pci pool
+ * @pool: the pci pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void
+pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
+{
+	struct pci_page		*page;
+	unsigned long		flags;
+	int			map, block;
+
+	if ((page = pool_find_page (pool, dma)) == 0) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, (unsigned long) dma);
+		return;
+	}
+
+	block = dma - page->dma;
+	block /= pool->size;
+	map = block / BITS_PER_LONG;
+	block %= BITS_PER_LONG;
+
+#ifdef	CONFIG_DEBUG_SLAB
+	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, (unsigned long) dma);
+		return;
+	}
+	if (page->bitmap [map] & (1UL << block)) {
+		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, dma);
+		return;
+	}
+	memset (vaddr, POOL_POISON_BYTE, pool->size);
+#endif
+
+	spin_lock_irqsave (&pool->lock, flags);
+	set_bit (block, &page->bitmap [map]);
+	if (waitqueue_active (&pool->waitq))
+		wake_up (&pool->waitq);
+	/*
+	 * Resist a temptation to do
+	 *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
+	 * it is not interrupt safe. Better have empty pages hang around.
+	 */
+	spin_unlock_irqrestore (&pool->lock, flags);
+}
+
+
+EXPORT_SYMBOL (pci_pool_create);
+EXPORT_SYMBOL (pci_pool_destroy);
+EXPORT_SYMBOL (pci_pool_alloc);
+EXPORT_SYMBOL (pci_pool_free);
diff -Nru a/drivers/pci/power.c b/drivers/pci/power.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/power.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,164 @@
+#include <linux/pci.h>
+#include <linux/pm.h>
+
+/*
+ * PCI Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ */
+
+static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->save_state) 
+			error = driver->save_state(dev,state);
+	}
+	return error;
+}
+
+static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->suspend)
+			error = driver->suspend(dev,state);
+	}
+	return error;
+}
+
+static int pci_pm_resume_device(struct pci_dev *dev)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->resume)
+			error = driver->resume(dev);
+	}
+	return error;
+}
+
+static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
+{
+	struct list_head *list;
+	int error = 0;
+
+	list_for_each(list, &bus->children) {
+		error = pci_pm_save_state_bus(pci_bus_b(list),state);
+		if (error) return error;
+	}
+	list_for_each(list, &bus->devices) {
+		error = pci_pm_save_state_device(pci_dev_b(list),state);
+		if (error) return error;
+	}
+	return 0;
+}
+
+static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
+{
+	struct list_head *list;
+
+	/* Walk the bus children list */
+	list_for_each(list, &bus->children) 
+		pci_pm_suspend_bus(pci_bus_b(list),state);
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_suspend_device(pci_dev_b(list),state);
+	return 0;
+}
+
+static int pci_pm_resume_bus(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_resume_device(pci_dev_b(list));
+
+	/* And then walk the bus children */
+	list_for_each(list, &bus->children)
+		pci_pm_resume_bus(pci_bus_b(list));
+	return 0;
+}
+
+static int pci_pm_save_state(u32 state)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+	int error = 0;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		error = pci_pm_save_state_bus(bus,state);
+		if (!error)
+			error = pci_pm_save_state_device(bus->self,state);
+	}
+	return error;
+}
+
+static int pci_pm_suspend(u32 state)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_suspend_bus(bus,state);
+		pci_pm_suspend_device(bus->self,state);
+	}
+	return 0;
+}
+
+static int pci_pm_resume(void)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_resume_device(bus->self);
+		pci_pm_resume_bus(bus);
+	}
+	return 0;
+}
+
+static int 
+pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
+{
+	int error = 0;
+
+	switch (rqst) {
+	case PM_SAVE_STATE:
+		error = pci_pm_save_state((unsigned long)data);
+		break;
+	case PM_SUSPEND:
+		error = pci_pm_suspend((unsigned long)data);
+		break;
+	case PM_RESUME:
+		error = pci_pm_resume();
+		break;
+	default: break;
+	}
+	return error;
+}
+
+static int __init pci_pm_init(void)
+{
+	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+	return 0;
+}
+
+subsys_initcall(pci_pm_init);
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/probe.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,605 @@
+/*
+ * probe.c - PCI detection and setup code
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+LIST_HEAD(pci_root_buses);
+LIST_HEAD(pci_devices);
+
+extern struct device_driver pci_device_driver;
+
+/*
+ * Translate the low bits of the PCI base
+ * to the resource type
+ */
+static inline unsigned int pci_calc_resource_flags(unsigned int flags)
+{
+	if (flags & PCI_BASE_ADDRESS_SPACE_IO)
+		return IORESOURCE_IO;
+
+	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+		return IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+	return IORESOURCE_MEM;
+}
+
+/*
+ * Find the extent of a PCI decode..
+ */
+static u32 pci_size(u32 base, unsigned long mask)
+{
+	u32 size = mask & base;		/* Find the significant bits */
+	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */
+	return size-1;			/* extent = size - 1 */
+}
+
+static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
+{
+	unsigned int pos, reg, next;
+	u32 l, sz;
+	struct resource *res;
+
+	for(pos=0; pos<howmany; pos = next) {
+		next = pos+1;
+		res = &dev->resource[pos];
+		res->name = dev->name;
+		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
+		pci_read_config_dword(dev, reg, &l);
+		pci_write_config_dword(dev, reg, ~0);
+		pci_read_config_dword(dev, reg, &sz);
+		pci_write_config_dword(dev, reg, l);
+		if (!sz || sz == 0xffffffff)
+			continue;
+		if (l == 0xffffffff)
+			l = 0;
+		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
+		} else {
+			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+		}
+		res->end = res->start + (unsigned long) sz;
+		res->flags |= pci_calc_resource_flags(l);
+		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+			pci_read_config_dword(dev, reg+4, &l);
+			next++;
+#if BITS_PER_LONG == 64
+			res->start |= ((unsigned long) l) << 32;
+			res->end = res->start + sz;
+			pci_write_config_dword(dev, reg+4, ~0);
+			pci_read_config_dword(dev, reg+4, &sz);
+			pci_write_config_dword(dev, reg+4, l);
+			if (~sz)
+				res->end = res->start + 0xffffffff +
+						(((unsigned long) ~sz) << 32);
+#else
+			if (l) {
+				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
+				res->start = 0;
+				res->flags = 0;
+				continue;
+			}
+#endif
+		}
+	}
+	if (rom) {
+		dev->rom_base_reg = rom;
+		res = &dev->resource[PCI_ROM_RESOURCE];
+		pci_read_config_dword(dev, rom, &l);
+		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
+		pci_read_config_dword(dev, rom, &sz);
+		pci_write_config_dword(dev, rom, l);
+		if (l == 0xffffffff)
+			l = 0;
+		if (sz && sz != 0xffffffff) {
+			res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
+			  IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+			res->start = l & PCI_ROM_ADDRESS_MASK;
+			sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
+			res->end = res->start + (unsigned long) sz;
+		}
+		res->name = dev->name;
+	}
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+	struct pci_dev *dev = child->self;
+	u8 io_base_lo, io_limit_lo;
+	u16 mem_base_lo, mem_limit_lo;
+	unsigned long base, limit;
+	struct resource *res;
+	int i;
+
+	if (!dev)		/* It's a host bus, nothing to read */
+		return;
+
+	for(i=0; i<3; i++)
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+	res = child->resource[0];
+	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
+	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
+
+	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+		u16 io_base_hi, io_limit_hi;
+		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
+		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
+		base |= (io_base_hi << 16);
+		limit |= (io_limit_hi << 16);
+	}
+
+	if (base && base <= limit) {
+		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res->start = base;
+		res->end = limit + 0xfff;
+		res->name = child->name;
+	} else {
+		/*
+		 * Ugh. We don't know enough about this bridge. Just assume
+		 * that it's entirely transparent.
+		 */
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
+		child->resource[0] = child->parent->resource[0];
+	}
+
+	res = child->resource[1];
+	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	if (base && base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+		res->start = base;
+		res->end = limit + 0xfffff;
+		res->name = child->name;
+	} else {
+		/* See comment above. Same thing */
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
+		child->resource[1] = child->parent->resource[1];
+	}
+
+	res = child->resource[2];
+	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+
+	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+		u32 mem_base_hi, mem_limit_hi;
+		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
+		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+#if BITS_PER_LONG == 64
+		base |= ((long) mem_base_hi) << 32;
+		limit |= ((long) mem_limit_hi) << 32;
+#else
+		if (mem_base_hi || mem_limit_hi) {
+			printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
+			return;
+		}
+#endif
+	}
+	if (base && base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		res->start = base;
+		res->end = limit + 0xfffff;
+		res->name = child->name;
+	} else {
+		/* See comments above */
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
+		child->resource[2] = child->parent->resource[2];
+	}
+}
+
+static struct pci_bus * __devinit pci_alloc_bus(void)
+{
+	struct pci_bus *b;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (b) {
+		memset(b, 0, sizeof(*b));
+		INIT_LIST_HEAD(&b->children);
+		INIT_LIST_HEAD(&b->devices);
+	}
+	return b;
+}
+
+struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+{
+	struct pci_bus *child;
+	int i;
+
+	/*
+	 * Allocate a new bus, and inherit stuff from the parent..
+	 */
+	child = pci_alloc_bus();
+
+	list_add_tail(&child->node, &parent->children);
+	child->self = dev;
+	dev->subordinate = child;
+	child->parent = parent;
+	child->ops = parent->ops;
+	child->sysdata = parent->sysdata;
+	child->dev = &dev->dev;
+
+	/*
+	 * Set up the primary, secondary and subordinate
+	 * bus numbers.
+	 */
+	child->number = child->secondary = busnr;
+	child->primary = parent->secondary;
+	child->subordinate = 0xff;
+
+	/* Set up default resource pointers.. */
+	for (i = 0; i < 4; i++)
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+	return child;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus);
+
+/*
+ * If it's a bridge, configure it and scan the bus behind it.
+ * For CardBus bridges, we don't scan behind as the devices will
+ * be handled by the bridge driver itself.
+ *
+ * We need to process bridges in two passes -- first we scan those
+ * already configured by the BIOS and after we are done with all of
+ * them, we proceed to assigning numbers to the remaining buses in
+ * order to avoid overlaps between old and new bus numbers.
+ */
+static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+{
+	unsigned int buses;
+	unsigned short cr;
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+	DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
+	if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
+		/*
+		 * Bus already configured by firmware, process it in the first
+		 * pass and just note the configuration.
+		 */
+		if (pass)
+			return max;
+		child = pci_add_new_bus(bus, dev, 0);
+		child->primary = buses & 0xFF;
+		child->secondary = (buses >> 8) & 0xFF;
+		child->subordinate = (buses >> 16) & 0xFF;
+		child->number = child->secondary;
+		if (!is_cardbus) {
+			unsigned int cmax = pci_do_scan_bus(child);
+			if (cmax > max) max = cmax;
+		} else {
+			unsigned int cmax = child->subordinate;
+			if (cmax > max) max = cmax;
+		}
+	} else {
+		/*
+		 * We need to assign a number to this bus which we always
+		 * do in the second pass. We also keep all address decoders
+		 * on the bridge disabled during scanning.  FIXME: Why?
+		 */
+		if (!pass)
+			return max;
+		pci_read_config_word(dev, PCI_COMMAND, &cr);
+		pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+		pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+		child = pci_add_new_bus(bus, dev, ++max);
+		buses = (buses & 0xff000000)
+		      | ((unsigned int)(child->primary)     <<  0)
+		      | ((unsigned int)(child->secondary)   <<  8)
+		      | ((unsigned int)(child->subordinate) << 16);
+		/*
+		 * We need to blast all three values with a single write.
+		 */
+		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+		if (!is_cardbus) {
+			/* Now we can scan all subordinate buses... */
+			max = pci_do_scan_bus(child);
+		} else {
+			/*
+			 * For CardBus bridges, we leave 4 bus numbers
+			 * as cards with a PCI-to-PCI bridge can be
+			 * inserted later.
+			 */
+			max += 3;
+		}
+		/*
+		 * Set the subordinate bus number to its real value.
+		 */
+		child->subordinate = max;
+		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+		pci_write_config_word(dev, PCI_COMMAND, cr);
+	}
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
+	return max;
+}
+
+/*
+ * Read interrupt line and base address registers.
+ * The architecture-dependent code can tweak these, of course.
+ */
+static void pci_read_irq(struct pci_dev *dev)
+{
+	unsigned char irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
+	if (irq)
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+}
+
+/**
+ * pci_setup_device - fill in class and map information of a device
+ * @dev: the device structure to fill
+ *
+ * Initialize the device structure with information about the device's 
+ * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * Called at initialisation of the PCI subsystem and by CardBus services.
+ * Returns 0 on success and -1 if unknown type of device (not normal, bridge
+ * or CardBus).
+ */
+int pci_setup_device(struct pci_dev * dev)
+{
+	u32 class;
+
+	sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+	
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+	class >>= 8;				    /* upper 3 bytes */
+	dev->class = class;
+	class >>= 8;
+
+	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+
+	/* "Unknown power state" */
+	dev->current_state = 4;
+
+	switch (dev->hdr_type) {		    /* header type */
+	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
+		if (class == PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
+		if (class != PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
+		break;
+
+	case PCI_HEADER_TYPE_CARDBUS:		    /* CardBus bridge header */
+		if (class != PCI_CLASS_BRIDGE_CARDBUS)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 1, 0);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	default:				    /* unknown header */
+		printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+			dev->slot_name, dev->hdr_type);
+		return -1;
+
+	bad:
+		printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
+		       dev->slot_name, class, dev->hdr_type);
+		dev->class = PCI_CLASS_NOT_DEFINED;
+	}
+
+	/* We found a fine healthy device, go go go... */
+	return 0;
+}
+
+/*
+ * Read the config data for a PCI device, sanity-check it
+ * and fill in the dev structure...
+ */
+struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
+{
+	struct pci_dev *dev;
+	u32 l;
+
+	if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
+		return NULL;
+
+	/* some broken boards return 0 or ~0 if a slot is empty: */
+	if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
+		return NULL;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	memcpy(dev, temp, sizeof(*dev));
+	dev->vendor = l & 0xffff;
+	dev->device = (l >> 16) & 0xffff;
+
+	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+	   set this higher, assuming the system even supports it.  */
+	dev->dma_mask = 0xffffffff;
+	if (pci_setup_device(dev) < 0) {
+		kfree(dev);
+		return NULL;
+	}
+
+	/* now put in global tree */
+	strcpy(dev->dev.name,dev->name);
+	strcpy(dev->dev.bus_id,dev->slot_name);
+
+	device_register(&dev->dev);
+	return dev;
+}
+
+struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	struct pci_dev *first_dev = NULL;
+	int func = 0;
+	int is_multi = 0;
+	u8 hdr_type;
+
+	for (func = 0; func < 8; func++, temp->devfn++) {
+		if (func && !is_multi)		/* not a multi-function device */
+			continue;
+		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		temp->hdr_type = hdr_type & 0x7f;
+
+		dev = pci_scan_device(temp);
+		if (!dev)
+			continue;
+		pci_name_device(dev);
+		if (!func) {
+			is_multi = hdr_type & 0x80;
+			first_dev = dev;
+		}
+
+		/*
+		 * Link the device to both the global PCI device chain and
+		 * the per-bus list of devices.
+		 */
+		list_add_tail(&dev->global_list, &pci_devices);
+		list_add_tail(&dev->bus_list, &bus->devices);
+
+		/* Fix up broken headers */
+		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+	}
+	return first_dev;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+	unsigned int devfn, max, pass;
+	struct list_head *ln;
+	struct pci_dev *dev, dev0;
+
+	DBG("Scanning bus %02x\n", bus->number);
+	max = bus->secondary;
+
+	/* Create a device template */
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = bus;
+	dev0.sysdata = bus->sysdata;
+	dev0.dev.parent = bus->dev;
+	dev0.dev.driver = &pci_device_driver;
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev0.devfn = devfn;
+		pci_scan_slot(&dev0);
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	DBG("Fixups for bus %02x\n", bus->number);
+	pcibios_fixup_bus(bus);
+	for (pass=0; pass < 2; pass++)
+		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+			dev = pci_dev_b(ln);
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+				max = pci_scan_bridge(bus, dev, max, pass);
+		}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	return max;
+}
+
+int __devinit pci_bus_exists(const struct list_head *list, int nr)
+{
+	const struct list_head *l;
+
+	for(l=list->next; l != list; l = l->next) {
+		const struct pci_bus *b = pci_bus_b(l);
+		if (b->number == nr || pci_bus_exists(&b->children, nr))
+			return 1;
+	}
+	return 0;
+}
+
+struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
+{
+	struct pci_bus *b;
+
+	if (pci_bus_exists(&pci_root_buses, bus)) {
+		/* If we already got to this bus through a different bridge, ignore it */
+		DBG("PCI: Bus %02x already known\n", bus);
+		return NULL;
+	}
+
+	b = pci_alloc_bus();
+	if (!b)
+		return NULL;
+	list_add_tail(&b->node, &pci_root_buses);
+
+	b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
+	memset(b->dev,0,sizeof(*(b->dev)));
+	sprintf(b->dev->bus_id,"pci%d",bus);
+	strcpy(b->dev->name,"Host/PCI Bridge");
+	device_register(b->dev);
+
+	b->number = b->secondary = bus;
+	b->resource[0] = &ioport_resource;
+	b->resource[1] = &iomem_resource;
+	return b;
+}
+
+struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+{
+	struct pci_bus *b = pci_alloc_primary_bus(bus);
+	if (b) {
+		b->sysdata = sysdata;
+		b->ops = ops;
+		b->subordinate = pci_do_scan_bus(b);
+	}
+	return b;
+}
+
+EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_root_buses);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_setup_device);
+EXPORT_SYMBOL(pci_add_new_bus);
+EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL(pci_scan_slot);
+#endif
diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c	Thu May  9 15:21:01 2002
+++ b/drivers/pci/proc.c	Thu May  9 15:21:01 2002
@@ -6,11 +6,10 @@
  *	Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
  */
 
-#include <linux/types.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/smp_lock.h>
 
@@ -615,3 +614,11 @@
 }
 
 __initcall(pci_proc_init);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_detach_device);
+EXPORT_SYMBOL(pci_proc_attach_bus);
+EXPORT_SYMBOL(pci_proc_detach_bus);
+#endif
+
diff -Nru a/drivers/pci/search.c b/drivers/pci/search.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/search.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,110 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI 
+ * device resides and the logical device number within that slot 
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device 
+ * is located in system global list of PCI devices.  If the device
+ * is found, a pointer to its data structure is returned.  If no 
+ * device is found, %NULL is returned.
+ */
+struct pci_dev *
+pci_find_slot(unsigned int bus, unsigned int devfn)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (dev->bus->number == bus && dev->devfn == devfn)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_subsys(unsigned int vendor, unsigned int device,
+		unsigned int ss_vendor, unsigned int ss_device,
+		const struct pci_dev *from)
+{
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
+		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+		    (device == PCI_ANY_ID || dev->device == device) &&
+		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+			return dev;
+		n = n->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+{
+	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+}
+
+
+/**
+ * pci_find_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @class, a pointer to its device structure is
+ * returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
+ */
+struct pci_dev *
+pci_find_class(unsigned int class, const struct pci_dev *from)
+{
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
+		if (dev->class == class)
+			return dev;
+		n = n->next;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(pci_find_class);
+EXPORT_SYMBOL(pci_find_device);
+EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_find_subsys);
diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
--- a/drivers/pci/setup-bus.c	Thu May  9 15:21:06 2002
+++ b/drivers/pci/setup-bus.c	Thu May  9 15:21:06 2002
@@ -11,7 +11,10 @@
 
 /*
  * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
- *	     PCI-PCI bridges cleanup, sorted resource allocation
+ *	     PCI-PCI bridges cleanup, sorted resource allocation.
+ * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ *	     Converted to allocation in 3 passes, which gives
+ *	     tighter packing. Prefetchable range support.
  */
 
 #include <linux/init.h>
@@ -23,7 +26,7 @@
 #include <linux/slab.h>
 
 
-#define DEBUG_CONFIG 0
+#define DEBUG_CONFIG 1
 #if DEBUG_CONFIG
 # define DBGC(args)     printk args
 #else
@@ -33,16 +36,14 @@
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 
 static int __init
-pbus_assign_resources_sorted(struct pci_bus *bus,
-			     struct pbus_set_ranges_data *ranges)
+pbus_assign_resources_sorted(struct pci_bus *bus)
 {
 	struct list_head *ln;
 	struct resource *res;
-	struct resource_list head_io, head_mem, *list, *tmp;
-	unsigned long io_reserved = 0, mem_reserved = 0;
+	struct resource_list head, *list, *tmp;
 	int idx, found_vga = 0;
 
-	head_io.next = head_mem.next = NULL;
+	head.next = NULL;
 	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
 		u16 class = dev->class >> 8;
@@ -64,63 +65,26 @@
 			pci_write_config_word(dev, PCI_COMMAND, cmd);
 		}
 
-		/* Reserve some resources for CardBus.
-		   Are these values reasonable? */
-		if (class == PCI_CLASS_BRIDGE_CARDBUS) {
-			io_reserved += 8*1024;
-			mem_reserved += 32*1024*1024;
-			continue;
-		}
-
-		pdev_sort_resources(dev, &head_io, IORESOURCE_IO);
-		pdev_sort_resources(dev, &head_mem, IORESOURCE_MEM);
+		pdev_sort_resources(dev, &head);
 	}
 
-	for (list = head_io.next; list;) {
+	for (list = head.next; list;) {
 		res = list->res;
 		idx = res - &list->dev->resource[0];
-		if (pci_assign_resource(list->dev, idx) == 0
-		    && ranges->io_end < res->end)
-			ranges->io_end = res->end;
+		pci_assign_resource(list->dev, idx);
 		tmp = list;
 		list = list->next;
 		kfree(tmp);
 	}
-	for (list = head_mem.next; list;) {
-		res = list->res;
-		idx = res - &list->dev->resource[0];
-		if (pci_assign_resource(list->dev, idx) == 0
-		    && ranges->mem_end < res->end)
-			ranges->mem_end = res->end;
-		tmp = list;
-		list = list->next;
-		kfree(tmp);
-	}
-
-	ranges->io_end += io_reserved;
-	ranges->mem_end += mem_reserved;
-
-	/* PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
-	   requires that if there is no I/O ports or memory behind the
-	   bridge, corresponding range must be turned off by writing base
-	   value greater than limit to the bridge's base/limit registers.  */
-#if 1
-	/* But assuming that some hardware designed before 1998 might
-	   not support this (very unlikely - at least all DEC bridges
-	   are ok and I believe that was standard de-facto. -ink), we
-	   must allow for at least one unit.  */
-	if (ranges->io_end == ranges->io_start)
-		ranges->io_end += 1;
-	if (ranges->mem_end == ranges->mem_start)
-		ranges->mem_end += 1;
-#endif
-	ranges->io_end = ROUND_UP(ranges->io_end, 4*1024);
-	ranges->mem_end = ROUND_UP(ranges->mem_end, 1024*1024);
 
 	return found_vga;
 }
 
-/* Initialize bridges with base/limit values we have collected */
+/* Initialize bridges with base/limit values we have collected.
+   PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
+   requires that if there is no I/O ports or memory behind the
+   bridge, corresponding range must be turned off by writing base
+   value greater than limit to the bridge's base/limit registers.  */
 static void __init
 pci_setup_bridge(struct pci_bus *bus)
 {
@@ -130,120 +94,311 @@
 
 	if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
 		return;
+
 	ranges.io_start = bus->resource[0]->start;
 	ranges.io_end = bus->resource[0]->end;
 	ranges.mem_start = bus->resource[1]->start;
 	ranges.mem_end = bus->resource[1]->end;
+	ranges.prefetch_start = bus->resource[2]->start;
+	ranges.prefetch_end = bus->resource[2]->end;
 	pcibios_fixup_pbus_ranges(bus, &ranges);
 
-	DBGC((KERN_ERR "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name));
-	DBGC((KERN_ERR "  IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end));
-	DBGC((KERN_ERR "  MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end));
+	DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
+			bus->number, bridge->name));
 
 	/* Set up the top and bottom of the PCI I/O segment for this bus. */
-	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
-	l &= 0xffff0000;
-	l |= (ranges.io_start >> 8) & 0x00f0;
-	l |= ranges.io_end & 0xf000;
+	if (bus->resource[0]->flags & IORESOURCE_IO) {
+		pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+		l &= 0xffff0000;
+		l |= (ranges.io_start >> 8) & 0x00f0;
+		l |= ranges.io_end & 0xf000;
+		/* Set up upper 16 bits of I/O base/limit. */
+		pci_write_config_word(bridge, PCI_IO_BASE_UPPER16,
+				      ranges.io_start >> 16);
+		pci_write_config_word(bridge, PCI_IO_LIMIT_UPPER16,
+				      ranges.io_end >> 16);
+		DBGC((KERN_INFO "  IO window: %04lx-%04lx\n",
+				ranges.io_start, ranges.io_end));
+	}
+	else {
+		/* Clear upper 16 bits of I/O base/limit. */
+		pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+		l = 0x00f0;
+		DBGC((KERN_INFO "  IO window: disabled.\n"));
+	}
 	pci_write_config_dword(bridge, PCI_IO_BASE, l);
 
-	/* Clear upper 16 bits of I/O base/limit. */
-	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	if (bus->resource[1]->flags & IORESOURCE_MEM) {
+		l = (ranges.mem_start >> 16) & 0xfff0;
+		l |= ranges.mem_end & 0xfff00000;
+		DBGC((KERN_INFO "  MEM window: %08lx-%08lx\n",
+				ranges.mem_start, ranges.mem_end));
+	}
+	else {
+		l = 0x0000fff0;
+		DBGC((KERN_INFO "  MEM window: disabled.\n"));
+	}
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 
 	/* Clear out the upper 32 bits of PREF base/limit. */
 	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
 	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
-	/* Set up the top and bottom of the PCI Memory segment
-	   for this bus. */
-	l = (ranges.mem_start >> 16) & 0xfff0;
-	l |= ranges.mem_end & 0xfff00000;
-	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
 	/* Set up PREF base/limit. */
-	l = (bus->resource[2]->start >> 16) & 0xfff0;
-	l |= bus->resource[2]->end & 0xfff00000;
+	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+		l = (ranges.prefetch_start >> 16) & 0xfff0;
+		l |= ranges.prefetch_end & 0xfff00000;
+		DBGC((KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
+				ranges.prefetch_start, ranges.prefetch_end));
+	}
+	else {
+		l = 0x0000fff0;
+		DBGC((KERN_INFO "  PREFETCH window: disabled.\n"));
+	}
 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
 	/* Check if we have VGA behind the bridge.
-	   Enable ISA in either case. */
+	   Enable ISA in either case (FIXME!). */
 	l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
 }
 
+/* Check whether the bridge supports optional I/O and
+   prefetchable memory ranges. If not, the respective
+   base/limit registers must be read-only and read as 0. */
 static void __init
-pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+pci_bridge_check_ranges(struct pci_bus *bus)
+{
+	u16 io;
+	u32 pmem;
+	struct pci_dev *bridge = bus->self;
+	struct resource *b_res;
+
+	if (!bridge || (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+		return;
+
+	b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+	b_res[1].flags |= IORESOURCE_MEM;
+
+	pci_read_config_word(bridge, PCI_IO_BASE, &io);
+	if (!io) {
+		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
+		pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ 		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+ 	}
+ 	if (io)
+		b_res[0].flags |= IORESOURCE_IO;
+	/*  DECchip 21050 pass 2 errata: the bridge may miss an address
+	    disconnect boundary by one PCI data phase.
+	    Workaround: do not use prefetching on this device. */
+	if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
+		return;
+	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+	if (!pmem) {
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
+					       0xfff0fff0);
+		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
+	}
+	if (pmem)
+		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+}
+
+/* Sizing the IO windows of the PCI-PCI bridge is trivial,
+   since these windows have 4K granularity and the IO ranges
+   of non-bridge PCI devices are limited to 256 bytes.
+   We must be careful with the ISA aliasing though. */
+static void __init
+pbus_size_io(struct pci_bus *bus)
 {
 	struct list_head *ln;
-	int found_vga = pbus_assign_resources_sorted(bus, ranges);
+	struct resource *b_res = bus->resource[0];
+	unsigned long size = 0, size1 = 0;
 
-	if (!ranges->found_vga && found_vga) {
-		struct pci_bus *b;
+	if (!(b_res->flags & IORESOURCE_IO))
+		return;
 
-		ranges->found_vga = 1;
-		/* Propogate presence of the VGA to upstream bridges */
-		for (b = bus; b->parent; b = b->parent) {
-#if 0
-			/* ? Do we actually need to enable PF memory? */
-			b->resource[2]->start = 0;
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		int i;
+		
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if (!(r->flags & IORESOURCE_IO))
+				continue;
+			if (r->parent)
+				BUG();
+			r_size = r->end - r->start + 1;
+
+			if (r_size < 0x400)
+				/* Might be re-aligned for ISA */
+				size += r_size;
+			else
+				size1 += r_size;
+		}
+		/* ??? Reserve some resources for CardBus. */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS)
+			size1 += 4*1024;
+	}
+/* To be fixed in 2.5: we should have sort of HAVE_ISA
+   flag in the struct pci_bus. */
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+	size = (size & 0xff) + ((size & ~0xffUL) << 2);
 #endif
-			b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
+	size = ROUND_UP(size + size1, 4096);
+	if (!size) {
+		b_res->flags = 0;
+		return;
+	}
+	/* Alignment of the IO window is always 4K */
+	b_res->start = 4096;
+	b_res->end = b_res->start + size - 1;
+}
+
+/* Calculate the size of the bus and minimal alignment which
+   guarantees that all child resources fit in this size. */
+static void __init
+pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+{
+	struct list_head *ln;
+	unsigned long min_align, align, size;
+	unsigned long aligns[12];	/* Alignments from 1Mb to 2Gb */
+	int order, max_order;
+	struct resource *b_res = (type & IORESOURCE_PREFETCH) ?
+				 bus->resource[2] : bus->resource[1];
+
+	memset(aligns, 0, sizeof(aligns));
+	max_order = 0;
+	size = 0;
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		int i;
+		
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if ((r->flags & mask) != type)
+				continue;
+			if (r->parent)
+				BUG();
+			r_size = r->end - r->start + 1;
+			/* For bridges size != alignment */
+			align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+			order = __ffs(align) - 20;
+			if (order > 11) {
+				printk(KERN_WARNING "PCI: region %s/%d "
+				       "too large: %lx-%lx\n",
+				       dev->slot_name, i, r->start, r->end);
+				r->flags = 0;
+				continue;
+			}
+			size += r_size;
+			if (order < 0)
+				order = 0;
+			/* Exclude ranges with size > align from
+			   calculation of the alignment. */
+			if (size == align)
+				aligns[order] += align;
+			if (order > max_order)
+				max_order = order;
+		}
+		/* ??? Reserve some resources for CardBus. */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+			size += 1UL << 24;		/* 16 Mb */
+			aligns[24 - 20] += 1UL << 24;
 		}
 	}
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
-		struct pci_bus *b = pci_bus_b(ln);
 
-		b->resource[0]->start = ranges->io_start = ranges->io_end;
-		b->resource[1]->start = ranges->mem_start = ranges->mem_end;
+	align = 0;
+	min_align = 0;
+	for (order = 0; order <= max_order; order++) {
+		unsigned long align1 = 1UL << (order + 20);
+
+		if (!align)
+			min_align = align1;
+		else if (ROUND_UP(align + min_align, min_align) < align1)
+			min_align = align1 >> 1;
+		align += aligns[order];
+	}
+	size = ROUND_UP(size, min_align);
+	if (!size) {
+		b_res->flags = 0;
+		return;
+	}
+	b_res->start = min_align;
+	b_res->end = size + min_align - 1;
+}
+
+void __init
+pbus_size_bridges(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	unsigned long mask, type;
 
-		pbus_assign_resources(b, ranges);
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+		pbus_size_bridges(pci_bus_b(ln));
 
-		b->resource[0]->end = ranges->io_end - 1;
-		b->resource[1]->end = ranges->mem_end - 1;
+	/* The root bus? */
+	if (!bus->self)
+		return;
 
-		pci_setup_bridge(b);
+	pci_bridge_check_ranges(bus);
+
+	pbus_size_io(bus);
+
+	mask = type = IORESOURCE_MEM;
+	/* If the bridge supports prefetchable range, size it separately. */
+	if (bus->resource[2] &&
+	    bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+		pbus_size_mem(bus, IORESOURCE_PREFETCH, IORESOURCE_PREFETCH);
+		mask |= IORESOURCE_PREFETCH;	/* Size non-prefetch only. */
 	}
+	pbus_size_mem(bus, mask, type);
 }
 
 void __init
-pci_assign_unassigned_resources(void)
+pbus_assign_resources(struct pci_bus *bus)
 {
-	struct pbus_set_ranges_data ranges;
 	struct list_head *ln;
-	struct pci_dev *dev;
+	int found_vga = pbus_assign_resources_sorted(bus);
 
-	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
-		struct pci_bus *b = pci_bus_b(ln);
+	if (found_vga) {
+		struct pci_bus *b;
 
-		ranges.io_start = b->resource[0]->start + PCIBIOS_MIN_IO;
-		ranges.mem_start = b->resource[1]->start + PCIBIOS_MIN_MEM;
-		ranges.io_end = ranges.io_start;
-		ranges.mem_end = ranges.mem_start;
-		ranges.found_vga = 0;
-		pbus_assign_resources(b, &ranges);
+		/* Propagate presence of the VGA to upstream bridges */
+		for (b = bus; b->parent; b = b->parent) {
+			b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
+		}
 	}
-	pci_for_each_dev(dev) {
-		pdev_enable_device(dev);
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+
+		pbus_assign_resources(b);
+		pci_setup_bridge(b);
 	}
 }
 
-/* Check whether the bridge supports I/O forwarding.
-   If not, its I/O base/limit register must be
-   read-only and read as 0. */
-unsigned long __init
-pci_bridge_check_io(struct pci_dev *bridge)
+void __init
+pci_assign_unassigned_resources(void)
 {
-	u16 io;
+	struct list_head *ln;
+	struct pci_dev *dev;
 
-	pci_read_config_word(bridge, PCI_IO_BASE, &io);
-	if (!io) {
-		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
-		pci_read_config_word(bridge, PCI_IO_BASE, &io);
-		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+	/* Depth first, calculate sizes and alignments of all
+	   subordinate buses. */
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+		pbus_size_bridges(pci_bus_b(ln));
+	/* Depth last, allocate resources and update the hardware. */
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+		pbus_assign_resources(pci_bus_b(ln));
+
+	pci_for_each_dev(dev) {
+		pdev_enable_device(dev);
 	}
-	if (io)
-		return IORESOURCE_IO;
-	printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n",
-				bridge->name);
-	return 0;
 }
diff -Nru a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
--- a/drivers/pci/setup-res.c	Thu May  9 15:21:05 2002
+++ b/drivers/pci/setup-res.c	Thu May  9 15:21:05 2002
@@ -69,6 +69,7 @@
 	unsigned int type_mask,
 	int resno)
 {
+	unsigned long align;
 	int i;
 
 	type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
@@ -81,12 +82,20 @@
 		if ((res->flags ^ r->flags) & type_mask)
 			continue;
 
-		/* We cannot allocate a non-prefetching resource from a pre-fetching area */
-		if ((r->flags & IORESOURCE_PREFETCH) && !(res->flags & IORESOURCE_PREFETCH))
+		/* We cannot allocate a non-prefetching resource
+		   from a pre-fetching area */
+		if ((r->flags & IORESOURCE_PREFETCH) &&
+		    !(res->flags & IORESOURCE_PREFETCH))
 			continue;
 
+		/* The bridge resources are special, as their
+		   size != alignment. Sizing routines return
+		   required alignment in the "start" field. */
+		align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
+
 		/* Ok, try it out.. */
-		if (allocate_resource(r, res, size, min, -1, size, pcibios_align_resource, dev) < 0)
+		if (allocate_resource(r, res, size, min, -1, align,
+				      pcibios_align_resource, dev) < 0)
 			continue;
 
 		/* Update PCI config space.  */
@@ -127,47 +136,45 @@
 	return 0;
 }
 
-/* Sort resources of a given type by alignment */
+/* Sort resources by alignment */
 void __init
-pdev_sort_resources(struct pci_dev *dev,
-		    struct resource_list *head, u32 type_mask)
+pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 {
 	int i;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		struct resource *r;
 		struct resource_list *list, *tmp;
-		unsigned long r_size;
-
-		/* PCI-PCI bridges may have I/O ports or
-		   memory on the primary bus */
-		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI &&
-						i >= PCI_BRIDGE_RESOURCES)
-			continue;
+		unsigned long r_align;
 
 		r = &dev->resource[i];
-		r_size = r->end - r->start;
+		r_align = r->end - r->start;
 		
-		if (!(r->flags & type_mask) || r->parent)
+		if (!(r->flags) || r->parent)
 			continue;
-		if (!r_size) {
+		if (!r_align) {
 			printk(KERN_WARNING "PCI: Ignore bogus resource %d "
-					 "[%lx:%lx] of %s\n",
-					  i, r->start, r->end, dev->name);
+					    "[%lx:%lx] of %s\n",
+					    i, r->start, r->end, dev->name);
 			continue;
 		}
+		r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
 		for (list = head; ; list = list->next) {
-			unsigned long size = 0;
+			unsigned long align = 0;
 			struct resource_list *ln = list->next;
+			int idx;
 
-			if (ln)
-				size = ln->res->end - ln->res->start;
-			if (r_size > size) {
+			if (ln) {
+				idx = ln->res - &ln->dev->resource[0];
+				align = (idx < PCI_BRIDGE_RESOURCES) ?
+					ln->res->end - ln->res->start + 1 :
+					ln->res->start;
+			}
+			if (r_align > align) {
 				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-				if (!tmp) {
-					printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n");
-					continue;
-				}
+				if (!tmp)
+					panic("pdev_sort_resources(): "
+					      "kmalloc() failed!\n");
 				tmp->next = ln;
 				tmp->res = r;
 				tmp->dev = dev;
diff -Nru a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
--- a/drivers/pcmcia/Config.in	Thu May  9 15:21:07 2002
+++ b/drivers/pcmcia/Config.in	Thu May  9 15:21:07 2002
@@ -7,25 +7,20 @@
 mainmenu_option next_comment
 comment 'PCMCIA/CardBus support'
 
-#dep_tristate 'CardBus support' CONFIG_PCMCIA $CONFIG_PCI
-#if [ "$CONFIG_PCMCIA" != "n" ]; then
-#  define_bool CONFIG_CARDBUS y
-#fi
-
 tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
 if [ "$CONFIG_PCMCIA" != "n" ]; then
    if [ "$CONFIG_PCI" != "n" ]; then
       bool '  CardBus support' CONFIG_CARDBUS
    fi
-   dep_bool '  i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI
-   bool '  i82365 compatible bridge support' CONFIG_I82365
-   bool '  Databook TCIC host bridge support' CONFIG_TCIC
+   dep_tristate '  i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCMCIA $CONFIG_PCI
+   dep_tristate '  i82365 compatible bridge support' CONFIG_I82365 $CONFIG_PCMCIA
+   dep_tristate '  Databook TCIC host bridge support' CONFIG_TCIC $CONFIG_PCMCIA
    if [ "$CONFIG_HD64465" = "y" ]; then
       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
    fi
-fi
-if [ "$CONFIG_ARM" = "y" ]; then
-   dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+   if [ "$CONFIG_ARM" = "y" ]; then
+      dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+   fi
 fi
 
 endmenu
diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
--- a/drivers/pcmcia/Makefile	Thu May  9 15:21:04 2002
+++ b/drivers/pcmcia/Makefile	Thu May  9 15:21:04 2002
@@ -6,52 +6,22 @@
 
 export-objs := ds.o cs.o yenta.o pci_socket.o
 
-yenta_socket-objs := pci_socket.o yenta.o
-pcmcia_core-objs := cistpl.o rsrc_mgr.o bulkmem.o cs.o
-
+obj-$(CONFIG_PCMCIA)			+= pcmcia_core.o ds.o
 ifeq ($(CONFIG_CARDBUS),y)
-  pcmcia_core-objs += cardbus.o
+  obj-$(CONFIG_PCMCIA) 			+= yenta_socket.o
 endif
 
-ifeq ($(CONFIG_PCMCIA),y)
-  obj-y   := cistpl.o rsrc_mgr.o bulkmem.o ds.o cs.o
-  ifeq ($(CONFIG_CARDBUS),y)
-    obj-y += cardbus.o yenta.o pci_socket.o
-  endif
-  ifeq ($(CONFIG_I82365),y)
-    obj-y += i82365.o
-  endif
-  ifeq ($(CONFIG_I82092),y)
-    obj-y += i82092.o
-  endif
-  ifeq ($(CONFIG_TCIC),y)
-    obj-y += tcic.o
-  endif
-  ifeq ($(CONFIG_HD64465_PCMCIA),y)
-    obj-y += hd64465_ss.o
-  endif
-else
-  ifeq ($(CONFIG_PCMCIA),m)
-    obj-m   := pcmcia_core.o ds.o
-    ifeq ($(CONFIG_I82365),y)
-      obj-m += i82365.o
-    endif
-    ifeq ($(CONFIG_I82092),y)
-      obj-m += i82092.o
-    endif
-    ifeq ($(CONFIG_TCIC),y)
-      obj-m += tcic.o
-    endif
-    ifeq ($(CONFIG_HD64465_PCMCIA),m)
-      obj-m += hd64465_ss.o
-    endif
-     ifeq ($(CONFIG_CARDBUS),y)
-	obj-m += yenta_socket.o
-     endif
-  endif
-endif
+obj-$(CONFIG_I82365)			+= i82365.o
+obj-$(CONFIG_I82092)			+= i82092.o
+obj-$(CONFIG_TCIC)			+= tcic.o
+obj-$(CONFIG_HD64465_PCMCIA)		+= hd64465_ss.o
+obj-$(CONFIG_PCMCIA_SA1100)		+= sa1100_cs.o
+
+yenta_socket-objs				:= pci_socket.o yenta.o
 
-obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
+pcmcia_core-objs-y				:= cistpl.o rsrc_mgr.o bulkmem.o cs.o
+pcmcia_core-objs-$(CONFIG_CARDBUS)		+= cardbus.o
+pcmcia_core-objs				:= $(pcmcia_core-objs-y)
 
 sa1100_cs-objs-y				:= sa1100_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
@@ -74,5 +44,6 @@
 sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) 	+= sa1100_trizeps.o
 sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
+sa1100_cs-objs					:= $(sa11000_cs-objs-y)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c	Thu May  9 15:21:09 2002
+++ b/drivers/pcmcia/ds.c	Thu May  9 15:21:09 2002
@@ -830,7 +830,7 @@
 	err = unbind_request(i, &buf.bind_info);
 	break;
     case DS_BIND_MTD:
-	if (!suser()) return -EPERM;
+	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
 	err = bind_mtd(i, &buf.mtd_info);
 	break;
     default:
diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c
--- a/drivers/s390/char/tubtty.c	Thu May  9 15:21:09 2002
+++ b/drivers/s390/char/tubtty.c	Thu May  9 15:21:09 2002
@@ -561,7 +561,7 @@
 	/*
 	 * Superuser-mode settings affect the driver overall ---
 	 */
-	if (!suser()) {
+	if (!capable(CAP_SYS_TTY_CONFIG)) {
 		return -EPERM;
 	} else if (strncmp(mybuf, "index=", 6) == 0) {
 		tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0);
diff -Nru a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
--- a/drivers/scsi/53c7xx.c	Thu May  9 15:21:07 2002
+++ b/drivers/scsi/53c7xx.c	Thu May  9 15:21:07 2002
@@ -1119,8 +1119,9 @@
  */
 
 int 
-ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, 
-    u32 base, int io_port, int irq, int dma, long long options, int clock)
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+    unsigned long base, int io_port, int irq, int dma, 
+    long long options, int clock)
 {
     struct Scsi_Host *instance;
     struct NCR53c7x0_hostdata *hostdata;
@@ -1224,7 +1225,7 @@
     memset((void *)instance->hostdata[0], 0, 8192);
     cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
     cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
-    kernel_set_cachemode(instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
+    kernel_set_cachemode((void *)instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
 
     /* FIXME : if we ever support an ISA NCR53c7xx based board, we
        need to check if the chip is running in a 16 bit mode, and if so 
@@ -1251,7 +1252,7 @@
      */
 
     if (base) {
-	instance->base = (unsigned char *) (unsigned long) base;
+	instance->base = base;
 	/* Check for forced I/O mapping */
     	if (!(options & OPTION_IO_MAPPED)) {
 	    options |= OPTION_MEMORY_MAPPED;
@@ -1423,7 +1424,7 @@
     	memory_to_ncr = tmp|DMODE_800_DIOM;
     	ncr_to_memory = tmp|DMODE_800_SIOM;
     } else {
-    	base = virt_to_bus(host->base);
+    	base = virt_to_bus((void *)host->base);
 	memory_to_ncr = ncr_to_memory = tmp;
     }
 
@@ -3049,7 +3050,7 @@
     /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
      * XXX may be invalid (CONFIG_060_WRITETHROUGH)
      */
-    kernel_set_cachemode((u32)addr, 4096, IOMAP_FULL_CACHING);
+    kernel_set_cachemode((void *)addr, 4096, IOMAP_FULL_CACHING);
     free_page ((u32)addr);
 }
 
@@ -3107,7 +3108,7 @@
         memset((void *)real, 0, 4096);
         cache_push(virt_to_phys((void *)real), 4096);
         cache_clear(virt_to_phys((void *)real), 4096);
-        kernel_set_cachemode(real, 4096, IOMAP_NOCACHE_SER);
+        kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
 	tmp = ROUNDUP(real, void *);
 #ifdef FORCE_DSA_ALIGNMENT
 	{
@@ -6114,7 +6115,7 @@
     /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
      * XXX may be invalid (CONFIG_060_WRITETHROUGH)
      */
-    kernel_set_cachemode((u32)hostdata, 8192, IOMAP_FULL_CACHING);
+    kernel_set_cachemode((void *)hostdata, 8192, IOMAP_FULL_CACHING);
     free_pages ((u32)hostdata, 1);
     return 1;
 }
diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
--- a/drivers/scsi/NCR53C9x.c	Thu May  9 15:21:04 2002
+++ b/drivers/scsi/NCR53C9x.c	Thu May  9 15:21:04 2002
@@ -927,7 +927,7 @@
 			esp->dma_mmu_get_scsi_sgl(esp, sp);
 		else
 			sp->SCp.ptr =
-				(char *) virt_to_phys(sp->SCp.buffer->address);
+				(char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
 	}
 }
 
@@ -1748,7 +1748,8 @@
 	if (esp->dma_advance_sg)
 		esp->dma_advance_sg (sp);
 	else
-		sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
+		sp->SCp.ptr = (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+
 }
 
 /* Please note that the way I've coded these routines is that I _always_
diff -Nru a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
--- a/drivers/scsi/a2091.c	Thu May  9 15:21:01 2002
+++ b/drivers/scsi/a2091.c	Thu May  9 15:21:01 2002
@@ -40,9 +40,9 @@
 		continue;
 
 	if (status & ISTR_INTS) {
-		spin_lock_irqsave(instance->host_lock, flags);
+		spin_lock_irqsave(&instance->host_lock, flags);
 		wd33c93_intr (instance);
-		spin_unlock_irqrestore(instance->host_lock, flags);
+		spin_unlock_irqrestore(&instance->host_lock, flags);
 	}
     }
 }
@@ -60,7 +60,7 @@
 	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
 	    & ~0x1ff;
 	HDATA(instance)->dma_bounce_buffer =
-	    scsi_malloc (HDATA(instance)->dma_bounce_len);
+	    kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL);
 	
 	/* can't allocate memory; use PIO */
 	if (!HDATA(instance)->dma_bounce_buffer) {
@@ -74,8 +74,7 @@
 	/* the bounce buffer may not be in the first 16M of physmem */
 	if (addr & A2091_XFER_MASK) {
 	    /* we could use chipmem... maybe later */
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	    return 1;
@@ -162,8 +161,7 @@
 		memcpy (SCpnt->SCp.ptr, 
 			HDATA(instance)->dma_bounce_buffer,
 			SCpnt->SCp.this_residual);
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	    
@@ -174,8 +172,7 @@
 			HDATA(instance)->dma_bounce_buffer,
 			SCpnt->request_bufflen);
 
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	}
diff -Nru a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
--- a/drivers/scsi/a3000.c	Thu May  9 15:21:09 2002
+++ b/drivers/scsi/a3000.c	Thu May  9 15:21:09 2002
@@ -30,15 +30,14 @@
 {
 	unsigned long flags;
 	unsigned int status = DMA(a3000_host)->ISTR;
-	struct Scsi_Host *dev = dummy;
-	
+
 	if (!(status & ISTR_INT_P))
 		return;
 	if (status & ISTR_INTS)
 	{
-		spin_lock_irqsave(dev->host_lock, flags);
+		spin_lock_irqsave(&a3000_host->host_lock, flags);
 		wd33c93_intr (a3000_host);
-		spin_unlock_irqrestore(dev->host_lock, flags);
+		spin_unlock_irqrestore(&a3000_host->host_lock, flags);
 	} else
 		printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n",
 		       status);
@@ -61,7 +60,7 @@
 	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
 	    & ~0x1ff;
 	HDATA(a3000_host)->dma_bounce_buffer =
-	    scsi_malloc (HDATA(a3000_host)->dma_bounce_len);
+	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
 	
 	/* can't allocate memory; use PIO */
 	if (!HDATA(a3000_host)->dma_bounce_buffer) {
@@ -152,8 +151,7 @@
 		memcpy (SCpnt->SCp.ptr,
 			HDATA(instance)->dma_bounce_buffer,
 			SCpnt->SCp.this_residual);
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	} else {
@@ -162,8 +160,7 @@
 			HDATA(instance)->dma_bounce_buffer,
 			SCpnt->request_bufflen);
 
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	}
@@ -200,9 +197,7 @@
     return 1;
 
 fail_irq:
-#ifdef MODULE
     wd33c93_release();
-#endif /* MODULE */
     scsi_unregister(a3000_host);
 fail_register:
     release_mem_region(0xDD0000, 256);
@@ -217,11 +212,11 @@
 
 int __exit a3000_release(struct Scsi_Host *instance)
 {
-#ifdef MODULE
     wd33c93_release();
-#endif /* MODULE*/
     DMA(instance)->CNTR = 0;
     release_mem_region(0xDD0000, 256);
     free_irq(IRQ_AMIGA_PORTS, a3000_intr);
     return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
--- a/drivers/scsi/aha1542.c	Thu May  9 15:21:00 2002
+++ b/drivers/scsi/aha1542.c	Thu May  9 15:21:00 2002
@@ -168,6 +168,7 @@
 
 static struct Scsi_Host *aha_host[7];	/* One for each IRQ level (9-15) */
 
+static spinlock_t aha1542_lock = SPIN_LOCK_UNLOCKED;
 
 
 
@@ -218,31 +219,34 @@
 static int aha1542_out(unsigned int base, unchar * cmdp, int len)
 {
 	unsigned long flags = 0;
+	int got_lock;
 
-	save_flags(flags);
 	if (len == 1) {
+		got_lock = 0;
 		while (1 == 1) {
 			WAIT(STATUS(base), CDF, 0, CDF);
-			cli();
+			spin_lock_irqsave(&aha1542_lock, flags);
 			if (inb(STATUS(base)) & CDF) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&aha1542_lock, flags);
 				continue;
 			}
 			outb(*cmdp, DATA(base));
-			restore_flags(flags);
+			spin_unlock_irqrestore(&aha1542_lock, flags);
 			return 0;
 		}
 	} else {
-		cli();
+		spin_lock_irqsave(&aha1542_lock, flags);
+		got_lock = 1;
 		while (len--) {
 			WAIT(STATUS(base), CDF, 0, CDF);
 			outb(*cmdp++, DATA(base));
 		}
-		restore_flags(flags);
+		spin_unlock_irqrestore(&aha1542_lock, flags);
 	}
 	return 0;
 fail:
-	restore_flags(flags);
+	if (got_lock)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
 	printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
 	aha1542_stat();
 	return 1;
@@ -255,16 +259,15 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&aha1542_lock, flags);
 	while (len--) {
 		WAIT(STATUS(base), DF, DF, 0);
 		*cmdp++ = inb(DATA(base));
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 	return 0;
 fail:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 	printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
 	aha1542_stat();
 	return 1;
@@ -277,16 +280,15 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&aha1542_lock, flags);
 	while (len--) {
 		WAITd(STATUS(base), DF, DF, 0, 100);
 		*cmdp++ = inb(DATA(base));
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 	return 0;
 fail:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 	return 1;
 }
 
@@ -484,8 +486,7 @@
 		}
 		aha1542_intr_reset(shost->io_port);
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&aha1542_lock, flags);
 		mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
 		if (mbi >= 2 * AHA1542_MAILBOXES)
 			mbi = AHA1542_MAILBOXES;
@@ -499,7 +500,7 @@
 		} while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
 
 		if (mb[mbi].status == 0) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&aha1542_lock, flags);
 			/* Hmm, no mail.  Must have read it the last time around */
 			if (!number_serviced && !needs_restart)
 				printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
@@ -514,7 +515,7 @@
 		mbistatus = mb[mbi].status;
 		mb[mbi].status = 0;
 		HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&aha1542_lock, flags);
 
 #ifdef DEBUG
 		{
@@ -653,8 +654,7 @@
 	/* Use the outgoing mailboxes in a round-robin fashion, because this
 	   is how the host adapter will scan for them */
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&aha1542_lock, flags);
 	mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
 	if (mbo >= AHA1542_MAILBOXES)
 		mbo = 0;
@@ -674,7 +674,7 @@
 							   screwing with this cdb. */
 
 	HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
@@ -1179,12 +1179,14 @@
 		}
 	}
 	for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++)
-		if (bases[indx] != 0 && !check_region(bases[indx], 4)) {
+		if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) {
 			shpnt = scsi_register(tpnt,
 					sizeof(struct aha1542_hostdata));
 
-			if(shpnt==NULL)
+			if(shpnt==NULL) {
+				release_region(bases[indx], 4);
 				continue;
+			}
 			/* For now we do this - until kmalloc is more intelligent
 			   we are resigned to stupid hacks like this */
 			if (SCSI_BUF_PA(shpnt) >= ISA_DMA_THRESHOLD) {
@@ -1242,18 +1244,17 @@
 			DEB(aha1542_stat());
 
 			DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&aha1542_lock, flags);
 			if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
 				printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
-				restore_flags(flags);
+				spin_unlock_irqrestore(&aha1542_lock, flags);
 				goto unregister;
 			}
 			if (dma_chan != 0xFF) {
 				if (request_dma(dma_chan, "aha1542")) {
 					printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
 					free_irq(irq_level, NULL);
-					restore_flags(flags);
+					spin_unlock_irqrestore(&aha1542_lock, flags);
 					goto unregister;
 				}
 				if (dma_chan == 0 || dma_chan >= 5) {
@@ -1274,7 +1275,7 @@
 			HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1);
 			HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
 			memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
-			restore_flags(flags);
+			spin_unlock_irqrestore(&aha1542_lock, flags);
 #if 0
 			DEB(printk(" *** READ CAPACITY ***\n"));
 
@@ -1308,10 +1309,10 @@
 				aha1542_command(0, cmd, buffer, 512);
 			}
 #endif
-			request_region(bases[indx], 4, "aha1542");	/* Register the IO ports that we use */
 			count++;
 			continue;
 unregister:
+			release_region(bases[indx], 4);
 			scsi_unregister(shpnt);
 			continue;
 
@@ -1376,8 +1377,7 @@
 	ccb = HOSTDATA(SCpnt->host)->ccb;
 	mb = HOSTDATA(SCpnt->host)->mb;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&aha1542_lock, flags);
 	mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
 	if (mbo >= AHA1542_MAILBOXES)
 		mbo = 0;
@@ -1398,7 +1398,7 @@
 							   screwing with this cdb. */
 
 	HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 
 	any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo]));	/* This gets trashed for some reason */
 
@@ -1590,6 +1590,7 @@
 	return FAILED;
 }
 
+#if 0
 /*
  * These are the old error handling routines.  They are only temporarily
  * here while we play with the new error handling code.
@@ -1606,8 +1607,7 @@
 	       inb(STATUS(SCpnt->host->io_port)),
 	       inb(INTRFLAGS(SCpnt->host->io_port)));
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&aha1542_lock, flags);
 	mb = HOSTDATA(SCpnt->host)->mb;
 	mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
 	if (mbi >= 2 * AHA1542_MAILBOXES)
@@ -1620,7 +1620,7 @@
 		if (mbi >= 2 * AHA1542_MAILBOXES)
 			mbi = AHA1542_MAILBOXES;
 	} while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
 
 	if (mb[mbi].status) {
 		printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
@@ -1648,15 +1648,17 @@
 
 	DEB(printk("aha1542_abort\n"));
 #if 0
-	save_flags(flags);
-	cli();
-	for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
+	spin_lock_irqsave(&aha1542_lock, flags);
+	for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) {
 		if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
 			mb[mbo].status = 2;	/* Abort command */
 			aha1542_out(SCpnt->host->io_port, &ahacmd, 1);	/* start scsi command */
-			restore_flags(flags);
+			spin_unlock_irqrestore(&aha1542_lock, flags);
 			break;
-		};
+		}
+	}
+	if (AHA1542_MAILBOXES == mbo)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
 #endif
 	return SCSI_ABORT_SNOOZE;
 }
@@ -1777,6 +1779,7 @@
 	   to request sense information in order to decide what to do next. */
 	return SCSI_RESET_PUNT;
 }
+#endif    /* end of big comment block around old_abort + old_reset */
 
 #include "sd.h"
 
diff -Nru a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
--- a/drivers/scsi/aha1542.h	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/aha1542.h	Thu May  9 15:21:02 2002
@@ -137,8 +137,10 @@
 static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
 static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
 static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
+#if 0
 static int aha1542_old_abort(Scsi_Cmnd * SCpnt);
 static int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
 static int aha1542_biosparam(Disk *, kdev_t, int*);
 
 #define AHA1542_MAILBOXES 8
@@ -154,8 +156,6 @@
 		     detect:			aha1542_detect,		\
 		     command:			aha1542_command,	\
 		     queuecommand:		aha1542_queuecommand,	\
-                     abort:		        aha1542_old_abort,	\
-                     reset:			aha1542_old_reset,	\
 		     eh_abort_handler:		aha1542_abort,		\
 		     eh_device_reset_handler:	aha1542_dev_reset,	\
 		     eh_bus_reset_handler:	aha1542_bus_reset,	\
diff -Nru a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
--- a/drivers/scsi/amiga7xx.c	Thu May  9 15:21:05 2002
+++ b/drivers/scsi/amiga7xx.c	Thu May  9 15:21:05 2002
@@ -31,7 +31,7 @@
 #include<linux/stat.h>
 
 extern int ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, 
-			   u32 base, int io_port, int irq, int dma,
+			   unsigned long base, int io_port, int irq, int dma,
 			   long long options, int clock);
 
 int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
diff -Nru a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
--- a/drivers/scsi/atari_NCR5380.c	Thu May  9 15:21:08 2002
+++ b/drivers/scsi/atari_NCR5380.c	Thu May  9 15:21:08 2002
@@ -644,10 +644,7 @@
 
 static volatile int main_running = 0;
 static struct tq_struct NCR5380_tqueue = {
-    NULL,		/* next */
-    0,			/* sync */
-    (void (*)(void*))NCR5380_main,  /* routine, must have (void *) arg... */
-    NULL		/* data */
+    routine:	(void (*)(void*))NCR5380_main	/* must have (void *) arg... */
 };
 
 static __inline__ void queue_main(void)
diff -Nru a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
--- a/drivers/scsi/atari_scsi.c	Thu May  9 15:21:07 2002
+++ b/drivers/scsi/atari_scsi.c	Thu May  9 15:21:07 2002
@@ -1144,3 +1144,5 @@
 
 static Scsi_Host_Template driver_template = ATARI_SCSI;
 #include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
--- a/drivers/scsi/blz1230.c	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/blz1230.c	Thu May  9 15:21:02 2002
@@ -296,3 +296,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
--- a/drivers/scsi/blz2060.c	Thu May  9 15:21:06 2002
+++ b/drivers/scsi/blz2060.c	Thu May  9 15:21:06 2002
@@ -254,3 +254,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
--- a/drivers/scsi/bvme6000.c	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/bvme6000.c	Thu May  9 15:21:02 2002
@@ -24,7 +24,7 @@
 #include<linux/stat.h>
 
 extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
-			u32 base, int io_port, int irq, int dma,
+			unsigned long base, int io_port, int irq, int dma,
 			long long options, int clock);
 
 int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
@@ -44,7 +44,7 @@
 
     clock = 40000000;	/* 66MHz SCSI Clock */
 
-    ncr53c7xx_init(tpnt, 0, 710, (u32)BVME_NCR53C710_BASE,
+    ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
 			0, BVME_IRQ_SCSI, DMA_NONE,
 			options, clock);
     called = 1;
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/cpqfcTSinit.c	Thu May  9 15:21:02 2002
@@ -532,7 +532,7 @@
 
 	// must be super user to send stuff directly to the
 	// controller and/or physical drives...
-	if( !capable(CAP_SYS_ADMIN) )
+	if( !capable(CAP_SYS_RAWIO) )
 	  return -EPERM;
 
 	// copy the caller's struct to our space.
diff -Nru a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
--- a/drivers/scsi/cyberstorm.c	Thu May  9 15:21:04 2002
+++ b/drivers/scsi/cyberstorm.c	Thu May  9 15:21:04 2002
@@ -320,3 +320,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
--- a/drivers/scsi/cyberstormII.c	Thu May  9 15:21:04 2002
+++ b/drivers/scsi/cyberstormII.c	Thu May  9 15:21:04 2002
@@ -271,3 +271,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
--- a/drivers/scsi/fastlane.c	Thu May  9 15:21:05 2002
+++ b/drivers/scsi/fastlane.c	Thu May  9 15:21:05 2002
@@ -372,3 +372,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
--- a/drivers/scsi/g_NCR5380.c	Thu May  9 15:21:03 2002
+++ b/drivers/scsi/g_NCR5380.c	Thu May  9 15:21:03 2002
@@ -77,7 +77,7 @@
  * 	IRQ line if overridden on the command line.
  *     
  */
- 
+
 /*
  * $Log: generic_NCR5380.c,v $
  */
@@ -124,787 +124,772 @@
 #include <linux/isapnp.h>
 
 #define NCR_NOT_SET 0
-static int ncr_irq=NCR_NOT_SET;
-static int ncr_dma=NCR_NOT_SET;
-static int ncr_addr=NCR_NOT_SET;
-static int ncr_5380=NCR_NOT_SET;
-static int ncr_53c400=NCR_NOT_SET;
-static int ncr_53c400a=NCR_NOT_SET;
-static int dtc_3181e=NCR_NOT_SET;
+static int ncr_irq = NCR_NOT_SET;
+static int ncr_dma = NCR_NOT_SET;
+static int ncr_addr = NCR_NOT_SET;
+static int ncr_5380 = NCR_NOT_SET;
+static int ncr_53c400 = NCR_NOT_SET;
+static int ncr_53c400a = NCR_NOT_SET;
+static int dtc_3181e = NCR_NOT_SET;
 
 static struct override {
 	NCR5380_implementation_fields;
-    int irq;
-    int dma;
-    int board;	/* Use NCR53c400, Ricoh, etc. extensions ? */
-} overrides 
-#ifdef GENERIC_NCR5380_OVERRIDE 
-    [] __initdata = GENERIC_NCR5380_OVERRIDE;
+	int irq;
+	int dma;
+	int board;		/* Use NCR53c400, Ricoh, etc. extensions ? */
+} overrides
+#ifdef GENERIC_NCR5380_OVERRIDE
+[] __initdata = GENERIC_NCR5380_OVERRIDE;
 #else
-    [1] __initdata = {{0,},};
+[1] __initdata = { { 0,},};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
-/*
- * Function : static internal_setup(int board, char *str, int *ints)
+/**
+ *	internal_setup		-	handle lilo command string override
+ *	@board:	BOARD_* identifier for the board
+ *	@str: unused
+ *	@ints: numeric parameters
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, 
- * 	or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - 
- *	array of integer parameters with ints[0] equal to the number of ints.
+ * 	Do LILO command line initialization of the overrides array. Display
+ *	errors when needed
  *
+ *	Locks: none
  */
 
-static void __init internal_setup(int board, char *str, int *ints){
-    static int commandline_current = 0;
-    switch (board) {
-    case BOARD_NCR5380:
-	if (ints[0] != 2 && ints[0] != 3) {
-	    printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
-	    return;
-	}
-	break;
-    case BOARD_NCR53C400:
-	if (ints[0] != 2) {
-	    printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    case BOARD_NCR53C400A:
-	if (ints[0] != 2) {
-	    printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    case BOARD_DTC3181E:
-	if (ints[0] != 2) {
-	    printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
-	    return;
-	}
-	break;
-    }
-
-    if (commandline_current < NO_OVERRIDES) {
-	overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1];
-	overrides[commandline_current].irq = ints[2];
-	if (ints[0] == 3) 
-	    overrides[commandline_current].dma = ints[3];
-	else 
-	    overrides[commandline_current].dma = DMA_NONE;
-	overrides[commandline_current].board = board;
-	    ++commandline_current;
-    }
+static void __init internal_setup(int board, char *str, int *ints)
+{
+	static int commandline_current = 0;
+	switch (board) {
+	case BOARD_NCR5380:
+		if (ints[0] != 2 && ints[0] != 3) {
+			printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400A:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_DTC3181E:
+		if (ints[0] != 2) {
+			printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	}
+
+	if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1];
+		overrides[commandline_current].irq = ints[2];
+		if (ints[0] == 3)
+			overrides[commandline_current].dma = ints[3];
+		else
+			overrides[commandline_current].dma = DMA_NONE;
+		overrides[commandline_current].board = board;
+		++commandline_current;
+	}
 }
 
-/*
- * Function : generic_NCR5380_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C80_setup		-	set up entry point
+ *	@str: unused
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr5380= command
+ *	line.
  */
 
-void __init generic_NCR5380_setup (char *str, int *ints){
-    internal_setup (BOARD_NCR5380, str, ints);
+static int __init do_NCR5380_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR5380, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_NCR53C400_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C400_setup		-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr53c400= command
+ *	line.
  */
 
-void __init generic_NCR53C400_setup (char *str, int *ints){
-    internal_setup (BOARD_NCR53C400, str, ints);
+static int __init do_NCR53C400_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_NCR53C400A_setup (char *str, int *ints)
+/**
+ * 	do_NCR53C400A_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the ncr53c400a= command
+ *	line.
  */
 
-void generic_NCR53C400A_setup (char *str, int *ints) {
-    internal_setup (BOARD_NCR53C400A, str, ints);
+static int __init do_NCR53C400A_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400A, str, ints);
+	return 1;
 }
 
-/*
- * Function : generic_DTC3181E_setup (char *str, int *ints)
+/**
+ * 	do_DTC3181E_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
  *
- * Purpose : LILO command line initialization of the overrides array,
- * 
- * Inputs : str - unused, ints - array of integer parameters with ints[0] 
- * 	equal to the number of ints.
+ *	Setup function invoked at boot to parse the dtc3181e= command
+ *	line.
  */
 
-void generic_DTC3181E_setup (char *str, int *ints) {
-    internal_setup (BOARD_DTC3181E, str, ints);
+static int __init do_DTC3181E_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_DTC3181E, str, ints);
+	return 1;
 }
 
-/* 
- * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+/**
+ * 	generic_NCR5380_detect	-	look for NCR5380 controllers
+ *	@tpnt: the scsi template
  *
- * Purpose : initializes generic NCR5380 driver based on the 
- *	command line / compile time port and irq definitions.
+ *	Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E
+ *	and DTC436(ISAPnP) controllers. If overrides have been set we use
+ *	them.
  *
- * Inputs : tpnt - template for this SCSI adapter.
- * 
- * Returns : 1 if a host adapter was found, 0 if not.
+ *	The caller supplied NCR5380_init function is invoked from here, before
+ *	the interrupt line is taken.
  *
+ *	Locks: none
  */
 
-int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
-    static int current_override = 0;
-    int count, i;
-    u_int *ports;
-    u_int ncr_53c400a_ports[] = {0x280, 0x290, 0x300, 0x310, 0x330,
-    		     		0x340, 0x348, 0x350, 0};
-    u_int dtc_3181e_ports[] = {0x220, 0x240, 0x280, 0x2a0, 0x2c0,
-    			     0x300, 0x320, 0x340, 0};
-    int flags = 0;
-    struct Scsi_Host *instance;
-
-    if (ncr_irq != NCR_NOT_SET)
-	overrides[0].irq=ncr_irq;
-    if (ncr_dma != NCR_NOT_SET)
-	overrides[0].dma=ncr_dma;
-    if (ncr_addr != NCR_NOT_SET)
-	overrides[0].NCR5380_map_name=(NCR5380_map_type)ncr_addr;
-    if (ncr_5380 != NCR_NOT_SET)
-	overrides[0].board=BOARD_NCR5380;
-    else if (ncr_53c400 != NCR_NOT_SET)
-	overrides[0].board=BOARD_NCR53C400;
-    else if (ncr_53c400a != NCR_NOT_SET)
-        overrides[0].board=BOARD_NCR53C400A;
-    else if (dtc_3181e != NCR_NOT_SET)
-        overrides[0].board=BOARD_DTC3181E;
-
-    if (!current_override && isapnp_present()) {
-	    struct pci_dev *dev = NULL;
-	    count = 0;
-	    while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), dev))) {
-		    if (count >= NO_OVERRIDES)
-			    break;
-		    if (!dev->active && dev->prepare(dev) < 0) {
-			    printk(KERN_ERR "dtc436e probe: prepare failed\n");
-			    continue;
-		    }
-		    if (!(dev->resource[0].flags & IORESOURCE_IO))
-			    continue;
-		    if (!dev->active && dev->activate(dev) < 0) {
-			    printk(KERN_ERR "dtc436e probe: activate failed\n");
-			    continue;
-		    }
-		    if (dev->irq_resource[0].flags & IORESOURCE_IRQ)
-			    overrides[count].irq=dev->irq_resource[0].start;
-		    else
-			    overrides[count].irq=IRQ_NONE;
-		    if (dev->dma_resource[0].flags & IORESOURCE_DMA)
-			    overrides[count].dma=dev->dma_resource[0].start;
-		    else
-			    overrides[count].dma=DMA_NONE;
-		    overrides[count].NCR5380_map_name=(NCR5380_map_type)dev->resource[0].start;
-		    overrides[count].board=BOARD_DTC3181E;
-		    count++;
-	    }
-    }
-
-    tpnt->proc_name = "g_NCR5380";
-
-    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
-	if (!(overrides[current_override].NCR5380_map_name))
-	    continue;
-
-	ports = 0;
-	switch (overrides[current_override].board) {
-	case BOARD_NCR5380:
-	    flags = FLAG_NO_PSEUDO_DMA;
-	    break;
-	case BOARD_NCR53C400:
-	    flags = FLAG_NCR53C400;
-	    break;
-	case BOARD_NCR53C400A:
-	    flags = FLAG_NO_PSEUDO_DMA;
-            ports = ncr_53c400a_ports;
-	    break;
-	case BOARD_DTC3181E:
-	    flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
-	    ports = dtc_3181e_ports;
-	    break;
+int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0;
+	int count, i;
+	unsigned int *ports;
+	static unsigned int __initdata ncr_53c400a_ports[] = {
+		0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
+	};
+	static unsigned int __initdata dtc_3181e_ports[] = {
+		0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
+	};
+	int flags = 0;
+	struct Scsi_Host *instance;
+
+	if (ncr_irq != NCR_NOT_SET)
+		overrides[0].irq = ncr_irq;
+	if (ncr_dma != NCR_NOT_SET)
+		overrides[0].dma = ncr_dma;
+	if (ncr_addr != NCR_NOT_SET)
+		overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
+	if (ncr_5380 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR5380;
+	else if (ncr_53c400 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400;
+	else if (ncr_53c400a != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400A;
+	else if (dtc_3181e != NCR_NOT_SET)
+		overrides[0].board = BOARD_DTC3181E;
+
+	if (!current_override && isapnp_present()) {
+		struct pci_dev *dev = NULL;
+		count = 0;
+		while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) {
+			if (count >= NO_OVERRIDES)
+				break;
+			if (!dev->active && dev->prepare(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: prepare failed\n");
+				continue;
+			}
+			if (!(dev->resource[0].flags & IORESOURCE_IO))
+				continue;
+			if (!dev->active && dev->activate(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: activate failed\n");
+				continue;
+			}
+			if (dev->irq_resource[0].flags & IORESOURCE_IRQ)
+				overrides[count].irq = dev->irq_resource[0].start;
+			else
+				overrides[count].irq = IRQ_NONE;
+			if (dev->dma_resource[0].flags & IORESOURCE_DMA)
+				overrides[count].dma = dev->dma_resource[0].start;
+			else
+				overrides[count].dma = DMA_NONE;
+			overrides[count].NCR5380_map_name = (NCR5380_map_type) dev->resource[0].start;
+			overrides[count].board = BOARD_DTC3181E;
+			count++;
+		}
 	}
 
+	tpnt->proc_name = "g_NCR5380";
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+		if (!(overrides[current_override].NCR5380_map_name))
+			continue;
+
+		ports = 0;
+		switch (overrides[current_override].board) {
+		case BOARD_NCR5380:
+			flags = FLAG_NO_PSEUDO_DMA;
+			break;
+		case BOARD_NCR53C400:
+			flags = FLAG_NCR53C400;
+			break;
+		case BOARD_NCR53C400A:
+			flags = FLAG_NO_PSEUDO_DMA;
+			ports = ncr_53c400a_ports;
+			break;
+		case BOARD_DTC3181E:
+			flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+			ports = dtc_3181e_ports;
+			break;
+		}
+
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	if (ports) {
-	    /* wakeup sequence for the NCR53C400A and DTC3181E*/
+		if (ports) {
+			/* wakeup sequence for the NCR53C400A and DTC3181E */
 
-	    /* Disable the adapter and look for a free io port */
-	    outb(0x59, 0x779);
-	    outb(0xb9, 0x379);
-	    outb(0xc5, 0x379);
-	    outb(0xae, 0x379);
-	    outb(0xa6, 0x379);
-	    outb(0x00, 0x379);
-
-	    if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
-	        for(i=0; ports[i]; i++) {
-	            if (overrides[current_override].NCR5380_map_name == ports[i])
-	                break;
-	        }
-	    else
-	        for(i=0; ports[i]; i++) {
-	            if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff))
-	                break;
-		}
-	    if (ports[i]) {
-	        outb(0x59, 0x779);
-	        outb(0xb9, 0x379);
-	        outb(0xc5, 0x379);
-	        outb(0xae, 0x379);
-	        outb(0xa6, 0x379);
-	        outb(0x80 | i, 0x379);          /* set io port to be used */
-        	outb(0xc0, ports[i] + 9);
-	        if (inb(ports[i] + 9) != 0x80)
-	            continue;
-	        else
-	            overrides[current_override].NCR5380_map_name=ports[i];
-	    } else
-	        continue;
-	}
+			/* Disable the adapter and look for a free io port */
+			outb(0x59, 0x779);
+			outb(0xb9, 0x379);
+			outb(0xc5, 0x379);
+			outb(0xae, 0x379);
+			outb(0xa6, 0x379);
+			outb(0x00, 0x379);
+
+			if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
+				for (i = 0; ports[i]; i++) {
+					if (overrides[current_override].NCR5380_map_name == ports[i])
+						break;
+			} else
+				for (i = 0; ports[i]; i++) {
+					if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff))
+						break;
+				}
+			if (ports[i]) {
+				outb(0x59, 0x779);
+				outb(0xb9, 0x379);
+				outb(0xc5, 0x379);
+				outb(0xae, 0x379);
+				outb(0xa6, 0x379);
+				outb(0x80 | i, 0x379);	/* set io port to be used */
+				outb(0xc0, ports[i] + 9);
+				if (inb(ports[i] + 9) != 0x80)
+					continue;
+				else
+					overrides[current_override].NCR5380_map_name = ports[i];
+			} else
+				continue;
+		}
 
-	request_region(overrides[current_override].NCR5380_map_name,
-					NCR5380_region_size, "ncr5380");
+		request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380");
 #else
-	if(check_mem_region(overrides[current_override].NCR5380_map_name,
-		NCR5380_region_size))
-		continue;
-	request_mem_region(overrides[current_override].NCR5380_map_name,
-					NCR5380_region_size, "ncr5380");
+		if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size))
+			continue;
+		request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380");
 #endif
-	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	if(instance == NULL)
-	{
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL) {
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-		release_region(overrides[current_override].NCR5380_map_name,
-	                                        NCR5380_region_size);
+			release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size);
 #else
-		release_mem_region(overrides[current_override].NCR5380_map_name,
-	                                  	NCR5380_region_size);
+			release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size);
 #endif
-		continue;
-	}
-	
-	instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
-
-	NCR5380_init(instance, flags);
-
-	if (overrides[current_override].irq != IRQ_AUTO)
-	    instance->irq = overrides[current_override].irq;
-	else 
-	    instance->irq = NCR5380_probe_irq(instance, 0xffff);
+			continue;
+		}
 
-	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
-		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    } 
+		instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
 
-	if (instance->irq == IRQ_NONE) {
-	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
-	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-	}
+		NCR5380_init(instance, flags);
 
-	printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name);
-	if (instance->irq == IRQ_NONE)
-	    printk (" interrupts disabled");
-	else 
-	    printk (" irq %d", instance->irq);
-	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-	    CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
-	NCR5380_print_options(instance);
-	printk("\n");
-
-	++current_override;
-	++count;
-    }
-    return count;
-}
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, 0xffff);
+
+		if (instance->irq != IRQ_NONE)
+			if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
+				printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
+				instance->irq = IRQ_NONE;
+			}
+
+		if (instance->irq == IRQ_NONE) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
 
-const char * generic_NCR5380_info (struct Scsi_Host* host) {
-    static const char string[]="Generic NCR5380/53C400 Driver";
-    return string;
+		printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
+		if (instance->irq == IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
+
+		++current_override;
+		++count;
+	}
+	return count;
+}
+
+/**
+ *	generic_NCR5380_info	-	reporting string
+ *	@host: NCR5380 to report on
+ *
+ *	Report driver information for the NCR5380
+ */
+ 	
+const char *generic_NCR5380_info(struct Scsi_Host *host)
+{
+	static const char string[] = "Generic NCR5380/53C400 Driver";
+	return string;
 }
 
-int generic_NCR5380_release_resources(struct Scsi_Host * instance)
+/**
+ *	generic_NCR5380_release_resources	-	free resources
+ *	@instance: host adapter to clean up 
+ *
+ *	Free the generic interface resources from this adapter.
+ *
+ *	Locks: none
+ */
+ 
+int generic_NCR5380_release_resources(struct Scsi_Host *instance)
 {
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
 
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-    release_region(instance->NCR5380_instance_name, NCR5380_region_size);
+	release_region(instance->NCR5380_instance_name, NCR5380_region_size);
 #else
-    release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
-#endif    
+	release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+#endif
 
-    if (instance->irq != IRQ_NONE)
-	free_irq(instance->irq, NULL);
+	if (instance->irq != IRQ_NONE)
+		free_irq(instance->irq, NULL);
 
 	return 0;
 }
 
 #ifdef BIOSPARAM
-/*
- * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
+/**
+ *	generic_NCR5380_biosparam
+ *	@disk: disk to compute geometry for
+ *	@dev: device identifier for this disk
+ *	@ip: sizes to fill in
  *
- * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
- *	the specified device / size.
+ *	Generates a BIOS / DOS compatible H-C-S mapping for the specified 
+ *	device / size.
  * 
- * Inputs : size = size of device in sectors (512 bytes), dev = block device
- *	major / minor, ip[] = {heads, sectors, cylinders}  
+ * 	XXX Most SCSI boards use this mapping, I could be incorrect.  Someone
+ *	using hard disks on a trantor should verify that this mapping
+ *	corresponds to that used by the BIOS / ASPI driver by running the linux
+ *	fdisk program and matching the H_C_S coordinates to what DOS uses.
  *
- * Returns : always 0 (success), initializes ip
- *	
- */
-
-/* 
- * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
- * using hard disks on a trantor should verify that this mapping corresponds
- * to that used by the BIOS / ASPI driver by running the linux fdisk program
- * and matching the H_C_S coordinates to what DOS uses.
+ *	Locks: none
  */
 
 int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip)
 {
-  int size = disk->capacity;
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  return 0;
+	int size = disk->capacity;
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	return 0;
 }
 #endif
 
 #if NCR53C400_PSEUDO_DMA
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,    int len)
-{
-    int blocks = len / 128;
-    int start = 0;
-    int bl;
-#ifdef CONFIG_SCSI_G_NCR5380_PORT
-    int i;
-#endif 
 
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len);
-#endif
-
-    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
-    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
-    while (1) {
-    
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: %d blocks left\n", blocks);
-#endif
-
-	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	    if (blocks)
-		printk("53C400r: blocks still == %d\n", blocks);
-	    else
-		printk("53C400r: Exiting loop\n");
-#endif
-	    break;
-	}
-
-#if 1
-	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
-	    printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-	    return -1;
-	}
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Waiting for buffer, bl=%d\n", bl);
-#endif
-
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Transferring 128 bytes\n");
-#endif
+/**
+ *	NCR5380_pread		-	pseudo DMA read
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
+ 
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
 
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+		{
+			int i;
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
 #endif
-	start+=128;
-	blocks--;
-    }
-
-    if (blocks) {
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: EXTRA: Waiting for buffer\n");
-#endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+		start += 128;
+		blocks--;
+	}
+
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+		{
+			// FIXME - no timeout
+		}
 
-#if (NDEBUG & NDEBUG_C400_PREAD)
-	printk("53C400r: Transferring EXTRA 128 bytes\n");
-#endif
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
+		{
+			int i;	
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
-#endif
-	start+=128;
-	blocks--;
-    }
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: No EXTRA required\n");
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: Final values: blocks=%d   start=%d\n", blocks, start);
-#endif
-
-    if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
-	printk("53C400r: no 53C80 gated irq after transfer");
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: Got 53C80 interrupt and tried to clear it\n");
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
 #endif
+		start += 128;
+		blocks--;
+	}
 
-/* DON'T DO THIS - THEY NEVER ARRIVE!
-    printk("53C400r: Waiting for 53C80 registers\n");
-    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
-	;
-*/
+	if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		printk("53C400r: no 53C80 gated irq after transfer");
 
-    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
-	printk("53C400r: no end dma signal\n");
-#if (NDEBUG & NDEBUG_C400_PREAD)
-    else
-	printk("53C400r: end dma as expected\n");
+#if 0
+	/*
+	 *	DON'T DO THIS - THEY NEVER ARRIVE!
+	 */
+	printk("53C400r: Waiting for 53C80 registers\n");
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+		;
 #endif
-
-    NCR5380_write(MODE_REG, MR_BASE);
-    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-    return 0;
-}
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
+		printk(KERN_ERR "53C400r: no end dma signal\n");
 		
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,    int len)
-{
-    int blocks = len / 128;
-    int start = 0;
-    int i;
-    int bl;
-    NCR5380_local_declare();
-
-    NCR5380_setup(instance);
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len);
-#endif
-
-    NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
-    NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
-    while (1) {
-	if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
-	    printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-	    return -1;
-	}
-
-	if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	    if (blocks)
-		printk("53C400w: exiting loop, blocks still == %d\n", blocks);
-	    else
-		printk("53C400w: exiting loop\n");
-#endif
-	    break;
-	}
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	return 0;
+}
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: %d blocks left\n", blocks);
+/**
+ *	NCR5380_write		-	pseudo DMA write
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
 
-	printk("53C400w: waiting for buffer, bl=%d\n", bl);
-#endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+	int i;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: transferring 128 bytes\n");
-#endif
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - timeout
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
 #endif
-	start+=128;
-	blocks--;
-    }
-    if (blocks) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: EXTRA waiting for buffer\n");
-#endif
-	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	    ;
+		start += 128;
+		blocks--;
+	}
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - no timeout
 
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: transferring EXTRA 128 bytes\n");
-#endif
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
-	for (i=0; i<128; i++)
-	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
 #else
-	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
-#endif
-	start+=128;
-	blocks--;
-    }
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    else
-	printk("53C400w: No EXTRA required\n");
-#endif
-    
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: Final values: blocks=%d   start=%d\n", blocks, start);
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
 #endif
+		start += 128;
+		blocks--;
+	}
 
 #if 0
-    printk("53C400w: waiting for registers to be available\n");
-    THEY NEVER DO!
-    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
-	;
-    printk("53C400w: Got em\n");
-#endif
-
-    /* Let's wait for this instead - could be ugly */
-    /* All documentation says to check for this. Maybe my hardware is too
-     * fast. Waiting for it seems to work fine! KLL
-     */
-    while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
-	;
-
-    /*
-     * I know. i is certainly != 0 here but the loop is new. See previous
-     * comment.
-     */
-    if (i) {
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	printk("53C400w: got 53C80 gated irq (last block)\n");
-#endif
-	if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
-	    printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i);
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-	else
-	    printk("53C400w: Got END OF DMA\n");
-#endif
-    }
-    else
-	printk("53C400w: no 53C80 gated irq after transfer (last block)\n");
+	printk("53C400w: waiting for registers to be available\n");
+	THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
+	printk("53C400w: Got em\n");
+#endif
+
+	/* Let's wait for this instead - could be ugly */
+	/* All documentation says to check for this. Maybe my hardware is too
+	 * fast. Waiting for it seems to work fine! KLL
+	 */
+	while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		;	// FIXME - no timeout
+
+	/*
+	 * I know. i is certainly != 0 here but the loop is new. See previous
+	 * comment.
+	 */
+	if (i) {
+		if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
+			printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
+	} else
+		printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
 
 #if 0
-    if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
-	printk("53C400w: no end dma signal\n");
-    }
-#endif
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w: waiting for last byte...\n");
-#endif
-    while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
-    	;
-
-#if (NDEBUG & NDEBUG_C400_PWRITE)
-    printk("53C400w:     got last byte.\n");
-    printk("53C400w: pwrite exiting with status 0, whoopee!\n");
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
+		printk(KERN_ERR "53C400w: no end dma signal\n");
+	}
 #endif
-    return 0;
+	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+		; 	// TIMEOUT
+	return 0;
 }
-#endif /* PSEUDO_DMA */
+#endif				/* PSEUDO_DMA */
 
+/*
+ *	Include the NCR5380 core code that we build our driver around	
+ */
+ 
 #include "NCR5380.c"
 
 #define PRINTP(x) len += sprintf(buffer+len, x)
 #define ANDP ,
 
-static int sprint_opcode(char* buffer, int len, int opcode) {
-    int start = len;
-    PRINTP("0x%02x " ANDP opcode);
-    return len-start;
-}
-
-static int sprint_command (char* buffer, int len, unsigned char *command) {
-    int i,s,start=len;
-    len += sprint_opcode(buffer, len, command[0]);
-    for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-	PRINTP("%02x " ANDP command[i]);
-    PRINTP("\n");
-    return len-start;
-}
-
-static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) {
-    int start = len;
-    PRINTP("host number %d destination target %d, lun %d\n" ANDP
-       cmd->host->host_no ANDP
-       cmd->target ANDP
-       cmd->lun);
-    PRINTP("        command = ");
-    len += sprint_command (buffer, len, cmd->cmnd);
-    return len-start;
-}
-
-int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
-{
-    int len = 0;
-    NCR5380_local_declare();
-    unsigned long flags;
-    unsigned char status;
-    int i;
-    struct Scsi_Host *scsi_ptr;
-    Scsi_Cmnd *ptr;
-    struct NCR5380_hostdata *hostdata;
+static int sprint_opcode(char *buffer, int len, int opcode)
+{
+	int start = len;
+	PRINTP("0x%02x " ANDP opcode);
+	return len - start;
+}
+
+static int sprint_command(char *buffer, int len, unsigned char *command)
+{
+	int i, s, start = len;
+	len += sprint_opcode(buffer, len, command[0]);
+	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+		PRINTP("%02x " ANDP command[i]);
+	PRINTP("\n");
+	return len - start;
+}
+
+/**
+ *	sprintf_Scsi_Cmnd	-	print a scsi command
+ *	@buffer: buffr to print into
+ *	@len: buffer length
+ *	@cmd: SCSI command block
+ *	
+ *	Print out the target and command data in hex
+ */
+
+static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd)
+{
+	int start = len;
+	PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun);
+	PRINTP("        command = ");
+	len += sprint_command(buffer, len, cmd->cmnd);
+	return len - start;
+}
+
+/**
+ *	generic_NCR5380_proc_info	-	/proc for NCR5380 driver
+ *	@buffer: buffer to print into
+ *	@start: start position
+ *	@offset: offset into buffer
+ *	@len: length
+ *	@hostno: instance to affect
+ *	@inout: read/write
+ *
+ *	Provide the procfs information for the 5380 controller. We fill
+ *	this with useful debugging information including the commands
+ *	being executed, disconnected command queue and the statistical
+ *	data
+ *
+ *	Locks: global cli/lock for queue walk
+ */
+ 
+int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+	int len = 0;
+	NCR5380_local_declare();
+	unsigned long flags;
+	unsigned char status;
+	int i;
+	struct Scsi_Host *scsi_ptr;
+	Scsi_Cmnd *ptr;
+	struct NCR5380_hostdata *hostdata;
 #ifdef NCR5380_STATS
-    Scsi_Device *dev;
-    extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+	Scsi_Device *dev;
+	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #endif
-    save_flags(flags);
-    cli();
+	save_flags(flags);
+	cli();
 
-    for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
-	if (scsi_ptr->host_no == hostno)
-	    break;
-    NCR5380_setup(scsi_ptr);
-    hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata;
-
-    PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
-    PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
-    PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
+	for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr = scsi_ptr->next)
+		if (scsi_ptr->host_no == hostno)
+			break;
+	NCR5380_setup(scsi_ptr);
+	hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
+
+	PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
+	PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
+	PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
 #ifdef NCR53C400
-    PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
-    PRINTP("NCR53C400 card%s detected\n" ANDP  (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
+	PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
+	PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not");
 # if NCR53C400_PSEUDO_DMA
-    PRINTP("NCR53C400 pseudo DMA used\n");
+	PRINTP("NCR53C400 pseudo DMA used\n");
 # endif
 #else
-    PRINTP("NO NCR53C400 driver extensions\n");
+	PRINTP("NO NCR53C400 driver extensions\n");
 #endif
-    PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
-    if (scsi_ptr->irq == IRQ_NONE)
-	PRINTP("no interrupt\n");
-    else
-	PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
+	PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
+	if (scsi_ptr->irq == IRQ_NONE)
+		PRINTP("no interrupt\n");
+	else
+		PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
 
 #ifdef NCR5380_STATS
-    if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
-	PRINTP("There are commands pending, transfer rates may be crud\n");
-    if (hostdata->pendingr)
-	PRINTP("  %d pending reads" ANDP hostdata->pendingr);
-    if (hostdata->pendingw)
-	PRINTP("  %d pending writes" ANDP hostdata->pendingw);
-    if (hostdata->pendingr || hostdata->pendingw)
-	PRINTP("\n");
-    for (dev = scsi_ptr->host_queue; dev; dev=dev->next) {
-	    unsigned long br = hostdata->bytes_read[dev->id];
-	    unsigned long bw = hostdata->bytes_write[dev->id];
-	    long tr = hostdata->time_read[dev->id] / HZ;
-	    long tw = hostdata->time_write[dev->id] / HZ;
-
-	    PRINTP("  T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown");
-	    for (i=0; i<8; i++)
-		if (dev->vendor[i] >= 0x20)
-		    *(buffer+(len++)) = dev->vendor[i];
-	    *(buffer+(len++)) = ' ';
-	    for (i=0; i<16; i++)
-		if (dev->model[i] >= 0x20)
-		    *(buffer+(len++)) = dev->model[i];
-	    *(buffer+(len++)) = ' ';
-	    for (i=0; i<4; i++)
-		if (dev->rev[i] >= 0x20)
-		    *(buffer+(len++)) = dev->rev[i];
-	    *(buffer+(len++)) = ' ';
-				    
-	    PRINTP("\n%10ld kb read    in %5ld secs" ANDP br/1024 ANDP tr);
-	    if (tr)
-		PRINTP(" @ %5ld bps" ANDP br / tr); 
-
-	    PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw);
-	    if (tw)
-		PRINTP(" @ %5ld bps" ANDP bw / tw); 
-	    PRINTP("\n");
-    }
-#endif
-	
-    status = NCR5380_read(STATUS_REG);
-    if (!(status & SR_REQ))
-	PRINTP("REQ not asserted, phase unknown.\n");
-    else {
-	for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
-		    (phases[i].value != (status & PHASE_MASK)); ++i)
-	    ;
-	PRINTP("Phase %s\n" ANDP phases[i].name);
-    }
-
-    if (!hostdata->connected) {
-	PRINTP("No currently connected command\n");
-    } else {
-	len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected);
-    }
-
-    PRINTP("issue_queue\n");
-
-    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr;
-		ptr = (Scsi_Cmnd *) ptr->host_scribble)
-	len += sprint_Scsi_Cmnd (buffer, len, ptr);
-
-    PRINTP("disconnected_queue\n");
-
-    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
-		ptr = (Scsi_Cmnd *) ptr->host_scribble)
-	len += sprint_Scsi_Cmnd (buffer, len, ptr);
-	
-    *start = buffer + offset;
-    len -= offset;
-    if (len > length)
-	    len = length;
-    restore_flags(flags);
-    return len;
+	if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
+		PRINTP("There are commands pending, transfer rates may be crud\n");
+	if (hostdata->pendingr)
+		PRINTP("  %d pending reads" ANDP hostdata->pendingr);
+	if (hostdata->pendingw)
+		PRINTP("  %d pending writes" ANDP hostdata->pendingw);
+	if (hostdata->pendingr || hostdata->pendingw)
+		PRINTP("\n");
+	for (dev = scsi_ptr->host_queue; dev; dev = dev->next) {
+		unsigned long br = hostdata->bytes_read[dev->id];
+		unsigned long bw = hostdata->bytes_write[dev->id];
+		long tr = hostdata->time_read[dev->id] / HZ;
+		long tw = hostdata->time_write[dev->id] / HZ;
+
+		PRINTP("  T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+		for (i = 0; i < 8; i++)
+			if (dev->vendor[i] >= 0x20)
+				*(buffer + (len++)) = dev->vendor[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 16; i++)
+			if (dev->model[i] >= 0x20)
+				*(buffer + (len++)) = dev->model[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 4; i++)
+			if (dev->rev[i] >= 0x20)
+				*(buffer + (len++)) = dev->rev[i];
+		*(buffer + (len++)) = ' ';
+
+		PRINTP("\n%10ld kb read    in %5ld secs" ANDP br / 1024 ANDP tr);
+		if (tr)
+			PRINTP(" @ %5ld bps" ANDP br / tr);
+
+		PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw);
+		if (tw)
+			PRINTP(" @ %5ld bps" ANDP bw / tw);
+		PRINTP("\n");
+	}
+#endif
+
+	status = NCR5380_read(STATUS_REG);
+	if (!(status & SR_REQ))
+		PRINTP("REQ not asserted, phase unknown.\n");
+	else {
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
+		PRINTP("Phase %s\n" ANDP phases[i].name);
+	}
+
+	if (!hostdata->connected) {
+		PRINTP("No currently connected command\n");
+	} else {
+		len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected);
+	}
+
+	PRINTP("issue_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	PRINTP("disconnected_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	restore_flags(flags);
+	return len;
 }
 
 #undef PRINTP
 #undef ANDP
 
-/* Eventually this will go into an include file, but this will be later */
+/*
+ *	Eventually this will go into an include file, but this will be later 
+ */
 static Scsi_Host_Template driver_template = GENERIC_NCR5380;
 
 #include <linux/module.h>
 #include "scsi_module.c"
 
-#ifdef MODULE 
-
 MODULE_PARM(ncr_irq, "i");
 MODULE_PARM(ncr_dma, "i");
 MODULE_PARM(ncr_addr, "i");
@@ -913,65 +898,20 @@
 MODULE_PARM(ncr_53c400a, "i");
 MODULE_PARM(dtc_3181e, "i");
 MODULE_LICENSE("GPL");
-#else
-
-static int __init do_NCR5380_setup(char *str)
-{
-        int ints[10];
-
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR5380_setup(str,ints);
-
-        return 1;
-}
-
-static int __init do_NCR53C400_setup(char *str)
-{
-        int ints[10];
-
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR53C400_setup(str,ints);
 
-        return 1;
-}
-
-static int __init do_NCR53C400A_setup(char *str)
-{
-        int ints[10];
-
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_NCR53C400A_setup(str,ints);
-
-        return 1;
-}
-
-static int __init do_DTC3181E_setup(char *str)
-{
-        int ints[10];
-
-        get_options(str, sizeof(ints)/sizeof(int), ints);
-        generic_DTC3181E_setup(str,ints);
-
-        return 1;
-}
-
-__setup("ncr5380=", do_NCR5380_setup);
-__setup("ncr53c400=", do_NCR53C400_setup);
-__setup("ncr53c400a=", do_NCR53C400A_setup);
-__setup("dtc3181e=", do_DTC3181E_setup);
 
 static struct isapnp_device_id id_table[] __devinitdata = {
 	{
-		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), 
-		0
-	},
+	 ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+	 ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e),
+	 0},
 	{0}
 };
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
-MODULE_LICENSE("GPL");
 
 
-#endif
-
+__setup("ncr5380=", do_NCR5380_setup);
+__setup("ncr53c400=", do_NCR53C400_setup);
+__setup("ncr53c400a=", do_NCR53C400A_setup);
+__setup("dtc3181e=", do_DTC3181E_setup);
diff -Nru a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
--- a/drivers/scsi/gvp11.c	Thu May  9 15:21:09 2002
+++ b/drivers/scsi/gvp11.c	Thu May  9 15:21:09 2002
@@ -40,9 +40,9 @@
 	if (!(status & GVP11_DMAC_INT_PENDING))
 	    continue;
 
-	spin_lock_irqsave(instance->host_lock, flags);
+	spin_lock_irqsave(&instance->host_lock, flags);
 	wd33c93_intr (instance);
-	spin_unlock_irqrestore(instance->host_lock, flags);
+	spin_unlock_irqrestore(&instance->host_lock, flags);
     }
 }
 
@@ -69,7 +69,7 @@
 
  	if( !scsi_alloc_out_of_range ) {
 	    HDATA(cmd->host)->dma_bounce_buffer =
-		scsi_malloc (HDATA(cmd->host)->dma_bounce_len);
+		kmalloc (HDATA(cmd->host)->dma_bounce_len, GFP_KERNEL);
 	    HDATA(cmd->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
 	}
 
@@ -93,8 +93,7 @@
 	if (addr & HDATA(cmd->host)->dma_xfer_mask) {
 	    /* fall back to Chip RAM if address out of range */
 	    if( HDATA(cmd->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-		scsi_free (HDATA(cmd->host)->dma_bounce_buffer,
-			   HDATA(cmd->host)->dma_bounce_len);
+		kfree (HDATA(cmd->host)->dma_bounce_buffer);
 		scsi_alloc_out_of_range = 1;
 	    } else {
 		amiga_chip_free (HDATA(cmd->host)->dma_bounce_buffer);
@@ -164,8 +163,7 @@
 		    SCpnt->SCp.this_residual);
 	
 	if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
-	    scsi_free (HDATA(instance)->dma_bounce_buffer,
-		       HDATA(instance)->dma_bounce_len);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
 	else
 	    amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
 	
@@ -372,3 +370,5 @@
 #endif
     return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Thu May  9 15:21:01 2002
+++ b/drivers/scsi/ide-scsi.c	Thu May  9 15:21:01 2002
@@ -557,7 +557,6 @@
 	check_media_change:	NULL,
 	revalidate:		idescsi_revalidate,
 	capacity:		NULL,
-	proc:			NULL
 };
 
 /*
@@ -800,17 +799,27 @@
 	if (rq) kfree (rq);
 	cmd->result = DID_ERROR << 16;
 	done(cmd);
+
 	return 0;
 }
 
-int idescsi_abort (Scsi_Cmnd *cmd)
+/* FIXME: This needs further investigation.
+ */
+int idescsi_device_reset (Scsi_Cmnd *cmd)
 {
-	return SCSI_ABORT_SNOOZE;
-}
+#if 0
+	ide_drive_t *drive = idescsi_drives[cmd->target];
+        struct request req;
 
-int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
-{
-	return SCSI_RESET_SUCCESS;
+        ide_init_drive_cmd(&req);
+        req.flags = REQ_SPECIAL;
+
+	/* FIX ME, the next executable line causes on oops in lk 2.5.10-dj1
+	 * [code copied from ide-cd's ide_cdrom_reset(), does it work?]
+	 */
+        ide_do_drive_cmd(drive, &req, ide_wait);
+#endif
+	return SUCCESS;
 }
 
 int idescsi_bios (Disk *disk, kdev_t dev, int *parm)
@@ -833,8 +842,8 @@
 	info:		idescsi_info,
 	ioctl:		idescsi_ioctl,
 	queuecommand:	idescsi_queue,
-	abort:		idescsi_abort,
-	reset:		idescsi_reset,
+	eh_device_reset_handler: 
+			idescsi_device_reset,
 	bios_param:	idescsi_bios,
 	can_queue:	10,
 	this_id:	-1,
diff -Nru a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c
--- a/drivers/scsi/mac_NCR5380.c	Thu May  9 15:21:04 2002
+++ b/drivers/scsi/mac_NCR5380.c	Thu May  9 15:21:04 2002
@@ -662,10 +662,7 @@
 
 static volatile int main_running = 0;
 static struct tq_struct NCR5380_tqueue = {
-    NULL,		/* next */
-    0,			/* sync */
-    (void (*)(void*))NCR5380_main,  /* routine, must have (void *) arg... */
-    NULL		/* data */
+    routine:	(void (*)(void*))NCR5380_main	/* must have (void *) arg... */
 };
 
 static __inline__ void queue_main(void)
diff -Nru a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
--- a/drivers/scsi/mac_esp.c	Thu May  9 15:21:07 2002
+++ b/drivers/scsi/mac_esp.c	Thu May  9 15:21:07 2002
@@ -713,3 +713,5 @@
 static Scsi_Host_Template driver_template = SCSI_MAC_ESP;
 
 #include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
--- a/drivers/scsi/mvme16x.c	Thu May  9 15:21:04 2002
+++ b/drivers/scsi/mvme16x.c	Thu May  9 15:21:04 2002
@@ -22,7 +22,7 @@
 #include<linux/stat.h>
 
 extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
-			u32 base, int io_port, int irq, int dma,
+			unsigned long base, int io_port, int irq, int dma,
 			long long options, int clock);
 
 int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
@@ -46,7 +46,7 @@
 
     clock = 66000000;	/* 66MHz SCSI Clock */
 
-    ncr53c7xx_init(tpnt, 0, 710, (u32)0xfff47000,
+    ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
 			0, MVME16x_IRQ_SCSI, DMA_NONE,
 			options, clock);
     called = 1;
diff -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
--- a/drivers/scsi/oktagon_esp.c	Thu May  9 15:21:01 2002
+++ b/drivers/scsi/oktagon_esp.c	Thu May  9 15:21:01 2002
@@ -77,7 +77,9 @@
 long oktag_to_io(long *paddr, long *addr, long len);
 long oktag_from_io(long *addr, long *paddr, long len);
 
-static struct tq_struct tq_fake_dma = { NULL, 0, dma_commit, NULL };
+static struct tq_struct tq_fake_dma = {
+    routine:	dma_commit,
+};
 
 #define DMA_MAXTRANSFER 0x8000
 
@@ -589,3 +591,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	Thu May  9 15:21:07 2002
+++ b/drivers/scsi/osst.c	Thu May  9 15:21:07 2002
@@ -16,15 +16,15 @@
   Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $
+  $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $
 
   Microscopic alterations - Rik Ling, 2000/12/21
   Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
-static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $";
-const char * osst_version = "0.9.8";
+static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $";
+const char * osst_version = "0.9.10";
 
 /* The "failure to reconnect" firmware bug */
 #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
@@ -226,20 +226,20 @@
 		 SRpnt->sr_cmnd[0] != MODE_SENSE &&
 		 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
-			printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev);
-			print_req_sense("osst", SRpnt);
+			printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev);
+			print_req_sense("osst:", SRpnt);
 		}
 		else {
 			static	int	notyetprinted = 1;
 
 			printk(KERN_WARNING
-			     "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			     "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
 			     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 			     host_byte(result));
 			if (notyetprinted) {
 				notyetprinted = 0;
 				printk(KERN_INFO
-					"osst%d:I: This error may be caused by your scsi controller,\n", dev);
+					"osst%d:I: This warning may be caused by your scsi controller,\n", dev);
 				printk(KERN_INFO
 					"osst%d:I: it has been reported with some Buslogic cards.\n", dev);
 			}
@@ -271,11 +271,10 @@
 /* Wakeup from interrupt */
 static void osst_sleep_done (Scsi_Cmnd * SCpnt)
 {
-	unsigned int dev;
+	unsigned int dev = TAPE_NR(SCpnt->request.rq_dev);
 	OS_Scsi_Tape * STp;
 
-	if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) {
-		STp = os_scsi_tapes[dev];
+	if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) {
 		if ((STp->buffer)->writing &&
 		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 		    (SCpnt->sense_buffer[2] & 0x40)) {
@@ -482,7 +481,8 @@
 				memset(page_address(STp->buffer->sg[i].page),
 				       0, STp->buffer->sg[i].length);
 			strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
-		}
+                } else
+			STp->buffer->buffer_bytes = OS_FRAME_SIZE;
 		return 1;
 	}
 	if (STp->buffer->syscall_result) {
@@ -621,8 +621,10 @@
 	if (!SRpnt) return (-EBUSY);
 
 	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
-		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4          &&
-	       (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)         ) {
+	       (( SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4    &&
+		 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)    ) ||
+		( SRpnt->sr_sense_buffer[2]  == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
+		  SRpnt->sr_sense_buffer[13] == 0                                        )  )) {
 #if DEBUG
 	    if (debugging) {
 		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev);
@@ -630,7 +632,7 @@
 		debugging = 0;
 	    }
 #endif
-	    current->state = TASK_INTERRUPTIBLE;
+	    set_current_state(TASK_INTERRUPTIBLE);
 	    schedule_timeout(HZ / 10);
 
 	    memset(cmd, 0, MAX_COMMAND_SIZE);
@@ -658,6 +660,66 @@
 	return 0;
 }
 
+/*
+ * Wait for a tape to be inserted in the unit
+ */
+static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Request  * SRpnt;
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg = debugging;
+	int		dev  = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+
+	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
+		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 0x3a       &&
+	        SRpnt->sr_sense_buffer[13] == 0                                             ) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev);
+		printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev);
+		debugging = 0;
+	    }
+#endif
+	    set_current_state(TASK_INTERRUPTIBLE);
+	    schedule_timeout(HZ / 10);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
+	}
+	*aSRpnt = SRpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( STp->buffer->syscall_result     && SRpnt->sr_sense_buffer[2]  != 2 &&
+	     SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev);
+	    printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+	    return 0;
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev);
+#endif
+	return 1;
+}
+
 static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame)
 {
 	int	retval;
@@ -696,7 +758,7 @@
 		result = osst_write_error_recovery(STp, aSRpnt, 0);
 
 	result |= osst_wait_ready(STp, aSRpnt, 5 * 60);
-	STp->ps[STp->partition].rw = ST_IDLE;
+	STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
 	return (result);
 }
 
@@ -745,7 +807,7 @@
 			notyetprinted--;
 		}
 #endif
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout (HZ / OSST_POLL_PER_SEC);
 	}
 #if DEBUG
@@ -903,6 +965,8 @@
 #endif
 		if ( osst_initiate_read(STp, aSRpnt)
                 || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
+			if (STp->raw)
+				return (-EIO);
 			position = osst_get_frame_position(STp, aSRpnt);
 			if (position >= 0xbae && position < 0xbb8)
 				position = 0xbb8;
@@ -968,7 +1032,7 @@
 	if (cnt > 1) {
 		STp->recover_count++;
 		STp->recover_erreg++;
-		printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", 
+		printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", 
 					dev, STp->read_error_frame);
  	}
 	STp->read_count++;
@@ -1525,7 +1589,10 @@
 			retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
 		else
 			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
-		printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" ");
+		printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev,
+			       	retval?"E"    :"I",
+			       	retval?""     :"Don't worry, ",
+			       	retval?" not ":" ");
 		break;
 	   case OS_WRITE_LAST_MARK:
 		printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev);
@@ -1596,7 +1663,7 @@
 			       mt_count, last_mark_ppos);
 #endif
 		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
-			osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG 
@@ -1628,7 +1695,7 @@
 #if DEBUG
 		printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos);
 #endif
-		osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0);
+		osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
 		cnt++;
 		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -1755,7 +1822,7 @@
 #endif
 			return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 		} else {
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 				printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n",
@@ -1795,7 +1862,7 @@
 #endif
 					return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
 				}
-				osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0);
+				osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
 				if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
 					printk(OSST_DEB_MSG
@@ -1827,7 +1894,7 @@
 #if DEBUG
 			else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos);
 #endif
-			osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0);
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
 			cnt++;
 			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
 #if DEBUG
@@ -2464,7 +2531,7 @@
 	}
 
 #if DEBUG
-	printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev);
+	printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev);
 	 /*
 	 * In debug mode, we want to see as many errors as possible
 	 * to test the error recovery mechanism.
@@ -3402,6 +3469,7 @@
 		if (retval)
 			goto out;
 		STps->rw = ST_IDLE;
+		/* FIXME -- this may leave the tape without EOD and up2date headers */
 	}
 
 	if ((count % STp->block_size) != 0) {
@@ -3814,6 +3882,10 @@
 			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
 		 else
 			ioctl_result = 0;
+#if DEBUG
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg);
+#endif
 		 for (i=0; i<arg; i++)
 			ioctl_result |= osst_write_filemark(STp, &SRpnt);
 		 if (fileno >= 0) fileno += arg;
@@ -3833,14 +3905,9 @@
 		 cmd[4] = arg;
 		 timeout = STp->timeout;
 #if DEBUG
-		 if (debugging) {
-			if (cmd_in == MTWEOF)
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev,
-				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-			else
-			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev,
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev,
 				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-		 }
 #endif
 		 if (fileno >= 0)
 			fileno += arg;
@@ -3853,8 +3920,12 @@
 	 case MTRETEN:
 		 cmd[0] = START_STOP;
 		 cmd[1] = 1;			/* Don't wait for completion */
-		 if (cmd_in == MTLOAD)
+		 if (cmd_in == MTLOAD) {
+		     if (STp->ready == ST_NO_TAPE)
+			 cmd[4] = 4;		/* open tray */
+		      else
 			 cmd[4] = 1;		/* load */
+		 }
 		 if (cmd_in == MTRETEN)
 			 cmd[4] = 3;		/* retension then mount */
 		 if (cmd_in == MTOFFL)
@@ -3993,7 +4064,7 @@
 		printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
 #endif
 
-	if (!ioctl_result) {
+	if (!ioctl_result) {				/* success */
 
 		if (cmd_in == MTFSFM) {
 			 fileno--;
@@ -4070,6 +4141,8 @@
 		if (cmd_in == MTLOCK)
 			STp->door_locked = ST_LOCK_FAILS;
 
+		if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
+			ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
 	}
 	*aSRpnt = SRpnt;
 
@@ -4110,6 +4183,7 @@
 		 __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
 	if (osst_template.module)
 		 __MOD_INC_USE_COUNT(osst_template.module);
+	STp->device->access_count++;
 
 	if (mode != STp->current_mode) {
 #if DEBUG
@@ -4126,6 +4200,8 @@
 	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
 	STp->raw = (minor(inode->i_rdev) & 0x40) != 0;
+	if (STp->raw)
+		STp->header_ok = 0;
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
@@ -4216,7 +4292,7 @@
 			STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
 		for (i=0; i < ST_NBR_PARTITIONS; i++) {
 			STps = &(STp->ps[i]);
-			STps->rw = ST_IDLE;			/* FIXME - seems to be redundant... */
+			STps->rw = ST_IDLE;		/* FIXME - seems to be redundant... */
 			STps->eof = ST_NOEOF;
 			STps->at_sm = 0;
 			STps->last_block_valid = FALSE;
@@ -4264,8 +4340,8 @@
 					STp->door_locked = ST_LOCKED_AUTO;
 			}
 			if (!STp->frame_in_buffer) {
-				STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
-					    (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+				STp->block_size = (STm->default_blksize > 0) ?
+							STm->default_blksize : OS_DATA_SIZE;
 				STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
 			}
 			STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
@@ -4358,8 +4434,6 @@
 		return 0;
 	}
 
-	STp->min_block = STp->max_block = (-1);
-
 	osst_configure_onstream(STp, &SRpnt);
 
 /*	STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
@@ -4386,11 +4460,9 @@
 	} else
 		STp->buffer->aux = NULL; /* this had better never happen! */
 
-	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : (
+	STp->block_size = STp->raw ? OS_FRAME_SIZE : (
 			     (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
-	STp->min_block  = 512;
-	STp->max_block  = OS_DATA_SIZE;
-	STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
+	STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
 	STp->buffer->buffer_bytes  =
 	STp->buffer->read_pointer  =
 	STp->frame_in_buffer       = 0;
@@ -4448,6 +4520,8 @@
 		STp->buffer = NULL;
 	}
 	STp->in_use = 0;
+	STp->header_ok = 0;
+	STp->device->access_count--;
 
 	if (STp->device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -4484,7 +4558,7 @@
 		if (result != 0 && result != (-ENOSPC))
 			goto out;
 	}
-	if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
 
 #if DEBUG
 		if (debugging) {
@@ -4494,16 +4568,17 @@
 					       dev, STp->nbr_waits, STp->nbr_finished);
 		}
 #endif
+		if (STp->write_type != OS_WRITE_NEW_MARK) {
+			/* true unless the user wrote the filemark for us */
+			result = osst_flush_drive_buffer(STp, &SRpnt);
+			if (result < 0) goto out;
+			result = osst_write_filemark(STp, &SRpnt);
+			if (result < 0) goto out;
 
-		result = osst_flush_drive_buffer(STp, &SRpnt);
-		if (result < 0) goto out;
-		result = osst_write_filemark(STp, &SRpnt);
-		if (result < 0) goto out;
-
-		if (STps->drv_file >= 0)
-			STps->drv_file++ ;
-		STps->drv_block = 0;
-
+			if (STps->drv_file >= 0)
+				STps->drv_file++ ;
+			STps->drv_block = 0;
+		}
 		result = osst_write_eod(STp, &SRpnt);
 		osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
 
@@ -4587,7 +4662,12 @@
 	if (STp->buffer != NULL)
 		STp->buffer->in_use = 0;
 
+	if (STp->raw)
+		STp->header_ok = 0;
+
 	STp->in_use = 0;
+	STp->device->access_count--;
+
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
 	if(osst_template.module)
@@ -4637,7 +4717,10 @@
 
 	cmd_type = _IOC_TYPE(cmd_in);
 	cmd_nr   = _IOC_NR(cmd_in);
-
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev,
+			    cmd_type, cmd_nr, STp->raw?"raw":"normal");
+#endif
 	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
 		struct mtop mtc;
 
@@ -4720,8 +4803,8 @@
 			}
 		}
 
-		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
-		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+		if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
+		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
 		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
 			STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
 
@@ -4773,7 +4856,10 @@
 	 	}
 
 		if (mtc.mt_op == MTSEEK) {
-			i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
+			if (STp->raw)
+				i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
+			else
+				i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
 			retval = i;
@@ -4878,7 +4964,10 @@
 			retval = (-EINVAL);
 			goto out;
 		}
-		blk = osst_get_sector(STp, &SRpnt);
+		if (STp->raw)
+			blk = osst_get_frame_position(STp, &SRpnt);
+		else
+			blk = osst_get_sector(STp, &SRpnt);
 		if (blk < 0) {
 			retval = blk;
 			goto out;
@@ -4972,7 +5061,7 @@
 				tb = NULL;
 				break;
 			    }
-			    tb->sg[segs].page = NULL;
+                            tb->sg[segs].page = NULL;
 			    tb->sg[segs].length = b_size;
 			    got += b_size;
 			    segs++;
@@ -5424,6 +5513,8 @@
 	tpnt->partition = 0;
 	tpnt->new_partition = 0;
 	tpnt->nbr_partitions = 0;
+	tpnt->min_block = 512;
+	tpnt->max_block = OS_DATA_SIZE;
 	tpnt->timeout = OSST_TIMEOUT;
 	tpnt->long_timeout = OSST_LONG_TIMEOUT;
 
@@ -5463,6 +5554,7 @@
 
 	tpnt->current_mode = 0;
 	tpnt->modes[0].defined = TRUE;
+	tpnt->modes[2].defined = TRUE;
 	tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
 	init_MUTEX(&tpnt->lock);
 
diff -Nru a/drivers/scsi/osst.h b/drivers/scsi/osst.h
--- a/drivers/scsi/osst.h	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/osst.h	Thu May  9 15:21:02 2002
@@ -1,5 +1,5 @@
 /*
- *	$Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $
+ *	$Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $
  */
 
 #include <asm/byteorder.h>
@@ -638,3 +638,5 @@
 #define OS_WRITE_HEADER    4
 #define OS_WRITE_FILLER    5
 
+/* Additional rw state */
+#define OS_WRITING_COMPLETE 3
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Thu May  9 15:21:03 2002
+++ b/drivers/scsi/sd.c	Thu May  9 15:21:03 2002
@@ -129,7 +129,7 @@
 static Scsi_Disk * sd_get_sdisk(int index);
 
 
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC32)
 /**
  *	sd_find_target - find kdev_t of first scsi disk that matches
  *	given host and scsi_id. 
@@ -149,7 +149,7 @@
 {
 	Scsi_Disk *sdkp;
 	Scsi_Device *sdp;
-	Scsi_Host *shp = hp;
+	struct Scsi_Host *shp = hp;
 	int dsk_nr;
 	unsigned long iflags;
 
@@ -162,7 +162,7 @@
 		sdp = sdkp->device;
 		if (sdp && (sdp->host == shp) && (sdp->id == scsi_id)) {
 			read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
-			return MKDEV_SD(k);
+			return MKDEV_SD(dsk_nr);
 		}
 	}
 	read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
@@ -242,38 +242,7 @@
 				return -EFAULT;
 			return 0;
 		}
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = 
-					(struct hd_big_geometry *) arg;
-
-			if(!loc)
-				return -EINVAL;
-			host = sdp->host;
-
-			/* default to most commonly used values */
-			diskinfo[0] = 0x40;
-			diskinfo[1] = 0x20;
-			diskinfo[2] = sdkp->capacity >> 11;
-
-			/* override with calculated, extended default, 
-			   or driver values */
-			if(host->hostt->bios_param != NULL) 
-				host->hostt->bios_param(sdkp, dev,
-							&diskinfo[0]);
-			else
-				scsicam_bios_param(sdkp, dev, &diskinfo[0]);
 
-			if (put_user(diskinfo[0], &loc->heads) ||
-				put_user(diskinfo[1], &loc->sectors) ||
-				put_user(diskinfo[2], 
-					 (unsigned int *) &loc->cylinders) ||
-				put_user((unsigned)
-					   get_start_sect(inode->i_rdev),
-					 (unsigned long *)&loc->start))
-				return -EFAULT;
-			return 0;
-		}
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
 		case BLKROSET:
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Thu May  9 15:21:07 2002
+++ b/drivers/scsi/sg.c	Thu May  9 15:21:07 2002
@@ -19,7 +19,7 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char * sg_version_str = "Version: 3.5.25 (20020425)";
+ static char * sg_version_str = "Version: 3.5.25 (20020504)";
 #endif
  static int sg_version_num = 30525; /* 2 digits for each component */
 /*
@@ -1640,7 +1640,7 @@
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
 {
 #ifdef SG_ALLOW_DIO_CODE
-    int res, k, split, offset, num, mx_sc_elems, rem_sz;
+    int res, k, j, split, offset, num, mx_sc_elems, rem_sz;
     struct kiobuf * kp;
     char * mem_src_arr;
     struct scatterlist * sclp;
@@ -1648,6 +1648,8 @@
     sg_io_hdr_t * hp = &srp->header;
     Sg_scatter_hold * schp = &srp->data;
     int sg_tablesize = sfp->parentdp->sg_tablesize;
+    unsigned char * pg_addr;
+    unsigned char * hold_pg_addr = NULL;
     int nbhs = 0;
 
     res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
@@ -1690,24 +1692,28 @@
 	return 1;
     }
     mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
-    for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-	 (rem_sz > 0) && (k < mx_sc_elems);
-	 ++k, ++sclp) {
+    for (k = 0, j = 0, sclp = schp->buffer, rem_sz = dxfer_len;
+	 (rem_sz > 0) && (j < mx_sc_elems); ++k) {
 	offset = (0 == k) ? kp->offset : 0;
 	num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
 						rem_sz;
-	sclp->page = kp->maplist[k];
-	sclp->offset = offset;
-	sclp->length = num;
-	mem_src_arr[k] = SG_USER_MEM;
+	pg_addr = page_address(kp->maplist[k]);
+	if ((k > 0) && ((hold_pg_addr + PAGE_SIZE) == pg_addr))
+	    (sclp - 1)->length += num;
+	else {
+	    sclp->page = kp->maplist[k];
+	    sclp->offset = offset;
+	    sclp->length = num;
+	    mem_src_arr[j] = SG_USER_MEM;
+	    ++j;
+	    ++sclp;
+	}
+        hold_pg_addr = pg_addr;
 	rem_sz -= num;
-	SCSI_LOG_TIMEOUT(5,
-	    printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
-	    k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
     }
-    schp->k_use_sg = k;
-    SCSI_LOG_TIMEOUT(5,
-	printk("sg_build_dir: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));
+    schp->k_use_sg = j;
+    SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k_use_sg=%d, k=%d, rem_sz=%d\n",
+		     j, k, rem_sz));
     schp->bufflen = dxfer_len;
     if (rem_sz > 0) {   /* must have failed */
 	sg_unmap_and(schp, 1);
@@ -1854,16 +1860,18 @@
     else {      /* kernel using scatter gather list */
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
+
 	ksglen = (int)sclp->length;
 	p = sg_scatg2virt(sclp);
-
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
 	    if (res) return res;
 
-	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, 
-		 	p = sg_scatg2virt(sclp)) {
+	    for (; k < schp->k_use_sg; ++k, ++sclp) {
+		ksglen = (int)sclp->length; 
+		p = sg_scatg2virt(sclp);
+		if (NULL == p)
+		    break;
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1990,7 +1998,6 @@
 
     if (0 == schp->k_use_sg) {  /* kernel has single buffer */
 	if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */
-
 	    for (j = 0, p = schp->buffer; j < onum; ++j) {
 		res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 		if (res) return res;
@@ -2006,16 +2013,18 @@
     else {      /* kernel using scatter gather list */
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
+
 	ksglen = (int)sclp->length;
 	p = sg_scatg2virt(sclp);
-
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 	    if (res) return res;
 
-	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, 
-		 	p = sg_scatg2virt(sclp)) {
+	    for (; k < schp->k_use_sg; ++k, ++sclp) {
+		ksglen = (int)sclp->length; 
+		p = sg_scatg2virt(sclp);
+		if (NULL == p)
+		    break;
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
diff -Nru a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
--- a/drivers/scsi/sgiwd93.c	Thu May  9 15:21:09 2002
+++ b/drivers/scsi/sgiwd93.c	Thu May  9 15:21:09 2002
@@ -43,22 +43,23 @@
 struct Scsi_Host *sgiwd93_host1 = NULL;
 
 /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
-static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value)
+static inline void write_wd33c93_count(const wd33c93_regs regs,
+				       unsigned long value)
 {
-	regp->SASR = WD_TRANSFER_COUNT_MSB;
-	regp->SCMD = ((value >> 16) & 0xff);
-	regp->SCMD = ((value >>  8) & 0xff);
-	regp->SCMD = ((value >>  0) & 0xff);
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	*regs.SCMD = ((value >> 16) & 0xff);
+	*regs.SCMD = ((value >>  8) & 0xff);
+	*regs.SCMD = ((value >>  0) & 0xff);
 }
 
-static inline unsigned long read_wd33c93_count(wd33c93_regs *regp)
+static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
 {
 	unsigned long value;
 
-	regp->SASR = WD_TRANSFER_COUNT_MSB;
-	value =  ((regp->SCMD & 0xff) << 16);
-	value |= ((regp->SCMD & 0xff) <<  8);
-	value |= ((regp->SCMD & 0xff) <<  0);
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	value =  (*regs.SCMD << 16);
+	value |= (*regs.SCMD <<  8);
+	value |= (*regs.SCMD <<  0);
 	return value;
 }
 
@@ -100,7 +101,7 @@
 static int dma_setup(Scsi_Cmnd *cmd, int datainp)
 {
 	struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
-	wd33c93_regs *regp = hdata->regp;
+	const wd33c93_regs regs = hdata->regs;
 	struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base;
 	struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer;
 
@@ -133,7 +134,7 @@
 		printk(">tlen<%d>", totlen);
 #endif
 		hdata->dma_bounce_len = totlen; /* a trick... */
-		write_wd33c93_count(regp, totlen);
+		write_wd33c93_count(regs, totlen);
 	} else {
 		/* Non-scattered dma. */
 #ifdef DEBUG_DMA
@@ -149,7 +150,7 @@
 		if (cmd->SCp.ptr == NULL)
 			return 1;
 		fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual);
-		write_wd33c93_count(regp, cmd->SCp.this_residual);
+		write_wd33c93_count(regs, cmd->SCp.this_residual);
 	}
 
 	/* To make sure, if we trip an HPC bug, that we transfer
@@ -176,7 +177,7 @@
 		     int status)
 {
 	struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata;
-	wd33c93_regs *regp = hdata->regp;
+	const wd33c93_regs regs = hdata->regs;
 	struct hpc3_scsiregs *hregs;
 
 	if (!SCpnt)
@@ -203,7 +204,7 @@
 
 		/* Yep, we were doing the scatterlist thang. */
 		totlen = hdata->dma_bounce_len;
-		wd93_residual = read_wd33c93_count(regp);
+		wd93_residual = read_wd33c93_count(regs);
 		transferred = totlen - wd93_residual;
 
 #ifdef DEBUG_DMA
@@ -273,6 +274,7 @@
 	struct WD33C93_hostdata *hdata;
 	struct WD33C93_hostdata *hdata1;
 	uchar *buf;
+	wd33c93_regs regs;
 	
 	if(called)
 		return 0; /* Should bitch on the console about this... */
@@ -294,8 +296,9 @@
 	init_hpc_chain(buf);
 	dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
 	/* HPC_SCSI_REG0 | 0x03 | KSEG1 */
-	wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003),
-		     dma_setup, dma_stop, WD33C93_FS_16_20);
+	regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc0003);
+	regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc0007);
+	wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20);
 
 	hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata;
 	hdata->no_sync = 0;
@@ -328,8 +331,10 @@
 			init_hpc_chain(buf);
 			dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
 			/* HPC_SCSI_REG1 | 0x03 | KSEG1 */
-			wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003),
-				     dma_setup, dma_stop, WD33C93_FS_16_20);
+			regs.SASR = (volatile unsigned char *)KSEG1ADDR (0x1fbc8003);
+			regs.SCMD = (volatile unsigned char *)KSEG1ADDR (0x1fbc8007);
+			wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop,
+				     WD33C93_FS_16_20);
 	
 			hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
 			hdata1->no_sync = 0;
diff -Nru a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
--- a/drivers/scsi/sun3_scsi.c	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/sun3_scsi.c	Thu May  9 15:21:02 2002
@@ -609,3 +609,4 @@
 
 #include "scsi_module.c"
 
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
--- a/drivers/scsi/wd33c93.c	Thu May  9 15:21:02 2002
+++ b/drivers/scsi/wd33c93.c	Thu May  9 15:21:02 2002
@@ -349,7 +349,8 @@
    if (cmd->use_sg) {
       cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
       cmd->SCp.buffers_residual = cmd->use_sg - 1;
-      cmd->SCp.ptr = (char *)cmd->SCp.buffer->address;
+      cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+		     cmd->SCp.buffer->offset;
       cmd->SCp.this_residual = cmd->SCp.buffer->length;
       }
    else {
@@ -692,7 +693,8 @@
       ++cmd->SCp.buffer;
       --cmd->SCp.buffers_residual;
       cmd->SCp.this_residual = cmd->SCp.buffer->length;
-      cmd->SCp.ptr = cmd->SCp.buffer->address;
+      cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+		     cmd->SCp.buffer->offset;
       }
 
    write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
@@ -2034,3 +2036,5 @@
 {
    MOD_DEC_USE_COUNT;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/Config.in b/drivers/usb/Config.in
--- a/drivers/usb/Config.in	Thu May  9 15:21:06 2002
+++ b/drivers/usb/Config.in	Thu May  9 15:21:06 2002
@@ -15,7 +15,7 @@
    source drivers/usb/storage/Config.in
 
    source drivers/usb/input/Config.in
- 
+
    source drivers/usb/image/Config.in
 
    source drivers/usb/media/Config.in
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Thu May  9 15:21:09 2002
+++ b/drivers/usb/Makefile	Thu May  9 15:21:09 2002
@@ -17,7 +17,7 @@
 
 subdir-$(CONFIG_USB_ACM)	+= class
 subdir-$(CONFIG_USB_AUDIO)	+= class
-subdir-$(CONFIG_USB_BLUETOOTH)	+= class
+subdir-$(CONFIG_USB_BLUETOOTH_TTY)	+= class
 subdir-$(CONFIG_USB_PRINTER)	+= class
 
 subdir-$(CONFIG_USB_STORAGE)	+= storage
diff -Nru a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
--- a/drivers/usb/class/printer.c	Thu May  9 15:21:03 2002
+++ b/drivers/usb/class/printer.c	Thu May  9 15:21:03 2002
@@ -828,12 +828,12 @@
 	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->writeurb) {
 		err("out of memory");
-		goto abort;
+		goto abort_minor;
 	}
 	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->readurb) {
 		err("out of memory");
-		goto abort;
+		goto abort_minor;
 	}
 
 	/* Malloc device ID string buffer to the largest expected length,
@@ -841,7 +841,7 @@
 	 * could change in length. */
 	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
 		err("out of memory for device_id_string");
-		goto abort;
+		goto abort_minor;
 	}
 
 	/* Malloc write/read buffers in one chunk.  We somewhat wastefully
@@ -849,7 +849,7 @@
 	 * alternate setting can be changed later via an ioctl. */
 	if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) {
 		err("out of memory for buf");
-		goto abort;
+		goto abort_minor;
 	}
 
 	/* Lookup quirks for this printer. */
@@ -863,12 +863,12 @@
 		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
 			dev->descriptor.idVendor,
 			dev->descriptor.idProduct);
-		goto abort;
+		goto abort_minor;
 	}
 
 	/* Setup the selected alternate setting and endpoints. */
 	if (usblp_set_protocol(usblp, protocol) < 0)
-		goto abort;
+		goto abort_minor;
 
 	/* Retrieve and store the device ID string. */
 	usblp_cache_device_id_string(usblp);
@@ -897,6 +897,8 @@
 
 	return usblp;
 
+abort_minor:
+	usb_deregister_dev (&usblp_driver, 1, usblp->minor);
 abort:
 	if (usblp) {
 		usb_free_urb(usblp->writeurb);
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h	Thu May  9 15:21:02 2002
+++ b/drivers/usb/core/hub.h	Thu May  9 15:21:02 2002
@@ -9,6 +9,7 @@
  */
 
 #include <linux/list.h>
+#include <linux/compiler.h>	/* likely()/unlikely() */
 
 /*
  * Hub request types
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Thu May  9 15:21:07 2002
+++ b/drivers/usb/core/usb.c	Thu May  9 15:21:07 2002
@@ -1899,11 +1899,12 @@
 				down(&driver->serialize);
 				driver->disconnect(dev, interface->private_data);
 				up(&driver->serialize);
-				if (driver->owner)
-					__MOD_DEC_USE_COUNT(driver->owner);
 				/* if driver->disconnect didn't release the interface */
 				if (interface->driver)
 					usb_driver_release_interface(driver, interface);
+				/* we don't need the driver any longer */
+				if (driver->owner)
+					__MOD_DEC_USE_COUNT(driver->owner);
 			}
 			/* remove our device node for this interface */
 			put_device(&interface->dev);
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Thu May  9 15:21:08 2002
+++ b/drivers/usb/host/ehci-hcd.c	Thu May  9 15:21:08 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,8 @@
  *
  * 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
@@ -83,7 +85,7 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "$Revision: 0.31 $"
+#define DRIVER_VERSION "2002-May-07"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -582,7 +584,7 @@
 		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:
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Thu May  9 15:21:04 2002
+++ b/drivers/usb/host/ehci-q.c	Thu May  9 15:21:04 2002
@@ -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),
@@ -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,70 +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.
-		 *
-		 * FIXME can simplify: cleanup case is gone now.
+		/* 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;
-
-			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)) {
+		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;
 
-				/* 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
@@ -356,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,
@@ -387,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));
 	}
@@ -737,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;
@@ -748,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;
 	}
@@ -885,7 +873,7 @@
 	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.
@@ -961,6 +949,7 @@
 	}
 	prev->hw_next = qh->hw_next;
 	prev->qh_next = qh->qh_next;
+	wmb ();
 
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
@@ -987,7 +976,7 @@
 				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_put (ehci, qh);
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Thu May  9 15:21:05 2002
+++ b/drivers/usb/host/ehci-sched.c	Thu May  9 15:21:05 2002
@@ -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 ...)
  */
 
 /*
@@ -430,6 +438,7 @@
 					ehci->periodic [frame] =
 						QH_NEXT (qh->qh_dma);
 				}
+				wmb ();
 				frame += period;
 			} while (frame < ehci->periodic_size);
 
@@ -478,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);
 
@@ -825,17 +834,26 @@
 			itd->hw_transaction [uframe & 0x07] = itd->transaction;
 			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
 				itd);
+			wmb ();
 			usecs += itd->usecs;
 
 			itd = list_entry (itd->itd_list.next,
 				struct ehci_itd, itd_list);
 		}
 
-		/* update bandwidth utilization records (for usbfs) */
-		/* FIXME usbcore expects per-frame average, which isn't
-		 * most accurate model... this provides the total claim,
-		 * and expects the average to be computed only display.
+		/* 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 */
diff -Nru a/drivers/usb/host/usb-ohci.c b/drivers/usb/host/usb-ohci.c
--- a/drivers/usb/host/usb-ohci.c	Thu May  9 15:21:04 2002
+++ b/drivers/usb/host/usb-ohci.c	Thu May  9 15:21:04 2002
@@ -83,7 +83,8 @@
 
 
 #ifdef CONFIG_PMAC_PBOOK
-#include <asm/feature.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
 #include <asm/pci-bridge.h>
 #ifndef CONFIG_PM
 #define CONFIG_PM
@@ -2727,12 +2728,12 @@
 	pci_write_config_word (dev, PCI_COMMAND, cmd);
 #ifdef CONFIG_PMAC_PBOOK
 	{
-   	struct device_node	*of_node;
+		struct device_node	*of_node;
 
-	/* Disable USB PAD & cell clock */
-	of_node = pci_device_to_OF_node (ohci->ohci_dev);
-	if (of_node && _machine == _MACH_Pmac)
-		feature_set_usb_power (of_node, 0);
+		/* Disable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
 	}
 #endif
 	return 0;
@@ -2757,12 +2758,12 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 	{
-	struct device_node *of_node;
+		struct device_node *of_node;
 
-	/* Re-enable USB PAD & cell clock */
-	of_node = pci_device_to_OF_node (ohci->ohci_dev);
-	if (of_node && _machine == _MACH_Pmac)
-		feature_set_usb_power (of_node, 1);
+		/* Re-enable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
 	}
 #endif
 
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Thu May  9 15:21:08 2002
+++ b/drivers/usb/input/hid-core.c	Thu May  9 15:21:08 2002
@@ -1396,12 +1396,12 @@
 	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) {
 		strcat(hid->name, buf);
 		if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
-			sprintf(hid->name, "%s %s", hid->name, buf);
+			snprintf(hid->name, 64, "%s %s", hid->name, buf);
 	} else
-		sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
+		snprintf(hid->name, 128, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
 
-	usb_make_path(dev, buf, 63);
-	sprintf(hid->phys, "%s/input%d", buf, ifnum);
+	usb_make_path(dev, buf, 64);
+	snprintf(hid->phys, 64, "%s/input%d", buf, ifnum);
 
 	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
 		hid->uniq[0] = 0;
@@ -1477,20 +1477,20 @@
 {
 	struct hid_device *hid = ptr;
 
+	dbg("cleanup called");
 	usb_unlink_urb(hid->urbin);
 	usb_unlink_urb(hid->urbout);
 	usb_unlink_urb(hid->urbctrl);
 
-	if (hid->claimed & HID_CLAIMED_INPUT)
-		hidinput_disconnect(hid);
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
-		hiddev_disconnect(hid);
-
 	usb_free_urb(hid->urbin);
 	usb_free_urb(hid->urbctrl);
 	if (hid->urbout)
 		usb_free_urb(hid->urbout);
 
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_disconnect(hid);
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_disconnect(hid);
 	hid_free_device(hid);
 }
 
diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c	Thu May  9 15:21:02 2002
+++ b/drivers/usb/net/rtl8150.c	Thu May  9 15:21:02 2002
@@ -19,6 +19,7 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 /* Version Information */
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Thu May  9 15:21:01 2002
+++ b/drivers/usb/net/usbnet.c	Thu May  9 15:21:01 2002
@@ -33,19 +33,32 @@
  * re-enable queues to get higher bandwidth utilization (without needing
  * to tweak MTU for larger packets).
  *
- * Add support for more "network cable" chips; interop with their Win32
- * drivers may be a good thing.  Test the AnchorChip 2720 support..
- * Figure out the initialization protocol used by the Prolific chips,
- * for better robustness ... there's some powerup/reset handshake that's
- * needed when only one end reboots.
- *
- * Use interrupt on PL230x to detect peer connect/disconnect, and call
- * netif_carrier_{on,off} (?) appropriately.  For Net1080, detect peer
- * connect/disconnect with async control messages.
- *
- * Find some way to report "peer connected" network hotplug events; it'll
- * likely mean updating the networking layer.  (This has been discussed
- * on the netdev list...)
+ * - AN2720 ... not widely available, but reportedly works well
+ *
+ * - Belkin/eTEK ... no known issues
+ *
+ * - Both GeneSys and PL-230x use interrupt transfers for driver-to-driver
+ *   handshaking; it'd be worth implementing those as "carrier detect".
+ *   Prefer generic hooks, not minidriver-specific hacks.
+ *
+ * - Linux devices ... the www.handhelds.org SA-1100 support works nicely,
+ *   but the Sharp Zaurus uses an incompatible protocol (extra checksums).
+ *   No reason not to merge the Zaurus protocol here too (got patch? :)
+ *
+ * - For Netchip, use keventd to poll via control requests to detect hardware
+ *   level "carrier detect". 
+ *
+ * - PL-230x ... the initialization protocol doesn't seem to match chip data
+ *   sheets, sometimes it's not needed and sometimes it hangs.  Prolific has
+ *   not responded to repeated support/information requests.
+ *
+ * Interop with more Win32 drivers may be a good thing.
+ *
+ * Seems like reporting "peer connected" (carrier present) events may end
+ * up going through the netlink event system, not hotplug ... that may be
+ * awkward in terms of automatic configuration though.
+ *
+ * There are reports that bridging gives lower-than-usual throughput.
  *
  * Craft smarter hotplug policy scripts ... ones that know how to arrange
  * bridging with "brctl", and can handle static and dynamic ("pump") setups.
@@ -88,6 +101,9 @@
  *		Level of diagnostics is more configurable; they use device
  *		location (usb_device->devpath) instead of address (2.5).
  *		For tx_fixup, memflags can't be NOIO.
+ * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
+ *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
+ *		Use "locally assigned" IEEE802 address space. (Brad Hards)
  *
  *-------------------------------------------------------------------------*/
 
@@ -113,6 +129,7 @@
 #include <linux/usb.h>
 
 
+/* minidrivers _could_ be individually configured */
 #define	CONFIG_USB_AN2720
 #define	CONFIG_USB_BELKIN
 #define	CONFIG_USB_GENESYS
@@ -121,7 +138,7 @@
 #define	CONFIG_USB_PL2301
 
 
-#define DRIVER_VERSION		"26-Apr-2002"
+#define DRIVER_VERSION		"07-May-2002"
 
 /*-------------------------------------------------------------------------*/
 
@@ -185,7 +202,12 @@
 	struct sk_buff_head	txq;
 	struct sk_buff_head	done;
 	struct tasklet_struct	bh;
-	struct tq_struct	ctrl_task;
+
+	struct tq_struct	kevent;
+	unsigned long		flags;
+#		define EVENT_TX_HALT	0
+#		define EVENT_RX_HALT	1
+#		define EVENT_RX_MEMORY	2
 };
 
 // device-specific info used by the driver
@@ -1238,6 +1260,21 @@
 	spin_unlock_irqrestore (&dev->done.lock, flags);
 }
 
+/* some work can't be done in tasklets, so we use keventd
+ *
+ * NOTE:  annoying asymmetry:  if it's active, schedule_task() fails,
+ * but tasklet_schedule() doesn't.  hope the failure is rare.
+ */
+static void defer_kevent (struct usbnet *dev, int work)
+{
+	set_bit (work, &dev->flags);
+	if (!schedule_task (&dev->kevent))
+		err ("%s: kevent %d may have been dropped",
+			dev->net.name, work);
+	else
+		dbg ("%s: kevent %d scheduled", dev->net.name, work);
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void rx_complete (struct urb *urb);
@@ -1264,7 +1301,7 @@
 
 	if ((skb = alloc_skb (size, flags)) == 0) {
 		dbg ("no rx skb");
-		tasklet_schedule (&dev->bh);
+		defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		return;
 	}
@@ -1290,11 +1327,20 @@
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
-	if (netif_running (&dev->net)) {
-		if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
+	if (netif_running (&dev->net)
+			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
+		switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ 
+		case -EPIPE:
+			defer_kevent (dev, EVENT_RX_HALT);
+			break;
+		case -ENOMEM:
+			defer_kevent (dev, EVENT_RX_MEMORY);
+			break;
+		default:
 			dbg ("%s rx submit, %d", dev->net.name, retval);
 			tasklet_schedule (&dev->bh);
-		} else {
+			break;
+		case 0:
 			__skb_queue_tail (&dev->rxq, skb);
 		}
 	} else {
@@ -1368,12 +1414,20 @@
 		}
 		break;
 
+	    // stalls need manual reset. this is rare ... except that
+	    // when going through USB 2.0 TTs, unplug appears this way.
+	    // we avoid the highspeed version of the ETIMEOUT/EILSEQ
+	    // storm, recovering as needed.
+	    case -EPIPE:
+		defer_kevent (dev, EVENT_RX_HALT);
+		// FALLTHROUGH
+
 	    // software-driven interface shutdown
-	    case -ECONNRESET:		// usb-ohci, usb-uhci
-	    case -ECONNABORTED:		// uhci ... for usb-uhci, INTR
-		dbg ("%s shutdown, code %d", dev->net.name, urb_status);
+	    case -ECONNRESET:		// according to API spec
+	    case -ECONNABORTED:		// some (now fixed?) UHCI bugs
+		dbg ("%s rx shutdown, code %d", dev->net.name, urb_status);
 		entry->state = rx_cleanup;
-		// do urb frees only in the tasklet
+		// do urb frees only in the tasklet (UHCI has oopsed ...)
 		entry->urb = urb;
 		urb = 0;
 		break;
@@ -1384,8 +1438,9 @@
 		// FALLTHROUGH
 	    
 	    default:
-		// on unplug we'll get a burst of ETIMEDOUT/EILSEQ
-		// till the khubd gets and handles its interrupt.
+		// on unplug we get ETIMEDOUT (ohci) or EILSEQ (uhci)
+		// until khubd sees its interrupt and disconnects us.
+		// that can easily be hundreds of passes through here.
 		entry->state = rx_cleanup;
 		dev->stats.rx_errors++;
 		dbg ("%s rx: status %d", dev->net.name, urb_status);
@@ -1395,10 +1450,12 @@
 	defer_bh (dev, skb);
 
 	if (urb) {
-		if (netif_running (&dev->net)) {
+		if (netif_running (&dev->net)
+				&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 			rx_submit (dev, urb, GFP_ATOMIC);
 			return;
 		}
+		usb_free_urb (urb);
 	}
 #ifdef	VERBOSE
 	dbg ("no read resubmitted");
@@ -1428,7 +1485,7 @@
 		// during some PM-driven resume scenarios,
 		// these (async) unlinks complete immediately
 		retval = usb_unlink_urb (urb);
-		if (retval < 0)
+		if (retval != -EINPROGRESS && retval != 0)
 			dbg ("unlink urb err, %d", retval);
 		else
 			count++;
@@ -1600,16 +1657,62 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* usb_clear_halt cannot be called in interrupt context */
-
+/* work that cannot be done in interrupt context uses keventd.
+ *
+ * NOTE:  "uhci" and "usb-uhci" may have trouble with this since they don't
+ * queue control transfers to individual devices, and other threads could
+ * trigger control requests concurrently.  hope that's rare.
+ */
 static void
-tx_clear_halt (void *data)
+kevent (void *data)
 {
 	struct usbnet		*dev = data;
+	int			status;
+
+	/* usb_clear_halt() needs a thread context */
+	if (test_bit (EVENT_TX_HALT, &dev->flags)) {
+		unlink_urbs (&dev->txq);
+		status = usb_clear_halt (dev->udev,
+			usb_sndbulkpipe (dev->udev, dev->driver_info->out));
+		if (status < 0)
+			err ("%s: can't clear tx halt, status %d",
+				dev->net.name, status);
+		else {
+			clear_bit (EVENT_TX_HALT, &dev->flags);
+			netif_wake_queue (&dev->net);
+		}
+	}
+	if (test_bit (EVENT_RX_HALT, &dev->flags)) {
+		unlink_urbs (&dev->rxq);
+		status = usb_clear_halt (dev->udev,
+			usb_rcvbulkpipe (dev->udev, dev->driver_info->in));
+		if (status < 0)
+			err ("%s: can't clear rx halt, status %d",
+				dev->net.name, status);
+		else {
+			clear_bit (EVENT_RX_HALT, &dev->flags);
+			tasklet_schedule (&dev->bh);
+		}
+	}
+
+	/* tasklet could resubmit itself forever if memory is tight */
+	if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
+		struct urb	*urb = 0;
+
+		if (netif_running (&dev->net))
+			urb = usb_alloc_urb (0, GFP_KERNEL);
+		else
+			clear_bit (EVENT_RX_MEMORY, &dev->flags);
+		if (urb != 0) {
+			clear_bit (EVENT_RX_MEMORY, &dev->flags);
+			rx_submit (dev, urb, GFP_KERNEL);
+			tasklet_schedule (&dev->bh);
+		}
+	}
 
-	usb_clear_halt (dev->udev,
-		usb_sndbulkpipe (dev->udev, dev->driver_info->out));
-	netif_wake_queue (&dev->net);
+	if (dev->flags)
+		dbg ("%s: kevent done, flags = 0x%lx",
+			dev->net.name, dev->flags);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1620,15 +1723,8 @@
 	struct skb_data		*entry = (struct skb_data *) skb->cb;
 	struct usbnet		*dev = entry->dev;
 
-	if (urb->status == -EPIPE) {
-		if (dev->ctrl_task.sync == 0) {
-			dev->ctrl_task.routine = tx_clear_halt;
-			dev->ctrl_task.data = dev;
-			schedule_task (&dev->ctrl_task);
-		} else {
-			dbg ("Cannot clear TX stall");
-		}
-	}
+	if (urb->status == -EPIPE)
+		defer_kevent (dev, EVENT_TX_HALT);
 	urb->dev = 0;
 	entry->state = tx_done;
 	defer_bh (dev, skb);
@@ -1725,10 +1821,15 @@
 #endif	/* CONFIG_USB_NET1080 */
 
 	netif_stop_queue (net);
-	if ((retval = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
+	switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
+	case -EPIPE:
+		defer_kevent (dev, EVENT_TX_HALT);
+		break;
+	default:
 		netif_start_queue (net);
 		dbg ("%s tx: submit urb err %d", net->name, retval);
-	} else {
+		break;
+	case 0:
 		net->trans_start = jiffies;
 		__skb_queue_tail (&dev->txq, skb);
 		if (dev->txq.qlen < TX_QLEN)
@@ -1799,7 +1900,8 @@
 		}
 
 	// or are we maybe short a few urbs?
-	} else if (netif_running (&dev->net)) {
+	} else if (netif_running (&dev->net)
+			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 		int	temp = dev->rxq.qlen;
 
 		if (temp < RX_QLEN) {
@@ -1845,6 +1947,9 @@
 	list_del (&dev->dev_list);
 	mutex_unlock (&usbnet_mutex);
 
+	// assuming we used keventd, it must quiesce too
+	flush_scheduled_tasks ();
+
 	kfree (dev);
 	usb_dec_dev_use (udev);
 }
@@ -1902,6 +2007,7 @@
 	skb_queue_head_init (&dev->done);
 	dev->bh.func = usbnet_bh;
 	dev->bh.data = (unsigned long) dev;
+	INIT_TQUEUE (&dev->kevent, kevent, dev);
 
 	// set up network interface records
 	net = &dev->net;
@@ -2038,6 +2144,7 @@
 
 	get_random_bytes (node_id, sizeof node_id);
 	node_id [0] &= 0xfe;	// clear multicast bit
+	node_id [0] |= 0x02;    // set local assignment bit (IEEE802)
 
  	if (usb_register (&usbnet_driver) < 0)
  		return -1;
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Thu May  9 15:21:07 2002
+++ b/drivers/usb/serial/pl2303.c	Thu May  9 15:21:07 2002
@@ -73,6 +73,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
--- a/drivers/usb/serial/pl2303.h	Thu May  9 15:21:08 2002
+++ b/drivers/usb/serial/pl2303.h	Thu May  9 15:21:08 2002
@@ -16,3 +16,6 @@
 
 #define IODATA_VENDOR_ID	0x04bb
 #define IODATA_PRODUCT_ID	0x0a03
+
+#define ELCOM_VENDOR_ID		0x056e
+#define ELCOM_PRODUCT_ID	0x5003
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Thu May  9 15:21:06 2002
+++ b/drivers/usb/serial/usbserial.c	Thu May  9 15:21:06 2002
@@ -1665,7 +1665,7 @@
 #if 0
 static kdev_t usb_console_device(struct console *co)
 {
-	return MKDEV(SERIAL_TTY_MAJOR, co->index);	/* TBD */
+	return mk_kdev(SERIAL_TTY_MAJOR, co->index);	/* TBD */
 }
 #endif
 
diff -Nru a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
--- a/drivers/zorro/zorro.c	Thu May  9 15:21:01 2002
+++ b/drivers/zorro/zorro.c	Thu May  9 15:21:01 2002
@@ -124,13 +124,13 @@
      *  Initialization
      */
 
-void __init zorro_init(void)
+static int __init zorro_init(void)
 {
     struct zorro_dev *dev;
     u_int i;
 
     if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
-	return;
+	return 0;
 
     printk("Zorro: Probing AutoConfig expansion devices: %d device%s\n",
 	   zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
@@ -168,6 +168,8 @@
 	if (m68k_memory[i].addr < 16*1024*1024)
 	    mark_region(m68k_memory[i].addr,
 			m68k_memory[i].addr+m68k_memory[i].size, 0);
+
+    return 0;
 }
 
 subsys_initcall(zorro_init);
diff -Nru a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids
--- a/drivers/zorro/zorro.ids	Thu May  9 15:21:09 2002
+++ b/drivers/zorro/zorro.ids	Thu May  9 15:21:09 2002
@@ -4,7 +4,7 @@
 #	Maintained by Geert Uytterhoeven <zorro@linux-m68k.org>
 #	If you have any new entries, please send them to the maintainer.
 #
-#	$Id: zorro.ids,v 1.16 2000/09/28 18:45:47 geert Exp $
+#	$Id: zorro.ids,v 1.17 2001/10/25 08:21:39 geert Exp $
 #
 
 # Manufacturers and Products. Please keep sorted.
@@ -229,6 +229,7 @@
 	0a00  Impact Series II [RAM Expansion]
 081e  Interworks Network
 0820  Hardital Synthesis
+	0100  Super Big Bang [Accelerator, SCSI Host Adapter and RAM Expansion]
 	1400  TQM 68030+68882 [Accelerator]
 0828  Applied Engineering
 	1000  DL2000 [Modem]
@@ -383,7 +384,7 @@
 	ff00  Pixel64 RAM [Graphics Card]
 1212  Individual Computers
 	0000  Buddha [IDE Interface]
-	1700  X-Surf [Ethernet Card]
+	1700  X-Surf [Ethernet Card and IDE Interface]
 	2a00  Catweasel [IDE Interface and Floppy Controller]
 1248  Kupke
 	0100  Golem HD 3000 [HD Controller]
diff -Nru a/fs/affs/Changes b/fs/affs/Changes
--- a/fs/affs/Changes	Thu May  9 15:21:08 2002
+++ b/fs/affs/Changes	Thu May  9 15:21:08 2002
@@ -28,6 +28,12 @@
 
 Please direct bug reports to: zippel@linux-m68k.org
 
+Version 3.19
+------------
+
+- sizeof changes from Kernel Janitor Project
+- several bug fixes found with fsx
+
 Version 3.18
 ------------
 
diff -Nru a/fs/affs/bitmap.c b/fs/affs/bitmap.c
--- a/fs/affs/bitmap.c	Thu May  9 15:21:09 2002
+++ b/fs/affs/bitmap.c	Thu May  9 15:21:09 2002
@@ -296,7 +296,7 @@
 	sbi->s_bmap_bits = sb->s_blocksize * 8 - 32;
 	sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved +
 				 sbi->s_bmap_bits - 1) / sbi->s_bmap_bits;
-	size = sbi->s_bmap_count * sizeof(struct affs_bm_info);
+	size = sbi->s_bmap_count * sizeof(*bm);
 	bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL);
 	if (!sbi->s_bitmap) {
 		printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
diff -Nru a/fs/affs/file.c b/fs/affs/file.c
--- a/fs/affs/file.c	Thu May  9 15:21:07 2002
+++ b/fs/affs/file.c	Thu May  9 15:21:07 2002
@@ -507,7 +507,7 @@
 static int
 affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
 	char *data;
@@ -515,6 +515,8 @@
 	u32 tmp;
 
 	pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+	if (from > to || to > PAGE_CACHE_SIZE)
+		BUG();
 	data = page_address(page);
 	bsize = AFFS_SB(sb)->s_data_blksize;
 	tmp = (page->index << PAGE_CACHE_SHIFT) + from;
@@ -525,7 +527,9 @@
 		bh = affs_bread_ino(inode, bidx, 0);
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
-		tmp = min(bsize - boff, from - to);
+		tmp = min(bsize - boff, to - from);
+		if (from + tmp > to || tmp > bsize)
+			BUG();
 		memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
 		affs_brelse(bh);
 		bidx++;
@@ -536,9 +540,8 @@
 }
 
 static int
-affs_extent_file_ofs(struct file *file, u32 newsize)
+affs_extent_file_ofs(struct inode *inode, u32 newsize)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh, *prev_bh;
 	u32 bidx, boff;
@@ -548,7 +551,7 @@
 	pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
 	bsize = AFFS_SB(sb)->s_data_blksize;
 	bh = NULL;
-	size = inode->i_size;
+	size = AFFS_I(inode)->mmu_private;
 	bidx = size / bsize;
 	boff = size % bsize;
 	if (boff) {
@@ -556,6 +559,8 @@
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
 		tmp = min(bsize - boff, newsize - size);
+		if (boff + tmp > bsize || tmp > bsize)
+			BUG();
 		memset(AFFS_DATA(bh) + boff, 0, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -574,18 +579,21 @@
 		if (IS_ERR(bh))
 			goto out;
 		tmp = min(bsize, newsize - size);
+		if (tmp > bsize)
+			BUG();
 		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 		affs_fix_checksum(sb, bh);
+		bh->b_state &= ~(1UL << BH_New);
 		mark_buffer_dirty_inode(bh, inode);
 		if (prev_bh) {
 			u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 			if (tmp)
-				affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+				affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
 			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-			affs_adjust_checksum(prev_bh, bidx - tmp);
+			affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 			mark_buffer_dirty_inode(prev_bh, inode);
 			affs_brelse(prev_bh);
 		}
@@ -593,18 +601,18 @@
 		bidx++;
 	}
 	affs_brelse(bh);
-	inode->i_size = AFFS_I(inode)->mmu_private = size;
+	inode->i_size = AFFS_I(inode)->mmu_private = newsize;
 	return 0;
 
 out:
-	inode->i_size = AFFS_I(inode)->mmu_private = size;
+	inode->i_size = AFFS_I(inode)->mmu_private = newsize;
 	return PTR_ERR(bh);
 }
 
 static int
 affs_readpage_ofs(struct file *file, struct page *page)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	u32 to;
 	int err;
 
@@ -624,22 +632,22 @@
 
 static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	u32 size, offset;
 	u32 tmp;
 	int err = 0;
 
 	pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
-	if (PageUptodate(page))
-		return 0;
-
-	size = inode->i_size;
 	offset = page->index << PAGE_CACHE_SHIFT;
-	if (offset + from > size) {
-		err = affs_extent_file_ofs(file, offset + from);
+	if (offset + from > AFFS_I(inode)->mmu_private) {
+		err = affs_extent_file_ofs(inode, offset + from);
 		if (err)
 			return err;
 	}
+	size = inode->i_size;
+
+	if (PageUptodate(page))
+		return 0;
 
 	if (from) {
 		err = affs_do_readpage_ofs(file, page, 0, from);
@@ -650,7 +658,7 @@
 		memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
 		if (size > offset + to) {
 			if (size < offset + PAGE_CACHE_SIZE)
-				tmp = size & PAGE_CACHE_MASK;
+				tmp = size & ~PAGE_CACHE_MASK;
 			else
 				tmp = PAGE_CACHE_SIZE;
 			err = affs_do_readpage_ofs(file, page, to, tmp);
@@ -661,7 +669,7 @@
 
 static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode = page->mapping->host;
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh, *prev_bh;
 	char *data;
@@ -683,6 +691,8 @@
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
 		tmp = min(bsize - boff, to - from);
+		if (boff + tmp > bsize || tmp > bsize)
+			BUG();
 		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -707,12 +717,13 @@
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
 			AFFS_DATA_HEAD(bh)->next = 0;
+			bh->b_state &= ~(1UL << BH_New);
 			if (prev_bh) {
 				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 				if (tmp)
-					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-				affs_adjust_checksum(prev_bh, bidx - tmp);
+				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 				mark_buffer_dirty_inode(prev_bh, inode);
 			}
 		}
@@ -729,6 +740,8 @@
 		if (IS_ERR(bh))
 			goto out;
 		tmp = min(bsize, to - from);
+		if (tmp > bsize)
+			BUG();
 		memcpy(AFFS_DATA(bh), data + from, tmp);
 		if (buffer_new(bh)) {
 			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
@@ -736,12 +749,13 @@
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
 			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
 			AFFS_DATA_HEAD(bh)->next = 0;
+			bh->b_state &= ~(1UL << BH_New);
 			if (prev_bh) {
 				u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
 				if (tmp)
-					affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+					affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
 				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
-				affs_adjust_checksum(prev_bh, bidx - tmp);
+				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
 				mark_buffer_dirty_inode(prev_bh, inode);
 			}
 		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
@@ -805,9 +819,9 @@
 	struct buffer_head *ext_bh;
 	int i;
 
-	pr_debug("AFFS: truncate(inode=%d, size=%u)\n", (u32)inode->i_ino, (u32)inode->i_size);
+	pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+		 (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size);
 
-	lock_kernel();
 	last_blk = 0;
 	ext = 0;
 	if (inode->i_size) {
@@ -822,10 +836,8 @@
 		int res;
 
 		page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
-		if (!page) {
-			unlock_kernel();
+		if (!page)
 			return;
-		}
 		size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
 		res = mapping->a_ops->prepare_write(NULL, page, size, size);
 		if (!res)
@@ -833,19 +845,25 @@
 		unlock_page(page);
 		page_cache_release(page);
 		mark_inode_dirty(inode);
-		unlock_kernel();
 		return;
-	} else if (inode->i_size == AFFS_I(inode)->mmu_private) {
-		unlock_kernel();
+	} else if (inode->i_size == AFFS_I(inode)->mmu_private)
 		return;
-	}
 
 	// lock cache
 	ext_bh = affs_get_extblock(inode, ext);
+	if (IS_ERR(ext_bh)) {
+		affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",
+			     ext, PTR_ERR(ext_bh));
+		return;
+	}
 	if (AFFS_I(inode)->i_lc) {
 		/* clear linear cache */
-		for (i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; i < AFFS_LC_SIZE; i++)
-			AFFS_I(inode)->i_lc[i] = 0;
+		i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;
+		if (AFFS_I(inode)->i_lc_size > i) {
+			AFFS_I(inode)->i_lc_size = i;
+			for (; i < AFFS_LC_SIZE; i++)
+				AFFS_I(inode)->i_lc[i] = 0;
+		}
 		/* clear associative cache */
 		for (i = 0; i < AFFS_AC_SIZE; i++)
 			if (AFFS_I(inode)->i_ac[i].ext >= ext)
@@ -876,6 +894,19 @@
 	if (inode->i_size) {
 		AFFS_I(inode)->i_blkcnt = last_blk + 1;
 		AFFS_I(inode)->i_extcnt = ext + 1;
+		if (AFFS_SB(sb)->s_flags & SF_OFS) {
+			struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
+			u32 tmp;
+			if (IS_ERR(ext_bh)) {
+				affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
+					     ext, PTR_ERR(ext_bh));
+				return;
+			}
+			tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
+			AFFS_DATA_HEAD(bh)->next = 0;
+			affs_adjust_checksum(bh, -tmp);
+			affs_brelse(bh);
+		}
 	} else {
 		AFFS_I(inode)->i_blkcnt = 0;
 		AFFS_I(inode)->i_extcnt = 1;
@@ -894,5 +925,5 @@
 		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
 		affs_brelse(ext_bh);
 	}
-	unlock_kernel();
+	affs_free_prealloc(inode);
 }
diff -Nru a/fs/affs/super.c b/fs/affs/super.c
--- a/fs/affs/super.c	Thu May  9 15:21:08 2002
+++ b/fs/affs/super.c	Thu May  9 15:21:08 2002
@@ -111,7 +111,7 @@
 		inode_init_once(&ei->vfs_inode);
 	}
 }
- 
+
 static int init_inodecache(void)
 {
 	affs_inode_cachep = kmem_cache_create("affs_inode_cache",
@@ -299,7 +299,7 @@
 	if (!sbi)
 		return -ENOMEM;
 	sb->u.generic_sbp = sbi;
-	memset(sbi, 0, sizeof(struct affs_sb_info));
+	memset(sbi, 0, sizeof(*AFFS_SB));
 	init_MUTEX(&sbi->s_bmlock);
 
 	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Thu May  9 15:21:02 2002
+++ b/fs/dcache.c	Thu May  9 15:21:02 2002
@@ -812,6 +812,7 @@
 	struct dentry *new = NULL;
 
 	if (inode && S_ISDIR(inode->i_mode)) {
+		lock_kernel(); /* for d_move */
 		spin_lock(&dcache_lock);
 		if (!list_empty(&inode->i_dentry)) {
 			new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
@@ -827,6 +828,7 @@
 			spin_unlock(&dcache_lock);
 			d_rehash(dentry);
 		}
+		unlock_kernel();
 	} else
 		d_add(dentry, inode);
 	return new;
diff -Nru a/fs/dnotify.c b/fs/dnotify.c
--- a/fs/dnotify.c	Thu May  9 15:21:05 2002
+++ b/fs/dnotify.c	Thu May  9 15:21:05 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 -Nru a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c	Thu May  9 15:21:04 2002
+++ b/fs/exportfs/expfs.c	Thu May  9 15:21:04 2002
@@ -3,39 +3,44 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 
+struct export_operations export_op_default;
+
+#define	CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
+
+#define dprintk(fmt, args...) do{}while(0)
+
 /**
  * find_exported_dentry - helper routine to implement export_operations->decode_fh
  * @sb:		The &super_block identifying the filesystem
- * @obj:	An opaque identifier of the object to be found - passed to get_inode
+ * @obj:	An opaque identifier of the object to be found - passed to
+ *		get_inode
  * @parent:	An optional opqaue identifier of the parent of the object.
- * @acceptable:	A function used to test possible &dentries to see of they are acceptable
- * @context:	A parameter to @acceptable so that it knows on what basis to judge.
- *
- * find_exported_dentry is the central helper routine to enable file systems to provide
- * the decode_fh() export_operation.  It's main task is to take an &inode, find or create an
- * appropriate &dentry structure, and possibly splice this into the dcache in the
- * correct place.
+ * @acceptable:	A function used to test possible &dentries to see if they are
+ *		acceptable
+ * @context:	A parameter to @acceptable so that it knows on what basis to
+ *		judge.
  *
- * The decode_fh() operation provided by the filesystem should call find_exported_dentry()
- * with the same parameters that it received except that instead of the file handle fragment,
- * pointers to opaque identifiers for the object and optionally its parent are passed.
- * The default decode_fh routine passes one pointer to the start of the filehandle fragment, and
- * one 8 bytes into the fragment.  It is expected that most filesystems will take this
- * approach, though the offset to the parent identifier may well be different.
+ * find_exported_dentry is the central helper routine to enable file systems
+ * to provide the decode_fh() export_operation.  It's main task is to take
+ * an &inode, find or create an appropriate &dentry structure, and possibly
+ * splice this into the dcache in the correct place.
  *
- * find_exported_dentry() will call get_dentry to get an dentry pointer from the file system.  If
- * any &dentry in the d_alias list is acceptable, it will be returned.  Otherwise
- * find_exported_dentry() will attempt to splice a new &dentry into the dcache using get_name() and
- * get_parent() to find the appropriate place.
+ * The decode_fh() operation provided by the filesystem should call
+ * find_exported_dentry() with the same parameters that it received except
+ * that instead of the file handle fragment, pointers to opaque identifiers
+ * for the object and optionally its parent are passed.  The default decode_fh
+ * routine passes one pointer to the start of the filehandle fragment, and
+ * one 8 bytes into the fragment.  It is expected that most filesystems will
+ * take this approach, though the offset to the parent identifier may well be
+ * different.
  *
+ * find_exported_dentry() will call get_dentry to get an dentry pointer from
+ * the file system.  If any &dentry in the d_alias list is acceptable, it will
+ * be returned.  Otherwise find_exported_dentry() will attempt to splice a new
+ * &dentry into the dcache using get_name() and get_parent() to find the
+ * appropriate place.
  */
 
-struct export_operations export_op_default;
-
-#define	CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
-
-#define dprintk(x, a...) do{}while(0)
-
 struct dentry *
 find_exported_dentry(struct super_block *sb, void *obj, void *parent,
 		     int (*acceptable)(void *context, struct dentry *de),
@@ -123,12 +128,12 @@
 	 * We then repeat.
 	 */
 
-	/* it is possible that a confused file system might not let us complete the
-	 * path to the root.  For example, if get_parent returns a directory
-	 * in which we cannot find a name for the child.  While this implies a very
-	 * sick filesystem we don't want it to cause knfsd to spin.  Hence the noprogress
-	 * counter.  If we go through the loop 10 times (2 is probably enough) without
-	 * getting anywhere, we just give up
+	/* it is possible that a confused file system might not let us complete 
+	 * the path to the root.  For example, if get_parent returns a directory
+	 * in which we cannot find a name for the child.  While this implies a
+	 * very sick filesystem we don't want it to cause knfsd to spin.  Hence
+	 * the noprogress counter.  If we go through the loop 10 times (2 is
+	 * probably enough) without getting anywhere, we just give up
 	 */
 	lock_kernel();
 	noprogress= 0;
@@ -155,8 +160,8 @@
 			 * to find parent and connect
 			 * note: racing with some other process renaming a
 			 * directory isn't much of a problem here.  If someone
-			 * renames the directory, it will end up properly connected,
-			 * which is what we want
+			 * renames the directory, it will end up properly
+			 * connected, which is what we want
 			 */
 			struct dentry *ppd;
 			struct dentry *npd;
@@ -178,8 +183,8 @@
 			if (err) {
 				dput(ppd);
 				if (err == -ENOENT)
-					/* some race between get_parent and get_name?
-					 * just try again
+					/* some race between get_parent and
+					 * get_name?  just try again
 					 */
 					continue;
 				dput(pd);
@@ -208,7 +213,7 @@
 			dput(npd);
 			dput(ppd);
 			if (IS_ROOT(pd)) {
-				/* something went wrong, we will have to give up */
+				/* something went wrong, we have to give up */
 				dput(pd);
 				break;
 			}
@@ -293,7 +298,8 @@
 
 
 struct getdents_callback {
-	char *name;		/* name that was found. It already points to a buffer NAME_MAX+1 is size */
+	char *name;		/* name that was found. It already points to a
+				   buffer NAME_MAX+1 is size */
 	unsigned long ino;	/* the inum we are looking for */
 	int found;		/* inode matched? */
 	int sequence;		/* sequence counter */
@@ -386,11 +392,11 @@
 	/* iget isn't really right if the inode is currently unallocated!!
 	 * This should really all be done inside each filesystem
 	 *
-	 * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
-	 *   had been deleted.
+	 * ext2fs' read_inode has been strengthed to return a bad_inode if
+	 * the inode had been deleted.
 	 *
-	 * Currently we don't know the generation for parent directory, so a generation
-	 * of 0 means "accept any"
+	 * Currently we don't know the generation for parent directory, so
+	 * a generation of 0 means "accept any"
 	 */
 	struct inode *inode;
 	struct dentry *result;
@@ -437,10 +443,10 @@
 
 /**
  * export_encode_fh - default export_operations->encode_fh function
- * dentry:  the dentry to encode
- * fh:      where to store the file handle fragment
- * max_len: maximum length to store there
- * connectable: whether to store parent infomation
+ * @dentry:  the dentry to encode
+ * @fh:      where to store the file handle fragment
+ * @max_len: maximum length to store there
+ * @connectable: whether to store parent infomation
  *
  * This default encode_fh function assumes that the 32 inode number
  * is suitable for locating an inode, and that the generation number
@@ -474,11 +480,11 @@
 
 /**
  * export_decode_fh - default export_operations->decode_fh function
- * sb:  The superblock
- * fh:  pointer to the file handle fragment
- * fh_len: length of file handle fragment
- * acceptable: function for testing acceptability of dentrys
- * context:   context for @acceptable
+ * @sb:  The superblock
+ * @fh:  pointer to the file handle fragment
+ * @fh_len: length of file handle fragment
+ * @acceptable: function for testing acceptability of dentrys
+ * @context:   context for @acceptable
  *
  * This is the default decode_fh() function.
  * a fileid_type of 1 indicates that the filehandlefragment
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
--- a/fs/ext3/namei.c	Thu May  9 15:21:08 2002
+++ b/fs/ext3/namei.c	Thu May  9 15:21:08 2002
@@ -220,9 +220,48 @@
 		}
 	}
 	unlock_kernel();
+	if (inode)
+		return d_splice_alias(inode, dentry);
 	d_add(dentry, inode);
 	return NULL;
 }
+
+
+struct dentry *ext3_get_parent(struct dentry *child)
+{
+	unsigned long ino;
+	struct dentry *parent;
+	struct inode *inode;
+	struct dentry dotdot;
+	struct ext3_dir_entry_2 * de;
+	struct buffer_head *bh;
+
+	dotdot.d_name.name = "..";
+	dotdot.d_name.len = 2;
+	dotdot.d_parent = child; /* confusing, isn't it! */
+
+	lock_kernel();
+	bh = ext3_find_entry(&dotdot, &de);
+	inode = NULL;
+	if (!bh) {
+		unlock_kernel();
+		return ERR_PTR(-ENOENT);
+	}
+	ino = le32_to_cpu(de->inode);
+	brelse(bh);
+	inode = iget(child->d_inode->i_sb, ino);
+	unlock_kernel();
+
+	if (!inode)
+		return ERR_PTR(-EACCES);
+
+	parent = d_alloc_anon(inode);
+	if (!parent) {
+		iput(inode);
+		parent = ERR_PTR(-ENOMEM);
+	}
+	return parent;
+} 
 
 #define S_SHIFT 12
 static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = {
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Thu May  9 15:21:09 2002
+++ b/fs/ext3/super.c	Thu May  9 15:21:09 2002
@@ -508,6 +508,12 @@
 	remount_fs:	ext3_remount,		/* BKL held */
 };
 
+struct dentry *ext3_get_parent(struct dentry *child);
+static struct export_operations ext3_export_ops = {
+	get_parent: ext3_get_parent,
+};
+
+
 static int want_value(char *value, char *option)
 {
 	if (!value || !*value) {
@@ -1157,6 +1163,7 @@
 	 * set up enough so that it can read an inode
 	 */
 	sb->s_op = &ext3_sops;
+	sb->s_export_op = &ext3_export_ops;
 	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
 
 	sb->s_root = 0;
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Thu May  9 15:21:06 2002
+++ b/fs/fat/inode.c	Thu May  9 15:21:06 2002
@@ -438,20 +438,26 @@
  *  4/  parent->i_logstart - maybe used to hunt for the file on disc
  *
  */
-struct dentry *fat_fh_to_dentry(struct super_block *sb, __u32 *fh,
-				int len, int fhtype, int parent)
+
+struct dentry *fat_decode_fh(struct super_block *sb, __u32 *fh,
+			     int len, int fhtype, 
+			     int (*acceptable)(void *context, struct dentry *de),
+			     void *context)
 {
-	struct inode *inode = NULL;
-	struct dentry *result;
 
 	if (fhtype != 3)
 		return ERR_PTR(-ESTALE);
 	if (len < 5)
 		return ERR_PTR(-ESTALE);
-	/* We cannot find the parent,
-	   It better just *be* there */
-	if (parent)
-		return ERR_PTR(-ESTALE);
+
+	return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
+}
+
+struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
+{
+	struct inode *inode = NULL;
+	struct dentry *result;
+	__u32 *fh = inump;
 
 	inode = iget(sb, fh[0]);
 	if (!inode || is_bad_inode(inode) ||
@@ -497,12 +503,13 @@
 		iput(inode);
 		return ERR_PTR(-ENOMEM);
 	}
+	result->d_op = sb->s_root->d_op;
 	result->d_vfs_flags |= DCACHE_REFERENCED;
 	return result;
 		
 }
 
-int fat_dentry_to_fh(struct dentry *de, __u32 *fh, int *lenp, int needparent)
+int fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
 {
 	int len = *lenp;
 	struct inode *inode =  de->d_inode;
@@ -520,6 +527,43 @@
 	return 3;
 }
 
+struct dentry *fat_get_parent(struct dentry *child)
+{
+	struct buffer_head *bh=NULL;
+	struct msdos_dir_entry *de = NULL;
+	struct dentry *parent = NULL;
+	int res;
+	int ino = 0;
+	struct inode *inode;
+
+	lock_kernel();
+	res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &ino);
+
+	if (res < 0)
+		goto out;
+	inode = fat_build_inode(child->d_sb, de, ino, &res);
+	if (res)
+		goto out;
+	if (!inode)
+		res = -EACCES;
+	else {
+		parent = d_alloc_anon(inode);
+		if (!parent) {
+			iput(inode);
+			res = -ENOMEM;
+		}
+	}
+
+ out:
+	if(bh)
+		fat_brelse(child->d_sb, bh);
+	unlock_kernel();
+	if (res)
+		return ERR_PTR(res);
+	else
+		return parent;
+}
+
 static kmem_cache_t *fat_inode_cachep;
 
 static struct inode *fat_alloc_inode(struct super_block *sb)
@@ -574,8 +618,13 @@
 	clear_inode:	fat_clear_inode,
 
 	read_inode:	make_bad_inode,
-	fh_to_dentry:	fat_fh_to_dentry,
-	dentry_to_fh:	fat_dentry_to_fh,
+};
+
+static struct export_operations fat_export_ops = {
+	decode_fh:	fat_decode_fh,
+	encode_fh:	fat_encode_fh,
+	get_dentry:	fat_get_dentry,
+	get_parent:	fat_get_parent,
 };
 
 /*
@@ -609,6 +658,7 @@
 
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
+	sb->s_export_op = &fat_export_ops;
 	sbi->options.isvfat = isvfat;
 	sbi->dir_ops = fs_dir_inode_ops;
 	sbi->cvf_format = &default_cvf;
diff -Nru a/fs/jffs/Makefile b/fs/jffs/Makefile
--- a/fs/jffs/Makefile	Thu May  9 15:21:01 2002
+++ b/fs/jffs/Makefile	Thu May  9 15:21:01 2002
@@ -4,21 +4,20 @@
 # $Id: Makefile,v 1.11 2001/09/25 20:59:41 dwmw2 Exp $
 #
 
-jffs-objs := jffs_fm.o intrep.o
+obj-y := jffs_fm.o intrep.o
 
 ifeq ($(PATCHLEVEL),2)
-	jffs-objs += inode-v22.o
+	obj-y += inode-v22.o
 else
-	jffs-objs += inode-v23.o
+	obj-y += inode-v23.o
 endif
 
 ifeq ($(CONFIG_JFFS_PROC_FS),y)
-	jffs-objs += jffs_proc.o
+	obj-y += jffs_proc.o
 endif
 
 O_TARGET := jffs.o
 
-obj-y := $(jffs-objs)
 obj-m := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Thu May  9 15:21:07 2002
+++ b/fs/jfs/jfs_logmgr.c	Thu May  9 15:21:07 2002
@@ -1386,6 +1386,35 @@
 
 
 /*
+ * NAME:	lmLogWait()
+ *
+ * FUNCTION:	wait for all outstanding log records to be written to disk
+ */
+void lmLogWait(log_t *log)
+{
+	int i;
+
+	jFYI(1, ("lmLogWait: log:0x%p\n", log));
+
+	if (log->cqueue.head || !list_empty(&log->synclist)) {
+		/*
+		 * If there was very recent activity, we may need to wait
+		 * for the lazycommit thread to catch up
+		 */
+
+		for (i = 0; i < 800; i++) {	/* Too much? */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ / 4);
+			if ((log->cqueue.head == NULL) &&
+			    list_empty(&log->synclist))
+				break;
+		}
+	}
+	assert(log->cqueue.head == NULL);
+	assert(list_empty(&log->synclist));
+}
+
+/*
  * NAME:	lmLogShutdown()
  *
  * FUNCTION:	log shutdown at last LogClose().
@@ -1411,23 +1440,7 @@
 
 	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
 
-	if (log->cqueue.head || !list_empty(&log->synclist)) {
-		/*
-		 * If there was very recent activity, we may need to wait
-		 * for the lazycommit thread to catch up
-		 */
-		int i;
-
-		for (i = 0; i < 800; i++) {	/* Too much? */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ / 4);
-			if ((log->cqueue.head == NULL) &&
-			    list_empty(&log->synclist))
-				break;
-		}
-	}
-	assert(log->cqueue.head == NULL);
-	assert(list_empty(&log->synclist));
+	lmLogWait(log);
 
 	/*
 	 * We need to make sure all of the "written" metapages
diff -Nru a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
--- a/fs/jfs/jfs_logmgr.h	Thu May  9 15:21:04 2002
+++ b/fs/jfs/jfs_logmgr.h	Thu May  9 15:21:04 2002
@@ -489,6 +489,7 @@
 }
 
 extern int lmLogOpen(struct super_block *sb, log_t ** log);
+extern void lmLogWait(log_t * log);
 extern int lmLogClose(struct super_block *sb, log_t * log);
 extern int lmLogSync(log_t * log, int nosyncwait);
 extern int lmLogQuiesce(log_t * log);
diff -Nru a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
--- a/fs/jfs/jfs_umount.c	Thu May  9 15:21:00 2002
+++ b/fs/jfs/jfs_umount.c	Thu May  9 15:21:00 2002
@@ -64,15 +64,11 @@
 	 *
 	 * if mounted read-write and log based recovery was enabled
 	 */
-	if ((log = sbi->log)) {
+	if ((log = sbi->log))
 		/*
-		 * close log: 
-		 *
-		 * remove file system from log active file system list.
+		 * Wait for outstanding transactions to be written to log: 
 		 */
-		log = sbi->log;
-		rc = lmLogClose(sb, log);
-	}
+		lmLogWait(log);
 
 	/*
 	 * close fileset inode allocation map (aka fileset inode)
@@ -113,6 +109,14 @@
 	sbi->ipimap = NULL;
 
 	/*
+	 * Make sure all metadata makes it to disk before we mark
+	 * the superblock as clean
+	 */
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+
+	/*
 	 * ensure all file system file pages are propagated to their
 	 * home blocks on disk (and their in-memory buffer pages are 
 	 * invalidated) BEFORE updating file system superblock state
@@ -120,10 +124,16 @@
 	 * consistent state) and log superblock active file system 
 	 * list (to signify skip logredo()).
 	 */
-	if (log)		/* log = NULL if read-only mount */
+	if (log) {		/* log = NULL if read-only mount */
 		rc = updateSuper(sb, FM_CLEAN);
 
-
+		/*
+		 * close log: 
+		 *
+		 * remove file system from log active file system list.
+		 */
+		rc = lmLogClose(sb, log);
+	}
 	jFYI(0, ("	UnMount JFS Complete: %d\n", rc));
 	return rc;
 }
@@ -132,8 +142,9 @@
 int jfs_umount_rw(struct super_block *sb)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	log_t *log = sbi->log;
 
-	if (!sbi->log)
+	if (!log)
 		return 0;
 
 	/*
@@ -141,13 +152,19 @@
 	 *
 	 * remove file system from log active file system list.
 	 */
-	lmLogClose(sb, sbi->log);
+	lmLogWait(log);
 
+	/*
+	 * Make sure all metadata makes it to disk
+	 */
 	dbSync(sbi->ipbmap);
 	diSync(sbi->ipimap);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
 
-	sbi->log = 0;
+	updateSuper(sb, FM_CLEAN);
+	sbi->log = NULL;
 
-	return updateSuper(sb, FM_CLEAN);
-       
+	return lmLogClose(sb, log);
 }
diff -Nru a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
--- a/fs/lockd/svc4proc.c	Thu May  9 15:21:05 2002
+++ b/fs/lockd/svc4proc.c	Thu May  9 15:21:05 2002
@@ -537,31 +537,35 @@
    0,					\
    respsize,				\
  }
+#define	Ck	(1+8)	/* cookie */
+#define	No	(1+1024/4)	/* netobj */
+#define	St	1	/* status */
+#define	Rg	4	/* range (offset + length) */
 struct svc_procedure		nlmsvc_procedures4[] = {
-  PROC(null,		void,		void,		void,	void, 0),
-  PROC(test,		testargs,	testres,	args,	res, 0),
-  PROC(lock,		lockargs,	res,		args,	res, 0),
-  PROC(cancel,		cancargs,	res,		args,	res, 0),
-  PROC(unlock,		unlockargs,	res,		args,	res, 0),
-  PROC(granted,		testargs,	res,		args,	res, 0),
-  PROC(test_msg,	testargs,	norep,		args,	void, 0),
-  PROC(lock_msg,	lockargs,	norep,		args,	void, 0),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void, 0),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 0),
-  PROC(granted_msg,	testargs,	norep,		args,	void, 0),
-  PROC(test_res,	testres,	norep,		res,	void, 0),
-  PROC(lock_res,	lockres,	norep,		res,	void, 0),
-  PROC(cancel_res,	cancelres,	norep,		res,	void, 0),
-  PROC(unlock_res,	unlockres,	norep,		res,	void, 0),
-  PROC(granted_res,	grantedres,	norep,		res,	void, 0),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void, 0),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
   PROC(none,		void,		void,		void,	void, 0),
   PROC(none,		void,		void,		void,	void, 0),
   PROC(none,		void,		void,		void,	void, 0),
-  PROC(share,		shareargs,	shareres,	args,	res, 0),
-  PROC(unshare,		shareargs,	shareres,	args,	res, 0),
-  PROC(nm_lock,		lockargs,	res,		args,	res, 0),
-  PROC(free_all,	notify,		void,		args,	void, 0),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(free_all,	notify,		void,		args,	void, 1),
 
 };
diff -Nru a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
--- a/fs/lockd/svcproc.c	Thu May  9 15:21:08 2002
+++ b/fs/lockd/svcproc.c	Thu May  9 15:21:08 2002
@@ -565,31 +565,37 @@
    0,					\
    respsize,				\
  }
+
+#define	Ck	(1+8)	/* cookie */
+#define	St	1	/* status */
+#define	No	(1+1024/4) /* Net Obj */
+#define	Rg	2	/* range - offset + size */
+
 struct svc_procedure		nlmsvc_procedures[] = {
-  PROC(null,		void,		void,		void,	void, 0),
-  PROC(test,		testargs,	testres,	args,	res, 0),
-  PROC(lock,		lockargs,	res,		args,	res, 0),
-  PROC(cancel,		cancargs,	res,		args,	res, 0),
-  PROC(unlock,		unlockargs,	res,		args,	res, 0),
-  PROC(granted,		testargs,	res,		args,	res, 0),
-  PROC(test_msg,	testargs,	norep,		args,	void, 0),
-  PROC(lock_msg,	lockargs,	norep,		args,	void, 0),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void, 0),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 0),
-  PROC(granted_msg,	testargs,	norep,		args,	void, 0),
-  PROC(test_res,	testres,	norep,		res,	void, 0),
-  PROC(lock_res,	lockres,	norep,		res,	void, 0),
-  PROC(cancel_res,	cancelres,	norep,		res,	void, 0),
-  PROC(unlock_res,	unlockres,	norep,		res,	void, 0),
-  PROC(granted_res,	grantedres,	norep,		res,	void, 0),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void, 0),
-  PROC(none,		void,		void,		void,	void, 0),
-  PROC(none,		void,		void,		void,	void, 0),
-  PROC(none,		void,		void,		void,	void, 0),
-  PROC(share,		shareargs,	shareres,	args,	res, 0),
-  PROC(unshare,		shareargs,	shareres,	args,	res, 0),
-  PROC(nm_lock,		lockargs,	res,		args,	res, 0),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
   PROC(free_all,	notify,		void,		args,	void, 0),
 
 };
diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c	Thu May  9 15:21:07 2002
+++ b/fs/msdos/namei.c	Thu May  9 15:21:07 2002
@@ -221,13 +221,22 @@
 	if (res)
 		goto out;
 add:
-	d_add(dentry, inode);
+	if (inode) {
+		dentry = d_splice_alias(inode, dentry);
+		dentry->d_op = &msdos_dentry_operations;
+	} else {
+		d_add(dentry, inode);
+		dentry = NULL;
+	}
 	res = 0;
 out:
 	if (bh)
 		fat_brelse(sb, bh);
 	unlock_kernel();
-	return ERR_PTR(res);
+	if (res)
+		return ERR_PTR(res);
+	else
+		return dentry;
 }
 
 /***** Creates a directory entry (name is already formatted). */
diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Thu May  9 15:21:05 2002
+++ b/fs/nfs/pagelist.c	Thu May  9 15:21:05 2002
@@ -196,7 +196,7 @@
 		BUG();
 	}
 #endif
-	for (pos = head->prev; pos != head; pos = pos->prev) {
+	list_for_each_prev(pos, head) {
 		struct nfs_page	*p = nfs_list_entry(pos);
 		if (page_index(p->wb_page) < pg_idx)
 			break;
diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c	Thu May  9 15:21:01 2002
+++ b/fs/nfsd/nfssvc.c	Thu May  9 15:21:01 2002
@@ -67,7 +67,7 @@
 /*
  * Maximum number of nfsd processes
  */
-#define	NFSD_MAXSERVS		128
+#define	NFSD_MAXSERVS		8192
 
 int
 nfsd_svc(unsigned short port, int nrservs)
@@ -90,6 +90,7 @@
 		goto out;
 	if (!nfsd_serv) {
 		atomic_set(&nfsd_busy, 0);
+		error = -ENOMEM;
 		nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
 		if (nfsd_serv == NULL)
 			goto out;
diff -Nru a/fs/nls/nls_base.c b/fs/nls/nls_base.c
--- a/fs/nls/nls_base.c	Thu May  9 15:21:02 2002
+++ b/fs/nls/nls_base.c	Thu May  9 15:21:02 2002
@@ -20,7 +20,8 @@
 #endif
 #include <linux/spinlock.h>
 
-static struct nls_table *tables;
+static struct nls_table default_table;
+static struct nls_table *tables = &default_table;
 static spinlock_t nls_lock = SPIN_LOCK_UNLOCKED;
 
 /*
diff -Nru a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c
--- a/fs/nls/nls_koi8-ru.c	Thu May  9 15:21:01 2002
+++ b/fs/nls/nls_koi8-ru.c	Thu May  9 15:21:01 2002
@@ -22,13 +22,14 @@
 	if ((uni & 0xffaf) == 0x040e || (uni & 0xffce) == 0x254c) {
 		/* koi8-ru and koi8-u differ only on two characters */
 		if (uni == 0x040e)
-			return 0xbe;
+			out[0] = 0xbe;
 		else if (uni == 0x045e)
-			return 0xae;
+			out[0] = 0xae;
 		else if (uni == 0x255d || uni == 0x256c)
 			return 0;
 		else
 			return p_nls->uni2char(uni, out, boundlen);
+		return 1;
 	}
 	else
 		/* fast path */
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Thu May  9 15:21:09 2002
+++ b/fs/ntfs/aops.c	Thu May  9 15:21:09 2002
@@ -76,13 +76,13 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	clear_buffer_async(bh);
+	clear_buffer_async_read(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
 		if (buffer_locked(tmp)) {
-			if (buffer_async(tmp))
+			if (buffer_async_read(tmp))
 				goto still_busy;
 		} else if (!buffer_uptodate(tmp))
 			SetPageError(page);
@@ -218,7 +218,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_file_async;
-			set_buffer_async(tbh);
+			set_buffer_async_read(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
@@ -378,13 +378,13 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	clear_buffer_async(bh);
+	clear_buffer_async_read(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
 		if (buffer_locked(tmp)) {
-			if (buffer_async(tmp))
+			if (buffer_async_read(tmp))
 				goto still_busy;
 		} else if (!buffer_uptodate(tmp))
 			SetPageError(page);
@@ -501,7 +501,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_mftbmp_async;
-			set_buffer_async(tbh);
+			set_buffer_async_read(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
@@ -574,13 +574,13 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	clear_buffer_async(bh);
+	clear_buffer_async_read(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
 		if (buffer_locked(tmp)) {
-			if (buffer_async(tmp))
+			if (buffer_async_read(tmp))
 				goto still_busy;
 		} else if (!buffer_uptodate(tmp))
 			SetPageError(page);
@@ -758,7 +758,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_mst_async;
-			set_buffer_async(tbh);
+			set_buffer_async_read(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Thu May  9 15:21:02 2002
+++ b/fs/open.c	Thu May  9 15:21:02 2002
@@ -835,7 +835,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 -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Thu May  9 15:21:02 2002
+++ b/fs/proc/proc_misc.c	Thu May  9 15:21:02 2002
@@ -50,6 +50,8 @@
  * have a way to deal with that gracefully. Right now I used straightforward
  * wrappers, but this needs further analysis wrt potential overflows.
  */
+extern int get_hardware_list(char *);
+extern int get_stram_list(char *);
 extern int get_device_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
@@ -205,6 +207,24 @@
 	release:	seq_release,
 };
 
+#ifdef CONFIG_PROC_HARDWARE
+static int hardware_read_proc(char *page, char **start, off_t off,
+				 int count, int *eof, void *data)
+{
+	int len = get_hardware_list(page);
+	return proc_calc_metrics(page, start, off, count, eof, len);
+}
+#endif
+
+#ifdef CONFIG_STRAM_PROC
+static int stram_read_proc(char *page, char **start, off_t off,
+				 int count, int *eof, void *data)
+{
+	int len = get_stram_list(page);
+	return proc_calc_metrics(page, start, off, count, eof, len);
+}
+#endif
+
 extern struct seq_operations partitions_op;
 static int partitions_open(struct inode *inode, struct file *file)
 {
@@ -546,6 +566,12 @@
 		{"uptime",	uptime_read_proc},
 		{"meminfo",	meminfo_read_proc},
 		{"version",	version_read_proc},
+#ifdef CONFIG_PROC_HARDWARE
+		{"hardware",	hardware_read_proc},
+#endif
+#ifdef CONFIG_STRAM_PROC
+		{"stram",	stram_read_proc},
+#endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
 		{"filesystems",	filesystems_read_proc},
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Thu May  9 15:21:05 2002
+++ b/fs/reiserfs/inode.c	Thu May  9 15:21:05 2002
@@ -1251,11 +1251,39 @@
     return inode;
 }
 
-struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
-				     int len, int fhtype, int parent) {
+struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp)
+{
+    __u32 *data = vobjp;
     struct cpu_key key ;
-    struct inode *inode = NULL ;
     struct dentry *result;
+    struct inode *inode;
+    
+    key.on_disk_key.k_objectid = data[0] ;
+    key.on_disk_key.k_dir_id = data[1] ;
+    inode = reiserfs_iget(sb, &key) ;
+    if (inode && !IS_ERR(inode) && data[2] != 0 &&
+	data[2] != inode->i_generation) {
+	    iput(inode) ;
+	    inode = NULL ;
+    }
+    if (!inode)
+	    inode = ERR_PTR(-ESTALE);
+    if (IS_ERR(inode))
+	    return ERR_PTR(PTR_ERR(inode));
+    result = d_alloc_anon(inode);
+    if (!result) {
+	    iput(inode);
+	    return ERR_PTR(-ENOMEM);
+    }
+    result->d_vfs_flags |= DCACHE_REFERENCED;
+    return result;
+}
+
+struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 *data,
+                                     int len, int fhtype,
+				  int (*acceptable)(void *contect, struct dentry *de),
+				  void *context) {
+    __u32 obj[3], parent[3];
 
     /* fhtype happens to reflect the number of u32s encoded.
      * due to a bug in earlier code, fhtype might indicate there
@@ -1275,51 +1303,25 @@
 			   fhtype, len);
 	    fhtype = 5;
     }
-    if (fhtype < 2 || (parent && fhtype < 4)) 
-	goto out ;
 
-    if (! parent) {
-	    /* this works for handles from old kernels because the default
-	    ** reiserfs generation number is the packing locality.
-	    */
-	    key.on_disk_key.k_objectid = data[0] ;
-	    key.on_disk_key.k_dir_id = data[1] ;
-	    inode = reiserfs_iget(sb, &key) ;
-	    if (inode && !IS_ERR(inode) && (fhtype == 3 || fhtype >= 5) &&
-		data[2] != inode->i_generation) {
-		    iput(inode) ;
-		    inode = NULL ;
-	    }
-    } else {
-	    key.on_disk_key.k_objectid = data[fhtype>=5?3:2] ;
-	    key.on_disk_key.k_dir_id = data[fhtype>=5?4:3] ;
-	    inode = reiserfs_iget(sb, &key) ;
-	    if (inode && !IS_ERR(inode) && fhtype == 6 &&
-		data[5] != inode->i_generation) {
-		    iput(inode) ;
-		    inode = NULL ;
-	    }
-    }
-out:
-    if (IS_ERR(inode))
-	return ERR_PTR(PTR_ERR(inode));
-    if (!inode)
-        return ERR_PTR(-ESTALE) ;
+    obj[0] = data[0];
+    obj[1] = data[1];
+    if (fhtype == 3 || fhtype >= 5)
+	    obj[2] = data[2];
+    else    obj[2] = 0; /* generation number */
 
-    /* now to find a dentry.
-     * If possible, get a well-connected one
-     */
-    result = d_alloc_anon(inode);
-    if (result == NULL) {
-	    iput(inode);
-	    return ERR_PTR(-ENOMEM);
+    if (fhtype >= 4) {
+	    parent[0] = data[fhtype>=5?3:2] ;
+	    parent[1] = data[fhtype>=5?4:3] ;
+	    if (fhtype == 6)
+		    parent[2] = data[5];
+	    else    parent[2] = 0;
     }
-    result->d_vfs_flags |= DCACHE_REFERENCED;
-    return result;
-
+    return sb->s_export_op->find_exported_dentry(sb, obj, fhtype < 4 ? NULL : parent,
+			       acceptable, context);
 }
 
-int reiserfs_dentry_to_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent) {
+int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent) {
     struct inode *inode = dentry->d_inode ;
     int maxlen = *lenp;
     
diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
--- a/fs/reiserfs/namei.c	Thu May  9 15:21:01 2002
+++ b/fs/reiserfs/namei.c	Thu May  9 15:21:01 2002
@@ -363,9 +363,54 @@
 	return ERR_PTR(-EIO);
     }
 
+    if (inode)
+	    return d_splice_alias(inode, dentry);
+    
     d_add(dentry, inode);
     return NULL;
 }
+
+
+/* 
+** looks up the dentry of the parent directory for child.
+** taken from ext2_get_parent
+*/
+struct dentry *reiserfs_get_parent(struct dentry *child)
+{
+    int retval;
+    struct inode * inode = NULL;
+    struct reiserfs_dir_entry de;
+    INITIALIZE_PATH (path_to_entry);
+    struct dentry *parent;
+    struct inode *dir = child->d_inode ;
+
+
+    if (dir->i_nlink == 0) {
+	return ERR_PTR(-ENOENT);
+    }
+    de.de_gen_number_bit_string = 0;
+
+    lock_kernel();
+    retval = reiserfs_find_entry (dir, "..", 2, &path_to_entry, &de);
+    pathrelse (&path_to_entry);
+    if (retval != NAME_FOUND) {
+	unlock_kernel();
+	return ERR_PTR(-ENOENT);
+    }
+    inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
+    unlock_kernel();
+
+    if (!inode || IS_ERR(inode)) {
+	return ERR_PTR(-EACCES);
+    }
+    parent = d_alloc_anon(inode);
+    if (!parent) {
+	iput(inode);
+	parent = ERR_PTR(-ENOMEM);
+    }
+    return parent;
+}
+
 
 //
 // a portion of this function, particularly the VFS interface portion,
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Thu May  9 15:21:06 2002
+++ b/fs/reiserfs/super.c	Thu May  9 15:21:06 2002
@@ -496,11 +496,15 @@
   statfs: reiserfs_statfs,
   remount_fs: reiserfs_remount,
 
-  fh_to_dentry: reiserfs_fh_to_dentry,
-  dentry_to_fh: reiserfs_dentry_to_fh,
-
 };
 
+static struct export_operations reiserfs_export_ops = {
+  encode_fh: reiserfs_encode_fh,
+  decode_fh: reiserfs_decode_fh,
+  get_parent: reiserfs_get_parent,
+  get_dentry: reiserfs_get_dentry,
+} ;
+
 /* this was (ext2)parse_options */
 static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks, char **jdev_name)
 {
@@ -799,6 +803,7 @@
 	      is_reiserfs_3_5 (rs) ? "3.5" : "3.6");
 
     s->s_op = &reiserfs_sops;
+    s->s_export_op = &reiserfs_export_ops;
 
     /* new format is limited by the 32 bit wide i_blocks field, want to
     ** be one full block below that.
diff -Nru a/fs/ufs/balloc.c b/fs/ufs/balloc.c
--- a/fs/ufs/balloc.c	Thu May  9 15:21:02 2002
+++ b/fs/ufs/balloc.c	Thu May  9 15:21:02 2002
@@ -288,7 +288,7 @@
 	/*
 	 * There is not enough space for user on the device
 	 */
-	if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+	if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
 		unlock_super (sb);
 		UFSD(("EXIT (FAILED)\n"))
 		return 0;
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Thu May  9 15:21:08 2002
+++ b/fs/vfat/namei.c	Thu May  9 15:21:08 2002
@@ -1020,6 +1020,14 @@
 	unlock_kernel();
 	dentry->d_op = &vfat_dentry_ops[table];
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
+	if (inode) {
+		dentry = d_splice_alias(inode, dentry);
+		if (dentry) {
+			dentry->d_op = &vfat_dentry_ops[table];
+			dentry->d_time = dentry->d_parent->d_inode->i_version;
+		}
+		return dentry;
+	}
 	d_add(dentry,inode);
 	return NULL;
 }
@@ -1305,11 +1313,11 @@
 		if (sbi->options.posixfs) {
 			sbi->options.name_check = 's';
 		}
-		if (sbi->options.name_check != 's') {
-			sb->s_root->d_op = &vfat_dentry_ops[0];
-		} else {
-			sb->s_root->d_op = &vfat_dentry_ops[2];
-		}
+	}
+	if (sbi->options.name_check != 's') {
+		sb->s_root->d_op = &vfat_dentry_ops[0];
+	} else {
+		sb->s_root->d_op = &vfat_dentry_ops[2];
 	}
 	return 0;
 }
diff -Nru a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h
--- a/include/asm-alpha/ide.h	Thu May  9 15:21:05 2002
+++ b/include/asm-alpha/ide.h	Thu May  9 15:21:05 2002
@@ -70,7 +70,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -79,37 +79,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-arm/ide.h b/include/asm-arm/ide.h
--- a/include/asm-arm/ide.h	Thu May  9 15:21:06 2002
+++ b/include/asm-arm/ide.h	Thu May  9 15:21:06 2002
@@ -21,34 +21,7 @@
 
 #include <asm/arch/ide.h>
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-cris/ide.h b/include/asm-cris/ide.h
--- a/include/asm-cris/ide.h	Thu May  9 15:21:03 2002
+++ b/include/asm-cris/ide.h	Thu May  9 15:21:03 2002
@@ -88,29 +88,6 @@
 	}
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
 /* some configuration options we don't need */
 
 #undef SUPPORT_VLB_SYNC
@@ -119,11 +96,7 @@
 #undef SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS	0
 
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-i386/ide.h b/include/asm-i386/ide.h
--- a/include/asm-i386/ide.h	Thu May  9 15:21:02 2002
+++ b/include/asm-i386/ide.h	Thu May  9 15:21:02 2002
@@ -16,7 +16,7 @@
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
-# ifdef CONFIG_BLK_DEV_IDEPCI
+# ifdef CONFIG_PCI
 #define MAX_HWIFS	10
 # else
 #define MAX_HWIFS	6
@@ -74,7 +74,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -83,37 +83,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h
--- a/include/asm-ia64/ide.h	Thu May  9 15:21:08 2002
+++ b/include/asm-ia64/ide.h	Thu May  9 15:21:08 2002
@@ -18,7 +18,7 @@
 #include <linux/irq.h>
 
 #ifndef MAX_HWIFS
-# ifdef CONFIG_BLK_DEV_IDEPCI
+# ifdef CONFIG_PCI
 #define MAX_HWIFS	10
 # else
 #define MAX_HWIFS	6
@@ -80,7 +80,7 @@
 static __inline__ void
 ide_init_default_hwifs (void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -89,37 +89,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
--- a/include/asm-m68k/bitops.h	Thu May  9 15:21:07 2002
+++ b/include/asm-m68k/bitops.h	Thu May  9 15:21:07 2002
@@ -97,6 +97,7 @@
   (__builtin_constant_p(nr) ? \
    __constant_clear_bit(nr, vaddr) : \
    __generic_clear_bit(nr, vaddr))
+#define __clear_bit(nr,vaddr) clear_bit(nr,vaddr)
 
 extern __inline__ void __constant_clear_bit(int nr, volatile void * vaddr)
 {
@@ -239,6 +240,28 @@
 
 	return 32 - cnt;
 }
+#define __ffs(x) (ffs(x) - 1)
+
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(unsigned long *b)
+{
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+}
+
 
 /*
  * hweightN: returns the hamming weight (i.e. the number
diff -Nru a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-m68k/cacheflush.h	Thu May  9 15:21:10 2002
@@ -0,0 +1,156 @@
+#ifndef _M68K_CACHEFLUSH_H
+#define _M68K_CACHEFLUSH_H
+
+/*
+ * Cache handling functions
+ */
+
+#define flush_icache()						\
+({								\
+	if (CPU_IS_040_OR_060)					\
+		__asm__ __volatile__("nop\n\t"			\
+				     ".chip 68040\n\t"		\
+				     "cinva %%ic\n\t"		\
+				     ".chip 68k" : );		\
+	else {							\
+		unsigned long _tmp;				\
+		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
+				     "orw %1,%0\n\t"		\
+				     "movec %0,%%cacr"		\
+				     : "=&d" (_tmp)		\
+				     : "id" (FLUSH_I));	\
+	}							\
+})
+
+/*
+ * invalidate the cache for the specified memory range.
+ * It starts at the physical address specified for
+ * the given number of bytes.
+ */
+extern void cache_clear(unsigned long paddr, int len);
+/*
+ * push any dirty cache in the specified memory range.
+ * It starts at the physical address specified for
+ * the given number of bytes.
+ */
+extern void cache_push(unsigned long paddr, int len);
+
+/*
+ * push and invalidate pages in the specified user virtual
+ * memory range.
+ */
+extern void cache_push_v(unsigned long vaddr, int len);
+
+/* cache code */
+#define FLUSH_I_AND_D	(0x00000808)
+#define FLUSH_I 	(0x00000008)
+
+/* This is needed whenever the virtual mapping of the current
+   process changes.  */
+#define __flush_cache_all()					\
+({								\
+	if (CPU_IS_040_OR_060)					\
+		__asm__ __volatile__("nop\n\t"			\
+				     ".chip 68040\n\t"		\
+				     "cpusha %dc\n\t"		\
+				     ".chip 68k");		\
+	else {							\
+		unsigned long _tmp;				\
+		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
+				     "orw %1,%0\n\t"		\
+				     "movec %0,%%cacr"		\
+				     : "=&d" (_tmp)		\
+				     : "di" (FLUSH_I_AND_D));	\
+	}							\
+})
+
+#define __flush_cache_030()					\
+({								\
+	if (CPU_IS_020_OR_030) {				\
+		unsigned long _tmp;				\
+		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
+				     "orw %1,%0\n\t"		\
+				     "movec %0,%%cacr"		\
+				     : "=&d" (_tmp)		\
+				     : "di" (FLUSH_I_AND_D));	\
+	}							\
+})
+
+#define flush_cache_all() __flush_cache_all()
+
+extern inline void flush_cache_mm(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		__flush_cache_030();
+}
+
+/* flush_cache_range/flush_cache_page must be macros to avoid
+   a dependency on linux/mm.h, which includes this file... */
+extern inline void flush_cache_range(struct vm_area_struct *vma,
+				     unsigned long start,
+				     unsigned long end)
+{
+	if (vma->vm_mm == current->mm) 
+	        __flush_cache_030();
+}
+
+extern inline void flush_cache_page(struct vm_area_struct *vma,
+				    unsigned long vmaddr)
+{
+ 	if (vma->vm_mm == current->mm)
+	        __flush_cache_030();
+}
+
+
+/* Push the page at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+#define flush_page_to_ram(page) __flush_page_to_ram((unsigned long) page_address(page))
+extern inline void __flush_page_to_ram(unsigned long address)
+{
+	if (CPU_IS_040_OR_060) {
+		__asm__ __volatile__("nop\n\t"
+				     ".chip 68040\n\t"
+				     "cpushp %%bc,(%0)\n\t"
+				     ".chip 68k"
+				     : : "a" (__pa((void *)address)));
+	} else {
+		unsigned long _tmp;
+		__asm__ __volatile__("movec %%cacr,%0\n\t"
+				     "orw %1,%0\n\t"
+				     "movec %0,%%cacr"
+				     : "=&d" (_tmp)
+				     : "di" (FLUSH_I));
+	}
+}
+
+#define flush_dcache_page(page)			do { } while (0)
+#define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+
+/* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+extern inline void flush_icache_range (unsigned long address,
+				       unsigned long endaddr)
+{
+	if (CPU_IS_040_OR_060) {
+		short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE;
+
+		while (--n >= 0) {
+			__asm__ __volatile__("nop\n\t"
+					     ".chip 68040\n\t"
+					     "cpushp %%bc,(%0)\n\t"
+					     ".chip 68k"
+					     : : "a" (virt_to_phys((void *)address)));
+			address += PAGE_SIZE;
+		}
+	} else {
+		unsigned long tmp;
+		__asm__ __volatile__("movec %%cacr,%0\n\t"
+				     "orw %1,%0\n\t"
+				     "movec %0,%%cacr"
+				     : "=&d" (tmp)
+				     : "di" (FLUSH_I));
+	}
+}
+
+#endif /* _M68K_CACHEFLUSH_H */
diff -Nru a/include/asm-m68k/entry.h b/include/asm-m68k/entry.h
--- a/include/asm-m68k/entry.h	Thu May  9 15:21:09 2002
+++ b/include/asm-m68k/entry.h	Thu May  9 15:21:09 2002
@@ -109,7 +109,7 @@
 
 .macro	get_current reg=%d0
 	movel	%sp,\reg
-	andw	#-KTHREAD_SIZE,\reg
+	andw	#-THREAD_SIZE,\reg
 	movel	\reg,%curptr
 .endm
 
@@ -128,8 +128,9 @@
 	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-"
 #define GET_CURRENT(tmp) \
 	"movel	%%sp,"#tmp"\n\t" \
-	"andw	#-"STR(KTHREAD_SIZE)","#tmp"\n\t" \
-	"movel	"#tmp",%%a2"
+	"andw	#-"STR(THREAD_SIZE)","#tmp"\n\t" \
+	"movel	"#tmp",%%a2\n\t" \
+	"movel	%%a2@,%%a2"
 
 #endif
 
diff -Nru a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h
--- a/include/asm-m68k/ide.h	Thu May  9 15:21:01 2002
+++ b/include/asm-m68k/ide.h	Thu May  9 15:21:01 2002
@@ -80,29 +80,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
 #undef SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -144,6 +121,7 @@
 #define inb(p)     in_8(ADDR_TRANS_B(p))
 #define inb_p(p)     in_8(ADDR_TRANS_B(p))
 #define inw(p)     in_be16(ADDR_TRANS_W(p))
+#define inw_p(p)     in_be16(ADDR_TRANS_W(p))
 #define outb(v,p)  out_8(ADDR_TRANS_B(p),v)
 #define outb_p(v,p)  out_8(ADDR_TRANS_B(p),v)
 #define outw(v,p)  out_be16(ADDR_TRANS_W(p),v)
@@ -155,7 +133,6 @@
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
 
-
 #if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
 
 #define insl_swapw(data_reg, buffer, wcount) \
@@ -168,101 +145,6 @@
 
 #endif /* CONFIG_ATARI || CONFIG_Q40 */
 
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-/* Q40 and Atari have byteswapped IDE bus and since many interesting
- * values in the identification string are text, chars and words they
- * happened to be almost correct without swapping.. However *_capacity 
- * is needed for drives over 8 GB. RZ */
-#if defined(CONFIG_Q40) || defined(CONFIG_ATARI)
-#define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
-#endif
-
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type, buf_size - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reserved */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-#endif /* CONFIG_AMIGA */
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
-   	return;
-#ifdef M68K_IDE_SWAPW
-   if (M68K_IDE_SWAPW)    /* fix bus byteorder first */
-      for (i=0; i < 512; i+=2) {
-	 t = p[i]; p[i] = p[i+1]; p[i+1] = t; 
-      }
-#endif
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[3];
-	       p[3] = t;
-	       t = p[1];
-	       p[1] = p[2];
-	       p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-#endif /* CONFIG_AMIGA */
-}
 
 static __inline__ void ide_release_lock (int *ide_lock)
 {
diff -Nru a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
--- a/include/asm-m68k/machdep.h	Thu May  9 15:21:02 2002
+++ b/include/asm-m68k/machdep.h	Thu May  9 15:21:02 2002
@@ -6,7 +6,7 @@
 struct pt_regs;
 struct kbd_repeat;
 struct mktime;
-struct hwclk_time;
+struct rtc_time;
 struct buffer_head;
 
 extern void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
@@ -27,9 +27,7 @@
 extern void (*mach_process_int) (int irq, struct pt_regs *fp);
 /* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
-extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
-			   int *min, int *sec);
-extern int (*mach_hwclk)(int, struct hwclk_time*);
+extern int (*mach_hwclk)(int, struct rtc_time*);
 extern int (*mach_set_clock_mmss)(unsigned long);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
diff -Nru a/include/asm-m68k/motorola_pgalloc.h b/include/asm-m68k/motorola_pgalloc.h
--- a/include/asm-m68k/motorola_pgalloc.h	Thu May  9 15:21:07 2002
+++ b/include/asm-m68k/motorola_pgalloc.h	Thu May  9 15:21:07 2002
@@ -1,6 +1,8 @@
 #ifndef _MOTOROLA_PGALLOC_H
 #define _MOTOROLA_PGALLOC_H
 
+#include <asm/tlbflush.h>
+
 extern struct pgtable_cache_struct {
 	unsigned long *pmd_cache;
 	unsigned long *pte_cache;
@@ -22,21 +24,6 @@
 extern int free_pointer_table(pmd_t *);
 
 
-extern inline void flush_tlb_kernel_page(unsigned long addr)
-{
-	if (CPU_IS_040_OR_060) {
-		mm_segment_t old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		__asm__ __volatile__(".chip 68040\n\t"
-				     "pflush (%0)\n\t"
-				     ".chip 68k"
-				     : : "a" (addr));
-		set_fs(old_fs);
-	} else
-		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
-}
-
-
 extern inline pte_t *get_pte_fast(void)
 {
 	unsigned long *ret;
@@ -184,74 +171,5 @@
 {
 }
 
-
-/*
- * flush all user-space atc entries.
- */
-static inline void __flush_tlb(void)
-{
-	if (CPU_IS_040_OR_060)
-		__asm__ __volatile__(".chip 68040\n\t"
-				     "pflushan\n\t"
-				     ".chip 68k");
-	else
-		__asm__ __volatile__("pflush #0,#4");
-}
-
-static inline void __flush_tlb040_one(unsigned long addr)
-{
-	__asm__ __volatile__(".chip 68040\n\t"
-			     "pflush (%0)\n\t"
-			     ".chip 68k"
-			     : : "a" (addr));
-}
-
-static inline void __flush_tlb_one(unsigned long addr)
-{
-	if (CPU_IS_040_OR_060)
-		__flush_tlb040_one(addr);
-	else
-		__asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
-}
-
-#define flush_tlb() __flush_tlb()
-
-/*
- * flush all atc entries (both kernel and user-space entries).
- */
-static inline void flush_tlb_all(void)
-{
-	if (CPU_IS_040_OR_060)
-		__asm__ __volatile__(".chip 68040\n\t"
-				     "pflusha\n\t"
-				     ".chip 68k");
-	else
-		__asm__ __volatile__("pflusha");
-}
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-	if (mm == current->mm)
-		__flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
-	if (vma->vm_mm == current->mm)
-		__flush_tlb_one(addr);
-}
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	if (vma->vm_mm == current->mm)
-		__flush_tlb();
-}
-
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				      unsigned long start, unsigned long end)
-{
-}
 
 #endif /* _MOTOROLA_PGALLOC_H */
diff -Nru a/include/asm-m68k/page.h b/include/asm-m68k/page.h
--- a/include/asm-m68k/page.h	Thu May  9 15:21:07 2002
+++ b/include/asm-m68k/page.h	Thu May  9 15:21:07 2002
@@ -18,9 +18,9 @@
 #include <asm/setup.h>
 
 #if PAGE_SHIFT < 13
-#define KTHREAD_SIZE (8192)
+#define THREAD_SIZE (8192)
 #else
-#define KTHREAD_SIZE PAGE_SIZE
+#define THREAD_SIZE PAGE_SIZE
 #endif
  
 #ifndef __ASSEMBLY__
diff -Nru a/include/asm-m68k/pgalloc.h b/include/asm-m68k/pgalloc.h
--- a/include/asm-m68k/pgalloc.h	Thu May  9 15:21:07 2002
+++ b/include/asm-m68k/pgalloc.h	Thu May  9 15:21:07 2002
@@ -3,158 +3,10 @@
 #define M68K_PGALLOC_H
 
 #include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
 #include <asm/setup.h>
 #include <asm/virtconvert.h>
-
-/*
- * Cache handling functions
- */
-
-#define flush_icache()						\
-({								\
-	if (CPU_IS_040_OR_060)					\
-		__asm__ __volatile__("nop\n\t"			\
-				     ".chip 68040\n\t"		\
-				     "cinva %%ic\n\t"		\
-				     ".chip 68k" : );		\
-	else {							\
-		unsigned long _tmp;				\
-		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
-				     "orw %1,%0\n\t"		\
-				     "movec %0,%%cacr"		\
-				     : "=&d" (_tmp)		\
-				     : "id" (FLUSH_I));	\
-	}							\
-})
-
-/*
- * invalidate the cache for the specified memory range.
- * It starts at the physical address specified for
- * the given number of bytes.
- */
-extern void cache_clear(unsigned long paddr, int len);
-/*
- * push any dirty cache in the specified memory range.
- * It starts at the physical address specified for
- * the given number of bytes.
- */
-extern void cache_push(unsigned long paddr, int len);
-
-/*
- * push and invalidate pages in the specified user virtual
- * memory range.
- */
-extern void cache_push_v(unsigned long vaddr, int len);
-
-/* cache code */
-#define FLUSH_I_AND_D	(0x00000808)
-#define FLUSH_I 	(0x00000008)
-
-/* This is needed whenever the virtual mapping of the current
-   process changes.  */
-#define __flush_cache_all()					\
-({								\
-	if (CPU_IS_040_OR_060)					\
-		__asm__ __volatile__("nop\n\t"			\
-				     ".chip 68040\n\t"		\
-				     "cpusha %dc\n\t"		\
-				     ".chip 68k");		\
-	else {							\
-		unsigned long _tmp;				\
-		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
-				     "orw %1,%0\n\t"		\
-				     "movec %0,%%cacr"		\
-				     : "=&d" (_tmp)		\
-				     : "di" (FLUSH_I_AND_D));	\
-	}							\
-})
-
-#define __flush_cache_030()					\
-({								\
-	if (CPU_IS_020_OR_030) {				\
-		unsigned long _tmp;				\
-		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
-				     "orw %1,%0\n\t"		\
-				     "movec %0,%%cacr"		\
-				     : "=&d" (_tmp)		\
-				     : "di" (FLUSH_I_AND_D));	\
-	}							\
-})
-
-#define flush_cache_all() __flush_cache_all()
-
-extern inline void flush_cache_mm(struct mm_struct *mm)
-{
-	if (mm == current->mm)
-		__flush_cache_030();
-}
-
-extern inline void flush_cache_range(struct vm_area_struct *vma,
-				     unsigned long start,
-				     unsigned long end)
-{
-	if (vma->vm_mm == current->mm)
-	        __flush_cache_030();
-}
-
-extern inline void flush_cache_page(struct vm_area_struct *vma,
-				    unsigned long vmaddr)
-{
-	if (vma->vm_mm == current->mm)
-	        __flush_cache_030();
-}
-
-/* Push the page at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-#define flush_page_to_ram(page) __flush_page_to_ram((unsigned long) page_address(page))
-extern inline void __flush_page_to_ram(unsigned long address)
-{
-	if (CPU_IS_040_OR_060) {
-		__asm__ __volatile__("nop\n\t"
-				     ".chip 68040\n\t"
-				     "cpushp %%bc,(%0)\n\t"
-				     ".chip 68k"
-				     : : "a" (__pa((void *)address)));
-	} else {
-		unsigned long _tmp;
-		__asm__ __volatile__("movec %%cacr,%0\n\t"
-				     "orw %1,%0\n\t"
-				     "movec %0,%%cacr"
-				     : "=&d" (_tmp)
-				     : "di" (FLUSH_I));
-	}
-}
-
-#define flush_dcache_page(page)			do { } while (0)
-#define flush_icache_page(vma,pg)              do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
-
-/* Push n pages at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-extern inline void flush_icache_range (unsigned long address,
-				       unsigned long endaddr)
-{
-	if (CPU_IS_040_OR_060) {
-		short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE;
-
-		while (--n >= 0) {
-			__asm__ __volatile__("nop\n\t"
-					     ".chip 68040\n\t"
-					     "cpushp %%bc,(%0)\n\t"
-					     ".chip 68k"
-					     : : "a" (virt_to_phys((void *)address)));
-			address += PAGE_SIZE;
-		}
-	} else {
-		unsigned long tmp;
-		__asm__ __volatile__("movec %%cacr,%0\n\t"
-				     "orw %1,%0\n\t"
-				     "movec %0,%%cacr"
-				     : "=&d" (tmp)
-				     : "di" (FLUSH_I));
-	}
-}
-
 
 
 
diff -Nru a/include/asm-m68k/resource.h b/include/asm-m68k/resource.h
--- a/include/asm-m68k/resource.h	Thu May  9 15:21:01 2002
+++ b/include/asm-m68k/resource.h	Thu May  9 15:21:01 2002
@@ -13,7 +13,7 @@
 #define RLIMIT_RSS	5		/* max resident set size */
 #define RLIMIT_NPROC	6		/* max number of processes */
 #define RLIMIT_NOFILE	7		/* max number of open files */
-#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space*/
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
 
@@ -27,19 +27,19 @@
 
 #ifdef __KERNEL__
 
-#define INIT_RLIMITS	\
-{                       \
-  {LONG_MAX, LONG_MAX}, \
-  {LONG_MAX, LONG_MAX}, \
-  {LONG_MAX, LONG_MAX}, \
-  {_STK_LIM, LONG_MAX}, \
-  {       0, LONG_MAX}, \
-  {LONG_MAX, LONG_MAX}, \
-  {0, 0},		\
-  {INR_OPEN, INR_OPEN}, \
-  {LONG_MAX, LONG_MAX}, \
-  {LONG_MAX, LONG_MAX}, \
-  {LONG_MAX, LONG_MAX}  \
+#define INIT_RLIMITS					\
+{							\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{      _STK_LIM, RLIM_INFINITY },		\
+	{             0, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{             0,             0 },		\
+	{      INR_OPEN,     INR_OPEN  },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+        { RLIM_INFINITY, RLIM_INFINITY },		\
 }
 
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-m68k/rtc.h b/include/asm-m68k/rtc.h
--- a/include/asm-m68k/rtc.h	Thu May  9 15:21:05 2002
+++ b/include/asm-m68k/rtc.h	Thu May  9 15:21:05 2002
@@ -13,17 +13,7 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
-
-struct hwclk_time {
-	unsigned	sec;	/* 0..59 */
-	unsigned	min;	/* 0..59 */
-	unsigned	hour;	/* 0..23 */
-	unsigned	day;	/* 1..31 */
-	unsigned	mon;	/* 0..11 */
-	unsigned	year;	/* 70... */
-	int		wday;	/* 0..6, 0 is Sunday, -1 means unknown/don't set */
-};
+#include <asm/machdep.h>
 
 /* a few implementation details for the emulation : */
 
diff -Nru a/include/asm-m68k/sun3_pgalloc.h b/include/asm-m68k/sun3_pgalloc.h
--- a/include/asm-m68k/sun3_pgalloc.h	Thu May  9 15:21:06 2002
+++ b/include/asm-m68k/sun3_pgalloc.h	Thu May  9 15:21:06 2002
@@ -140,117 +140,6 @@
 extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM];
 extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM];
 
-/* Flush all userspace mappings one by one...  (why no flush command,
-   sun?) */
-static inline void flush_tlb_all(void)
-{
-       unsigned long addr;
-       unsigned char ctx, oldctx;
 
-       oldctx = sun3_get_context();
-       for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
-	       for(ctx = 0; ctx < 8; ctx++) {
-		       sun3_put_context(ctx);
-		       sun3_put_segmap(addr, SUN3_INVALID_PMEG);
-	       }
-       }
-
-       sun3_put_context(oldctx);
-       /* erase all of the userspace pmeg maps, we've clobbered them
-	  all anyway */
-       for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
-	       if(pmeg_alloc[addr] == 1) {
-		       pmeg_alloc[addr] = 0;
-		       pmeg_ctx[addr] = 0;
-		       pmeg_vaddr[addr] = 0;
-	       }
-       }
-
-}
-
-/* Clear user TLB entries within the context named in mm */
-static inline void flush_tlb_mm (struct mm_struct *mm)
-{
-     unsigned char oldctx;
-     unsigned char seg;
-     unsigned long i;
-
-     oldctx = sun3_get_context();
-     sun3_put_context(mm->context);
-
-     for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
-	     seg = sun3_get_segmap(i);
-	     if(seg == SUN3_INVALID_PMEG)
-		     continue;
-	     
-	     sun3_put_segmap(i, SUN3_INVALID_PMEG);
-	     pmeg_alloc[seg] = 0;
-	     pmeg_ctx[seg] = 0;
-	     pmeg_vaddr[seg] = 0;
-     }
-
-     sun3_put_context(oldctx);
-     		     
-}
-
-/* Flush a single TLB page. In this case, we're limited to flushing a
-   single PMEG */
-static inline void flush_tlb_page (struct vm_area_struct *vma,
-				   unsigned long addr)
-{
-	unsigned char oldctx;
-	unsigned char i;
-
-	oldctx = sun3_get_context();
-	sun3_put_context(vma->vm_mm->context);
-	addr &= ~SUN3_PMEG_MASK;
-	if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
-	{
-		pmeg_alloc[i] = 0;
-		pmeg_ctx[i] = 0;
-		pmeg_vaddr[i] = 0;
-		sun3_put_segmap (addr,  SUN3_INVALID_PMEG);     
-	}
-	sun3_put_context(oldctx);
-
-}
-/* Flush a range of pages from TLB. */
-
-static inline void flush_tlb_range (struct vm_area_struct *vma,
-		      unsigned long start, unsigned long end)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	unsigned char seg, oldctx;
-	
-	start &= ~SUN3_PMEG_MASK;
-
-	oldctx = sun3_get_context();
-	sun3_put_context(mm->context);
-
-	while(start < end)
-	{
-		if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG) 
-		     goto next;
-		if(pmeg_ctx[seg] == mm->context) {
-			pmeg_alloc[seg] = 0;
-			pmeg_ctx[seg] = 0;
-			pmeg_vaddr[seg] = 0;
-		}
-		sun3_put_segmap(start, SUN3_INVALID_PMEG);
-	next:
-		start += SUN3_PMEG_SIZE;
-	}
-}
-
-/* Flush kernel page from TLB. */
-static inline void flush_tlb_kernel_page (unsigned long addr)
-{
-	sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
-}
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				      unsigned long start, unsigned long end)
-{
-}
 
 #endif /* SUN3_PGALLOC_H */
diff -Nru a/include/asm-m68k/tlbflush.h b/include/asm-m68k/tlbflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-m68k/tlbflush.h	Thu May  9 15:21:10 2002
@@ -0,0 +1,215 @@
+#ifndef _M68K_TLBFLUSH_H
+#define _M68K_TLBFLUSH_H
+
+#ifndef CONFIG_SUN3
+
+extern inline void flush_tlb_kernel_page(unsigned long addr)
+{
+	if (CPU_IS_040_OR_060) {
+		mm_segment_t old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		__asm__ __volatile__(".chip 68040\n\t"
+				     "pflush (%0)\n\t"
+				     ".chip 68k"
+				     : : "a" (addr));
+		set_fs(old_fs);
+	} else
+		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
+}
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+	if (CPU_IS_040_OR_060)
+		__asm__ __volatile__(".chip 68040\n\t"
+				     "pflushan\n\t"
+				     ".chip 68k");
+	else
+		__asm__ __volatile__("pflush #0,#4");
+}
+
+static inline void __flush_tlb040_one(unsigned long addr)
+{
+	__asm__ __volatile__(".chip 68040\n\t"
+			     "pflush (%0)\n\t"
+			     ".chip 68k"
+			     : : "a" (addr));
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+	if (CPU_IS_040_OR_060)
+		__flush_tlb040_one(addr);
+	else
+		__asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr));
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+	if (CPU_IS_040_OR_060)
+		__asm__ __volatile__(".chip 68040\n\t"
+				     "pflusha\n\t"
+				     ".chip 68k");
+	else
+		__asm__ __volatile__("pflusha");
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		__flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+	if (vma->vm_mm == current->mm)
+		__flush_tlb_one(addr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	if (vma->vm_mm == current->mm)
+		__flush_tlb();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+	flush_tlb_all();
+}
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#else
+
+/* Flush all userspace mappings one by one...  (why no flush command,
+   sun?) */
+static inline void flush_tlb_all(void)
+{
+       unsigned long addr;
+       unsigned char ctx, oldctx;
+
+       oldctx = sun3_get_context();
+       for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
+	       for(ctx = 0; ctx < 8; ctx++) {
+		       sun3_put_context(ctx);
+		       sun3_put_segmap(addr, SUN3_INVALID_PMEG);
+	       }
+       }
+
+       sun3_put_context(oldctx);
+       /* erase all of the userspace pmeg maps, we've clobbered them
+	  all anyway */
+       for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) {
+	       if(pmeg_alloc[addr] == 1) {
+		       pmeg_alloc[addr] = 0;
+		       pmeg_ctx[addr] = 0;
+		       pmeg_vaddr[addr] = 0;
+	       }
+       }
+
+}
+
+/* Clear user TLB entries within the context named in mm */
+static inline void flush_tlb_mm (struct mm_struct *mm)
+{
+     unsigned char oldctx;
+     unsigned char seg;
+     unsigned long i;
+
+     oldctx = sun3_get_context();
+     sun3_put_context(mm->context);
+
+     for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) {
+	     seg = sun3_get_segmap(i);
+	     if(seg == SUN3_INVALID_PMEG)
+		     continue;
+	     
+	     sun3_put_segmap(i, SUN3_INVALID_PMEG);
+	     pmeg_alloc[seg] = 0;
+	     pmeg_ctx[seg] = 0;
+	     pmeg_vaddr[seg] = 0;
+     }
+
+     sun3_put_context(oldctx);
+     		     
+}
+
+/* Flush a single TLB page. In this case, we're limited to flushing a
+   single PMEG */
+static inline void flush_tlb_page (struct vm_area_struct *vma,
+				   unsigned long addr)
+{
+	unsigned char oldctx;
+	unsigned char i;
+
+	oldctx = sun3_get_context();
+	sun3_put_context(vma->vm_mm->context);
+	addr &= ~SUN3_PMEG_MASK;
+	if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG)
+	{
+		pmeg_alloc[i] = 0;
+		pmeg_ctx[i] = 0;
+		pmeg_vaddr[i] = 0;
+		sun3_put_segmap (addr,  SUN3_INVALID_PMEG);     
+	}
+	sun3_put_context(oldctx);
+
+}
+/* Flush a range of pages from TLB. */
+
+static inline void flush_tlb_range (struct vm_area_struct *vma,
+		      unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned char seg, oldctx;
+	
+	start &= ~SUN3_PMEG_MASK;
+
+	oldctx = sun3_get_context();
+	sun3_put_context(mm->context);
+
+	while(start < end)
+	{
+		if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG) 
+		     goto next;
+		if(pmeg_ctx[seg] == mm->context) {
+			pmeg_alloc[seg] = 0;
+			pmeg_ctx[seg] = 0;
+			pmeg_vaddr[seg] = 0;
+		}
+		sun3_put_segmap(start, SUN3_INVALID_PMEG);
+	next:
+		start += SUN3_PMEG_SIZE;
+	}
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+	flush_tlb_all();
+}
+
+/* Flush kernel page from TLB. */
+static inline void flush_tlb_kernel_page (unsigned long addr)
+{
+	sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG);
+}
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#endif
+
+#endif /* _M68K_TLBFLUSH_H */
diff -Nru a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
--- a/include/asm-m68k/uaccess.h	Thu May  9 15:21:03 2002
+++ b/include/asm-m68k/uaccess.h	Thu May  9 15:21:03 2002
@@ -4,6 +4,7 @@
 /*
  * User space memory access functions
  */
+#include <linux/errno.h>
 #include <linux/sched.h>
 #include <asm/segment.h>
 
diff -Nru a/include/asm-mips/ide.h b/include/asm-mips/ide.h
--- a/include/asm-mips/ide.h	Thu May  9 15:21:03 2002
+++ b/include/asm-mips/ide.h	Thu May  9 15:21:03 2002
@@ -17,7 +17,7 @@
 #include <asm/io.h>
 
 #ifndef MAX_HWIFS
-# ifdef CONFIG_BLK_DEV_IDEPCI
+# ifdef CONFIG_PCI
 #define MAX_HWIFS	10
 # else
 #define MAX_HWIFS	6
@@ -53,7 +53,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -62,137 +62,12 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-}
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
 #endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-#endif
-	} b;
-} control_t;
+}
 
 #undef  SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
-#if defined(__MIPSEB__)
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
-#endif
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
diff -Nru a/include/asm-mips64/ide.h b/include/asm-mips64/ide.h
--- a/include/asm-mips64/ide.h	Thu May  9 15:21:01 2002
+++ b/include/asm-mips64/ide.h	Thu May  9 15:21:01 2002
@@ -20,10 +20,10 @@
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
-# ifdef CONFIG_BLK_DEV_IDEPCI
-#define MAX_HWIFS	10
+# ifdef CONFIG_PCI
+#  define MAX_HWIFS	10
 # else
-#define MAX_HWIFS	6
+#  define MAX_HWIFS	6
 # endif
 #endif
 
@@ -56,7 +56,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -65,82 +65,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-}
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
 #endif
+}
 
-#define insw(p,a,c)							\
-do {									\
-	unsigned short *ptr = (unsigned short *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		*ptr++ = inw(p);					\
-} while (0)
-#define insl(p,a,c)							\
-do {									\
-	unsigned long *ptr = (unsigned long *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		*ptr++ = inl(p);					\
-} while (0)
-#define outsw(p,a,c)							\
-do {									\
-	unsigned short *ptr = (unsigned short *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		outw(*ptr++, (p));					\
-} while (0)
-#define outsl(p,a,c) {							\
-	unsigned long *ptr = (unsigned long *)(a);			\
-	unsigned int i = (c);						\
-	while (i--)							\
-		outl(*ptr++, (p));					\
-} while (0)
-
-#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
--- a/include/asm-parisc/ide.h	Thu May  9 15:21:05 2002
+++ b/include/asm-parisc/ide.h	Thu May  9 15:21:05 2002
@@ -69,7 +69,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -78,37 +78,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h
--- a/include/asm-ppc/cacheflush.h	Thu May  9 15:21:03 2002
+++ b/include/asm-ppc/cacheflush.h	Thu May  9 15:21:03 2002
@@ -37,5 +37,5 @@
 extern void __flush_dcache_icache(void *page_va);
 extern void __flush_dcache_icache_phys(unsigned long physaddr);
 
-#endif _PPC_CACHEFLUSH_H
-#endif __KERNEL__
+#endif /* _PPC_CACHEFLUSH_H */
+#endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h
--- a/include/asm-ppc/cputable.h	Thu May  9 15:21:06 2002
+++ b/include/asm-ppc/cputable.h	Thu May  9 15:21:06 2002
@@ -67,6 +67,8 @@
 #define CPU_FTR_604_PERF_MON		0x00000080
 #define CPU_FTR_601			0x00000100
 #define CPU_FTR_HPTE_TABLE		0x00000200
+#define CPU_FTR_CAN_NAP			0x00000400
+#define CPU_FTR_L3CR			0x00000800
 
 #ifdef __ASSEMBLY__
 
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Thu May  9 15:21:01 2002
+++ b/include/asm-ppc/hardirq.h	Thu May  9 15:21:01 2002
@@ -8,7 +8,6 @@
 #include <linux/config.h>
 #include <asm/smp.h>
 
-/* entry.S is sensitive to the offsets of these fields */
 /* The __last_jiffy_stamp field is needed to ensure that no decrementer 
  * interrupt is lost on SMP machines. Since on most CPUs it is in the same 
  * cache line as local_irq_count, it is cheap to access and is also used on UP 
@@ -40,8 +39,8 @@
 #define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
-#define hardirq_enter(cpu)	(local_irq_count(cpu)++)
-#define hardirq_exit(cpu)	(local_irq_count(cpu)--)
+#define hardirq_enter(cpu)	do { preempt_disable(); local_irq_count(cpu)++; } while (0)
+#define hardirq_exit(cpu)	do { local_irq_count(cpu)--; preempt_enable(); } while (0)
 
 #define synchronize_irq()	do { } while (0)
 #define release_irqlock(cpu)    do { } while (0)
@@ -75,7 +74,8 @@
 static inline void hardirq_enter(int cpu)
 {
 	unsigned int loops = 10000000;
-	
+
+	preempt_disable();
 	++local_irq_count(cpu);
 	while (test_bit(0,&global_irq_lock)) {
 		if (cpu == global_irq_holder) {
@@ -97,6 +97,7 @@
 static inline void hardirq_exit(int cpu)
 {
 	--local_irq_count(cpu);
+	preempt_enable();
 }
 
 static inline int hardirq_trylock(int cpu)
diff -Nru a/include/asm-ppc/heathrow.h b/include/asm-ppc/heathrow.h
--- a/include/asm-ppc/heathrow.h	Thu May  9 15:21:03 2002
+++ b/include/asm-ppc/heathrow.h	Thu May  9 15:21:03 2002
@@ -25,7 +25,7 @@
  * Bits in feature control register.
  * Bits postfixed with a _N are in inverse logic
  */
-#define HRW_RESET_SCC		0x00000001	/* actually controls transceiver... */
+#define HRW_SCC_TRANS_EN_N	0x00000001	/* Also controls modem power */
 #define HRW_BAY_POWER_N		0x00000002
 #define HRW_BAY_PCI_ENABLE	0x00000004
 #define HRW_BAY_IDE_ENABLE	0x00000008
@@ -51,7 +51,7 @@
 #define HRW_ARB_BYPASS		0x00400000	/* Disable internal PCI arbitrer */
 #define HRW_IDE1_RESET_N	0x00800000	/* Media bay */
 #define HRW_SLOW_SCC_PCLK	0x01000000	/* ??? (0) */
-#define HRW_MODEM_POWER_N	0x02000000	/* Used by internal modem on wallstreet */
+#define HRW_RESET_SCC		0x02000000
 #define HRW_MFDC_CELL_ENABLE	0x04000000	/* ??? (0) */
 #define HRW_USE_MFDC		0x08000000	/* ??? (0) */
 #define HRW_BMAC_IO_ENABLE	0x60000000	/* two bits, not documented in OF */
@@ -59,10 +59,6 @@
 
 /* We OR those features at boot on desktop G3s */
 #define HRW_DEFAULTS		(HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE)
-
-/* Those seem to be different on paddington */
-#define PADD_MODEM_POWER_N	0x00000001	/* modem power on paddington */
-#define PADD_RESET_SCC		0x02000000	/* check this please */
 
 /* Looks like Heathrow has some sort of GPIOs as well... */
 #define HRW_GPIO_MODEM_RESET	0x6d
diff -Nru a/include/asm-ppc/i8259.h b/include/asm-ppc/i8259.h
--- a/include/asm-ppc/i8259.h	Thu May  9 15:21:02 2002
+++ b/include/asm-ppc/i8259.h	Thu May  9 15:21:02 2002
@@ -10,7 +10,7 @@
 extern struct hw_interrupt_type i8259_pic;
 
 void i8259_init(long);
-int i8259_irq(void);
+int i8259_irq(struct pt_regs *regs);
 int i8259_poll(void);
 
 #endif /* _PPC_KERNEL_i8259_H */
diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
--- a/include/asm-ppc/ide.h	Thu May  9 15:21:05 2002
+++ b/include/asm-ppc/ide.h	Thu May  9 15:21:05 2002
@@ -30,8 +30,6 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-
 struct ide_machdep_calls {
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
@@ -43,9 +41,6 @@
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc_generic_ide_fix_driveid((id))
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
@@ -96,7 +91,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 	ide_ioreg_t base;
@@ -109,36 +104,9 @@
 		hw.irq = ide_default_irq(base);
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0/1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- * unless direct IDE on 8xx
- */
 #if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE )
 #define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
 #else
diff -Nru a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h
--- a/include/asm-ppc/mediabay.h	Thu May  9 15:21:02 2002
+++ b/include/asm-ppc/mediabay.h	Thu May  9 15:21:02 2002
@@ -20,7 +20,6 @@
 #define MB_POWER	6	/* media bay contains a Power device (???) */
 #define MB_NO		7	/* media bay contains nothing */
 
-void media_bay_init(void);
 int check_media_bay(struct device_node *which_bay, int what);
 int check_media_bay_by_base(unsigned long base, int what);
 
diff -Nru a/include/asm-ppc/mpc10x.h b/include/asm-ppc/mpc10x.h
--- a/include/asm-ppc/mpc10x.h	Thu May  9 15:21:08 2002
+++ b/include/asm-ppc/mpc10x.h	Thu May  9 15:21:08 2002
@@ -59,6 +59,7 @@
 #define MPC10X_MAPA_ISA_MEM_BASE	0xc0000000
 #define	MPC10X_MAPA_DRAM_OFFSET		0x80000000
 
+#define	MPC10X_MAPA_PCI_INTACK_ADDR	0xbffffff0
 #define	MPC10X_MAPA_PCI_IO_START	0x00000000
 #define	MPC10X_MAPA_PCI_IO_END	       (0x00800000 - 1)
 #define	MPC10X_MAPA_PCI_MEM_START	0x00000000
@@ -75,6 +76,7 @@
 #define MPC10X_MAPB_ISA_MEM_BASE	0x80000000
 #define	MPC10X_MAPB_DRAM_OFFSET		0x00000000
 
+#define	MPC10X_MAPB_PCI_INTACK_ADDR	0xfef00000
 #define	MPC10X_MAPB_PCI_IO_START	0x00000000
 #define	MPC10X_MAPB_PCI_IO_END	       (0x00c00000 - 1)
 #define	MPC10X_MAPB_PCI_MEM_START	0x80000000
diff -Nru a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
--- a/include/asm-ppc/open_pic.h	Thu May  9 15:21:05 2002
+++ b/include/asm-ppc/open_pic.h	Thu May  9 15:21:05 2002
@@ -28,6 +28,19 @@
 #define OPENPIC_VEC_IPI		72	/* and up */
 #define OPENPIC_VEC_SPURIOUS	127
 
+/*
+ * For the OpenPIC_InitSenses table, we include both the sense
+ * and polarity in one number and mask out the value we want
+ * later on. -- Tom
+ */
+#define IRQ_SENSE_MASK		0x1
+#define IRQ_SENSE_LEVEL		0x1
+#define IRQ_SENSE_EDGE		0x0
+
+#define IRQ_POLARITY_MASK	0x2
+#define IRQ_POLARITY_POSITIVE	0x2
+#define IRQ_POLARITY_NEGATIVE	0x0
+
 /* OpenPIC IRQ controller structure */
 extern struct hw_interrupt_type open_pic;
 
@@ -42,7 +55,7 @@
 
 /* Exported functions */
 extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
-extern void openpic_init(int, int, unsigned char *, int);
+extern void openpic_init(int, int, int);
 extern u_int openpic_irq(void);
 extern void openpic_eoi(void);
 extern void openpic_request_IPIs(void);
diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h	Thu May  9 15:21:04 2002
+++ b/include/asm-ppc/page.h	Thu May  9 15:21:04 2002
@@ -90,13 +90,16 @@
 extern void clear_user_page(void *page, unsigned long vaddr);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
-extern unsigned long ppc_memstart;
-extern unsigned long ppc_memoffset;
 #ifndef CONFIG_APUS
 #define PPC_MEMSTART	0
+#define PPC_PGSTART	0
 #define PPC_MEMOFFSET	PAGE_OFFSET
 #else
+extern unsigned long ppc_memstart;
+extern unsigned long ppc_pgstart;
+extern unsigned long ppc_memoffset;
 #define PPC_MEMSTART	ppc_memstart
+#define PPC_PGSTART	ppc_pgstart
 #define PPC_MEMOFFSET	ppc_memoffset
 #endif
 
@@ -136,24 +139,21 @@
 #define __pa(x) ___pa((unsigned long)(x))
 #define __va(x) ((void *)(___va((unsigned long)(x))))
 
-#define MAP_PAGE_RESERVED	(1<<15)
-#define virt_to_page(kaddr)	(mem_map + (((unsigned long)kaddr-PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define pfn_to_page(pfn)	(mem_map + ((pfn) - PPC_PGSTART))
+#define page_to_pfn(page)	((unsigned long)((page) - mem_map) + PPC_PGSTART)
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
-extern unsigned long get_zero_page_fast(void);
+#define pfn_valid(pfn)		(((pfn) - PPC_PGSTART) < max_mapnr)
+#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 /* Pure 2^n version of get_order */
 extern __inline__ int get_order(unsigned long size)
 {
-	int order;
+	int lz;
 
-	size = (size-1) >> (PAGE_SHIFT-1);
-	order = -1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	return order;
+	size = (size-1) >> PAGE_SHIFT;
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
+	return 32 - lz;
 }
 
 #endif /* __ASSEMBLY__ */
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Thu May  9 15:21:04 2002
+++ b/include/asm-ppc/pgtable.h	Thu May  9 15:21:04 2002
@@ -148,7 +148,7 @@
      is cleared in the TLB miss handler before the TLB entry is loaded.
    - All other bits of the PTE are loaded into TLBLO without
      modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
-     software PTE bits.  We actually use use bits 20, 24, 25, 26, and
+     software PTE bits.  We actually use use bits 21, 24, 25, 26, and
      30 respectively for the software bits: ACCESSED, DIRTY, RW, EXEC,
      PRESENT.
 */
@@ -284,6 +284,16 @@
 
 #ifndef __ASSEMBLY__
 /*
+ * Conversions between PTE values and page frame numbers.
+ */
+
+#define pte_pfn(x)		(pte_val(x) >> PAGE_SHIFT)
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+
+#define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define mk_pte(page, prot)	pfn_pte(page_to_pfn(page), prot)
+
+/*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
@@ -301,8 +311,6 @@
 #define	pmd_present(pmd)	(pmd_val(pmd) != 0)
 #define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
 
-#define pte_page(x)		(mem_map+(unsigned long)((pte_val(x)-PPC_MEMSTART) >> PAGE_SHIFT))
-
 #ifndef __ASSEMBLY__
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
@@ -351,25 +359,6 @@
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-
-static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{
-	pte_t pte;
-	pte_val(pte) = physpage | pgprot_val(pgprot);
-	return pte;
-}
-
-#define mk_pte(page,pgprot) \
-({									\
-	pte_t pte;							\
-	pte_val(pte) = (((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART) | pgprot_val(pgprot); \
-	pte;							\
-})
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
diff -Nru a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h
--- a/include/asm-ppc/pmac_feature.h	Thu May  9 15:21:01 2002
+++ b/include/asm-ppc/pmac_feature.h	Thu May  9 15:21:01 2002
@@ -38,9 +38,11 @@
  */
 
 /* PowerSurge are the first generation of PCI Pmacs. This include
- * all of the Grand-Central based machines
+ * all of the Grand-Central based machines. We currently don't
+ * differenciate most of them.
  */
 #define PMAC_TYPE_PSURGE		0x10	/* PowerSurge */
+#define PMAC_TYPE_ANS			0x11	/* Apple Network Server */
 
 /* Here is the infamous serie of OHare based machines
  */
@@ -84,6 +86,7 @@
 #define PMAC_TYPE_PISMO			0x46	/* Pismo PowerBook */
 #define PMAC_TYPE_TITANIUM		0x47	/* Titanium PowerBook */
 #define PMAC_TYPE_TITANIUM2		0x48	/* Titanium II PowerBook */
+#define PMAC_TYPE_TITANIUM3		0x49	/* Titanium III PowerBook (with L3) */
 #define PMAC_TYPE_UNKNOWN_CORE99	0x5f
 
 /* MacRISC2 machines based on the Pangea chipset
@@ -245,7 +248,6 @@
 /* Don't use those directly, they are for the sake of pmac_setup.c */
 extern int pmac_do_feature_call(unsigned int selector, ...);
 extern void pmac_feature_init(void);
-extern void pmac_feature_late_init(void);
 
 #define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
 
diff -Nru a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h
--- a/include/asm-ppc/ppc_asm.h	Thu May  9 15:21:02 2002
+++ b/include/asm-ppc/ppc_asm.h	Thu May  9 15:21:02 2002
@@ -31,6 +31,11 @@
 #define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
 #define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
 
+#define SAVE_NVGPRS(base)	SAVE_GPR(13, base); SAVE_8GPRS(14, base); \
+				SAVE_10GPRS(22, base)
+#define REST_NVGPRS(base)	REST_GPR(13, base); REST_8GPRS(14, base); \
+				REST_10GPRS(22, base)
+
 #define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
 #define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
 #define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
--- a/include/asm-ppc/processor.h	Thu May  9 15:21:01 2002
+++ b/include/asm-ppc/processor.h	Thu May  9 15:21:01 2002
@@ -49,12 +49,12 @@
 #define MSR_LE		(1<<0) 		/* Little Endian */
 
 #ifdef CONFIG_APUS_FAST_EXCEPT
-#define MSR_		MSR_ME|MSR_IP|MSR_RI
+#define MSR_		(MSR_ME|MSR_IP|MSR_RI)
 #else
-#define MSR_		MSR_ME|MSR_RI
+#define MSR_		(MSR_ME|MSR_RI)
 #endif
-#define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
-#define MSR_USER	MSR_KERNEL|MSR_PR|MSR_EE
+#define MSR_KERNEL      (MSR_|MSR_IR|MSR_DR)
+#define MSR_USER	(MSR_KERNEL|MSR_PR|MSR_EE)
 
 /* Floating Point Status and Control Register (FPSCR) Fields */
 
@@ -214,10 +214,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 - 7450 */
+#define	  HID0_TBEN	(1<<26)		/* Timebase enable - 745x */
 #define	  HID0_ECLK	(1<<25)
 #define	  HID0_PAR	(1<<24)
-#define	  HID0_STEN	(1<<24)		/* S/W Tablewalk enable - 7450 */
+#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)
@@ -235,10 +236,10 @@
 #define   HID0_SGE	(1<<7)		/* Store Gathering Enable */
 #define	  HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
 #define	  HID0_DFCA	(1<<6)		/* Data Cache Flush Assist */
+#define   HID0_LRSTK	(1<<4)		/* Link register stack - 745x */
 #define   HID0_BTIC	(1<<5)		/* Branch Target Instr Cache Enable */
-#define   HID0_LRSTK	(1<<4)		/* Link Stack enable - 7450 */
 #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. */
@@ -308,6 +309,24 @@
 #define SPRN_L2CR2      0x3f8
 #define	SPRN_L3CR	0x3FA	/* Level 3 Cache Control Regsiter (7450) */
 #define L3CR_L3E		0x80000000	/* L3 enable */
+#define L3CR_L3PE		0x40000000	/* L3 data parity enable */
+#define L3CR_L3APE		0x20000000	/* L3 addr parity enable */
+#define L3CR_L3SIZ		0x10000000	/* L3 size */
+#define L3CR_L3CLKEN		0x08000000	/* L3 clock enable */
+#define L3CR_L3RES		0x04000000	/* L3 special reserved bit */
+#define L3CR_L3CLKDIV		0x03800000	/* L3 clock divisor */
+#define L3CR_L3IO		0x00400000	/* L3 instruction only */
+#define L3CR_L3SPO		0x00040000	/* L3 sample point override */
+#define L3CR_L3CKSP		0x00030000	/* L3 clock sample point */
+#define L3CR_L3PSP		0x0000e000	/* L3 P-clock sample point */
+#define L3CR_L3REP		0x00001000	/* L3 replacement algorithm */
+#define L3CR_L3HWF		0x00000800	/* L3 hardware flush */
+#define L3CR_L3I		0x00000400	/* L3 global invalidate */
+#define L3CR_L3RT		0x00000300	/* L3 SRAM type */
+#define L3CR_L3NIRCA		0x00000080	/* L3 non-integer ratio clock adj. */
+#define L3CR_L3DO		0x00000040	/* L3 data only mode */
+#define L3CR_PMEN		0x00000004	/* L3 private memory enable */
+#define L3CR_PMSIZ		0x00000001	/* L3 private memory size */
 #define SPRN_MSSCR0	0x3f6	/* Memory Subsystem Control Register 0 */
 #define SPRN_MSSSR0	0x3f7	/* Memory Subsystem Status Register 1 */
 #define SPRN_LDSTCR	0x3f8	/* Load/Store control register */
@@ -471,6 +490,8 @@
 #define	SPRG7   SPRN_SPRG7
 #define	SRR0	SPRN_SRR0	/* Save and Restore Register 0 */
 #define	SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
+#define	SRR2	SPRN_SRR2	/* Save and Restore Register 2 */
+#define	SRR3	SPRN_SRR3	/* Save and Restore Register 3 */
 #define	TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
 #define	TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
 #define	TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
--- a/include/asm-ppc/ptrace.h	Thu May  9 15:21:00 2002
+++ b/include/asm-ppc/ptrace.h	Thu May  9 15:21:00 2002
@@ -33,14 +33,16 @@
 	unsigned long mq;		/* 601 only (not used at present) */
 					/* Used on APUS to hold IPL value. */
 	unsigned long trap;		/* Reason for being here */
+	/* N.B. for critical exceptions on 4xx, the dar and dsisr
+	   fields are overloaded to hold srr0 and srr1. */
 	unsigned long dar;		/* Fault registers */
 	unsigned long dsisr;
 	unsigned long result; 		/* Result of a system call */
 };
-#endif
 
 /* iSeries uses mq field for soft enable flag */
 #define softEnable mq
+#endif /* __ASSEMBLY__ */
 
 #ifdef __KERNEL__
 #define STACK_FRAME_OVERHEAD	16	/* size of minimum stack frame */
@@ -48,8 +50,27 @@
 /* Size of stack frame allocated when calling signal handler. */
 #define __SIGNAL_FRAMESIZE	64
 
+#ifndef __ASSEMBLY__
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
+
+/*
+ * We use the least-significant bit of the trap field to indicate
+ * whether we have saved the full set of registers, or only a
+ * partial set.  A 1 there means the partial set.
+ * On 4xx we use the next bit to indicate whether the exception
+ * is a critical exception (1 means it is).
+ */
+#define FULL_REGS(regs)		(((regs)->trap & 1) == 0)
+#define IS_CRITICAL_EXC(regs)	(((regs)->trap & 2) == 0)
+#define TRAP(regs)		((regs)->trap & ~0xF)
+
+#define CHECK_FULL_REGS(regs)						      \
+do {									      \
+	if ((regs)->trap & 1)						      \
+		printk(KERN_CRIT "%s: partial register set\n", __FUNCTION__); \
+} while (0)
+#endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ppc/smplock.h b/include/asm-ppc/smplock.h
--- a/include/asm-ppc/smplock.h	Thu May  9 15:21:04 2002
+++ b/include/asm-ppc/smplock.h	Thu May  9 15:21:04 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smplock.h 1.10 10/23/01 08:09:35 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * <asm/smplock.h>
@@ -15,26 +15,28 @@
 
 extern spinlock_t kernel_flag;
 
+#ifdef CONFIG_SMP
 #define kernel_locked()		spin_is_locked(&kernel_flag)
+#elif defined(CONFIG_PREEMPT)
+#define kernel_locked()		preempt_get_count()
+#endif
 
 /*
  * Release global kernel lock and global interrupt lock
  */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
+#define release_kernel_lock(task, cpu)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0))	\
+		spin_unlock(&kernel_flag);	\
 } while (0)
 
 /*
  * Re-acquire the kernel lock
  */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
+#define reacquire_kernel_lock(task)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0))	\
+		spin_lock(&kernel_flag);	\
 } while (0)
 
 
@@ -47,8 +49,14 @@
  */
 static __inline__ void lock_kernel(void)
 {
+#ifdef CONFIG_PREEMPT
+	if (current->lock_depth == -1)
+		spin_lock(&kernel_flag);
+	++current->lock_depth;
+#else
 	if (!++current->lock_depth)
 		spin_lock(&kernel_flag);
+#endif /* CONFIG_PREEMPT */
 }
 
 static __inline__ void unlock_kernel(void)
diff -Nru a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h
--- a/include/asm-ppc/softirq.h	Thu May  9 15:21:08 2002
+++ b/include/asm-ppc/softirq.h	Thu May  9 15:21:08 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.softirq.h 1.13 07/12/01 20:02:34 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef __ASM_SOFTIRQ_H
@@ -10,6 +10,7 @@
 
 #define local_bh_disable()			\
 do {						\
+	preempt_disable();			\
 	local_bh_count(smp_processor_id())++;	\
 	barrier();				\
 } while (0)
@@ -18,14 +19,17 @@
 do {						\
 	barrier();				\
 	local_bh_count(smp_processor_id())--;	\
+	preempt_enable();			\
 } while (0)
 
 #define local_bh_enable()				\
 do {							\
+	barrier();					\
 	if (!--local_bh_count(smp_processor_id())	\
 	    && softirq_pending(smp_processor_id())) {	\
 		do_softirq();				\
 	}						\
+	preempt_enable();				\
 } while (0)
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
diff -Nru a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h
--- a/include/asm-ppc/thread_info.h	Thu May  9 15:21:04 2002
+++ b/include/asm-ppc/thread_info.h	Thu May  9 15:21:04 2002
@@ -23,6 +23,8 @@
 	unsigned long		flags;		/* low level flags */
 	int			cpu;		/* cpu we're on */
 	int			preempt_count;	/* not used at present */
+	int			softirq_count;
+	int			hardirq_count;
 };
 
 /*
@@ -67,6 +69,9 @@
 #define TI_EXECDOMAIN	4
 #define TI_FLAGS	8
 #define TI_CPU		12
+#define TI_PREEMPT	16
+#define TI_SOFTIRQ	20
+#define TI_HARDIRQ	24
 
 #define PREEMPT_ACTIVE		0x4000000
 
diff -Nru a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h
--- a/include/asm-ppc/tlbflush.h	Thu May  9 15:21:03 2002
+++ b/include/asm-ppc/tlbflush.h	Thu May  9 15:21:03 2002
@@ -30,7 +30,7 @@
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 				unsigned long vmaddr)
 	{ _tlbie(vmaddr); }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				unsigned long start, unsigned long end)
 	{ __tlbia(); }
 static inline void flush_tlb_kernel_range(unsigned long start,
@@ -86,5 +86,5 @@
 {
 }
 
-#endif _PPC_TLBFLUSH_H
-#endif __KERNEL__
+#endif /* _PPC_TLBFLUSH_H */
+#endif /*__KERNEL__ */
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Thu May  9 15:21:03 2002
+++ b/include/asm-ppc/unistd.h	Thu May  9 15:21:03 2002
@@ -234,7 +234,6 @@
 
 #define __NR(n)	#n
 
-
 #define __syscall_return(type) \
 	return (__sc_err & 0x10000000 ? errno = __sc_ret, __sc_ret = -1 : 0), \
 	       (type) __sc_ret
@@ -403,8 +402,9 @@
 	__syscall_return (type);					\
 }
 
+#ifdef __KERNEL__
 
-#ifdef __KERNEL_SYSCALLS__
+#define __NR__exit __NR_exit
 
 /*
  * Forking from kernel space will result in the child getting a new,
@@ -414,29 +414,24 @@
  * the child.
  */
 
+#ifdef __KERNEL_SYSCALLS__
 /*
  * System call prototypes.
  */
-#define __NR__exit __NR_exit
-static inline _syscall0(int,pause)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall1(int,delete_module,const char *,name)
+extern pid_t setsid(void);
+extern int write(int fd, const char *buf, off_t count);
+extern int read(int fd, char *buf, off_t count);
+extern off_t lseek(int fd, off_t offset, int count);
+extern int dup(int fd);
+extern int execve(const char *file, char **argv, char **envp);
+extern int open(const char *file, int flag, int mode);
+extern int close(int fd);
+extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
 
 static inline pid_t wait(int * wait_stat) 
 {
 	return waitpid(-1, wait_stat, 0);
 }
-
 #endif /* __KERNEL_SYSCALLS__ */
 
 /*
@@ -446,5 +441,7 @@
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_PPC_UNISTD_H_ */
diff -Nru a/include/asm-ppc/zorro.h b/include/asm-ppc/zorro.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/zorro.h	Thu May  9 15:21:10 2002
@@ -0,0 +1,30 @@
+#ifndef _ASM_PPC_ZORRO_H
+#define _ASM_PPC_ZORRO_H
+
+#include <asm/io.h>
+
+#define z_readb in_8
+#define z_readw in_be16
+#define z_readl in_be32
+
+#define z_writeb(val, port) out_8((port), (val))
+#define z_writew(val, port) out_be16((port), (val))
+#define z_writel(val, port) out_be32((port), (val))
+
+#define z_memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define z_memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define z_memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+extern void *__ioremap(unsigned long address, unsigned long size,
+		       unsigned long flags);
+
+extern void *ioremap(unsigned long address, unsigned long size);
+extern void iounmap(void *addr);
+
+extern void *__ioremap(unsigned long address, unsigned long size,
+                       unsigned long flags);
+
+#define z_ioremap ioremap
+#define z_iounmap iounmap
+
+#endif /* _ASM_ZORRO_H */
diff -Nru a/include/asm-ppc64/ide.h b/include/asm-ppc64/ide.h
--- a/include/asm-ppc64/ide.h	Thu May  9 15:21:07 2002
+++ b/include/asm-ppc64/ide.h	Thu May  9 15:21:07 2002
@@ -24,9 +24,6 @@
 
 #define ide__sti()	__sti()
 
-void ppc64_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
-
 static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; }
 static __inline__ ide_ioreg_t ide_default_io_base(int index) { return 0; }
 
@@ -53,33 +50,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-	
-/* XXX is this correct? - Anton */
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
diff -Nru a/include/asm-s390/ide.h b/include/asm-s390/ide.h
--- a/include/asm-s390/ide.h	Thu May  9 15:21:08 2002
+++ b/include/asm-s390/ide.h	Thu May  9 15:21:08 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-arm/ide.h
+ *  linux/include/asm-s390/ide.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
@@ -17,29 +17,6 @@
 
 #define ide__sti()	do {} while (0)
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
 /*
  * The following are not needed for the non-m68k ports
  */
@@ -57,4 +34,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMARM_IDE_H */
+#endif /* __ASMS390_IDE_H */
diff -Nru a/include/asm-s390x/ide.h b/include/asm-s390x/ide.h
--- a/include/asm-s390x/ide.h	Thu May  9 15:21:01 2002
+++ b/include/asm-s390x/ide.h	Thu May  9 15:21:01 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-arm/ide.h
+ *  linux/include/asm-s390/ide.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
@@ -17,34 +17,7 @@
 
 #define ide__sti()	do {} while (0)
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
@@ -57,4 +30,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMARM_IDE_H */
+#endif /* __ASMS390_IDE_H */
diff -Nru a/include/asm-sh/ide.h b/include/asm-sh/ide.h
--- a/include/asm-sh/ide.h	Thu May  9 15:21:04 2002
+++ b/include/asm-sh/ide.h	Thu May  9 15:21:04 2002
@@ -95,7 +95,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -104,37 +104,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
--- a/include/asm-sparc/ide.h	Thu May  9 15:21:07 2002
+++ b/include/asm-sparc/ide.h	Thu May  9 15:21:07 2002
@@ -61,7 +61,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -70,32 +70,9 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -188,84 +165,6 @@
 	/* __flush_dcache_range((unsigned long)src, end); */ /* P3 see hme */
 }
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
 /* #define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) */
 #define ide_release_lock(lock)		do {} while (0)
diff -Nru a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h	Thu May  9 15:21:05 2002
+++ b/include/asm-sparc64/ide.h	Thu May  9 15:21:05 2002
@@ -57,7 +57,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -66,32 +66,9 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -204,84 +181,6 @@
 #endif
 }
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
--- a/include/asm-sparc64/page.h	Thu May  9 15:21:06 2002
+++ b/include/asm-sparc64/page.h	Thu May  9 15:21:06 2002
@@ -113,8 +113,19 @@
 
 #define __pa(x)			((unsigned long)(x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define virt_to_page(kaddr)	(mem_map + ((__pa(kaddr)-phys_base) >> PAGE_SHIFT))
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+
+/* PFNs are real physical page numbers.  However, mem_map only begins to record
+ * per-page information starting at pfn_base.  This is to handle systems where
+ * the first physical page in the machine is at some huge physical address, such
+ * as 4GB.   This is common on a partitioned E10000, for example.
+ */
+
+#define pfn_to_page(pfn)	(mem_map + ((pfn)-(pfn_base)))
+#define page_to_pfn(page)	((unsigned long)(((page) - mem_map) + pfn_base))
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr)>>PAGE_SHIFT)
+
+#define pfn_valid(pfn)		(((pfn)-(pfn_base)) < max_mapnr)
+#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define virt_to_phys __pa
 #define phys_to_virt __va
diff -Nru a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
--- a/include/asm-sparc64/pgtable.h	Thu May  9 15:21:01 2002
+++ b/include/asm-sparc64/pgtable.h	Thu May  9 15:21:01 2002
@@ -190,18 +190,27 @@
 #ifndef __ASSEMBLY__
 
 extern unsigned long phys_base;
+extern unsigned long pfn_base;
 
 extern struct page *mem_map_zero;
 #define ZERO_PAGE(vaddr)	(mem_map_zero)
 
-/* Warning: These take pointers to page structs now... */
-#define mk_pte(page, pgprot)		\
-	__pte((((page - mem_map) << PAGE_SHIFT)+phys_base) | pgprot_val(pgprot) | _PAGE_SZBITS)
+/* PFNs are real physical page numbers.  However, mem_map only begins to record
+ * per-page information starting at pfn_base.  This is to handle systems where
+ * the first physical page in the machine is at some huge physical address, such
+ * as 4GB.   This is common on a partitioned E10000, for example.
+ */
+
+#define pfn_pte(pfn, prot)	\
+	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot) | _PAGE_SZBITS)
+#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
+
+#define pte_pfn(x)		((pte_val(x) & _PAGE_PADDR)>>PAGE_SHIFT)
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+
 #define page_pte_prot(page, prot)	mk_pte(page, prot)
 #define page_pte(page)			page_pte_prot(page, __pgprot(0))
 
-#define mk_pte_phys(physpage, pgprot)	(__pte((physpage) | pgprot_val(pgprot) | _PAGE_SZBITS))
-
 extern inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
 {
 	pte_t __pte;
@@ -245,8 +254,6 @@
 
 /* Permanent address of a page. */
 #define __page_address(page)	page_address(page)
-
-#define pte_page(x) (mem_map+(((pte_val(x)&_PAGE_PADDR)-phys_base)>>PAGE_SHIFT))
 
 /* Be very careful when you change these three, they are delicate. */
 #define pte_mkyoung(pte)	(__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R))
diff -Nru a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h
--- a/include/asm-sparc64/thread_info.h	Thu May  9 15:21:08 2002
+++ b/include/asm-sparc64/thread_info.h	Thu May  9 15:21:08 2002
@@ -24,11 +24,12 @@
 #define TI_FLAG_BYTE_WSAVED		5
 #define TI_FLAG_WSAVED_SHIFT		16
 
+#include <asm/page.h>
+
 #ifndef __ASSEMBLY__
 
 #include <asm/ptrace.h>
 #include <asm/types.h>
-#include <asm/page.h>
 
 struct task_struct;
 struct exec_domain;
diff -Nru a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h
--- a/include/asm-x86_64/ide.h	Thu May  9 15:21:07 2002
+++ b/include/asm-x86_64/ide.h	Thu May  9 15:21:07 2002
@@ -16,7 +16,7 @@
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
-# ifdef CONFIG_BLK_DEV_IDEPCI
+# ifdef CONFIG_PCI
 #define MAX_HWIFS	10
 # else
 #define MAX_HWIFS	6
@@ -74,7 +74,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifndef CONFIG_BLK_DEV_IDEPCI
+#ifndef CONFIG_PCI
 	hw_regs_t hw;
 	int index;
 
@@ -83,37 +83,10 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-/*
- * The following are not needed for the non-m68k ports
- */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h
--- a/include/linux/agp_backend.h	Thu May  9 15:21:04 2002
+++ b/include/linux/agp_backend.h	Thu May  9 15:21:04 2002
@@ -75,7 +75,8 @@
 	ALI_GENERIC,
 	SVWRKS_HE,
 	SVWRKS_LE,
-	SVWRKS_GENERIC
+	SVWRKS_GENERIC,
+	HP_ZX1,
 };
 
 typedef struct _agp_version {
diff -Nru a/include/linux/dnotify.h b/include/linux/dnotify.h
--- a/include/linux/dnotify.h	Thu May  9 15:21:01 2002
+++ b/include/linux/dnotify.h	Thu May  9 15:21:01 2002
@@ -1,14 +1,13 @@
 /*
  * Directory notification for Linux
  *
- * Copyright 2000 (C) Stephen Rothwell
+ * Copyright (C) 2000,2002 Stephen Rothwell
  */
 
 #include <linux/fs.h>
 
 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;
@@ -16,9 +15,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 -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Thu May  9 15:21:06 2002
+++ b/include/linux/hdreg.h	Thu May  9 15:21:06 2002
@@ -280,7 +280,7 @@
       unsigned long start;
 };
 
-/* BIG GEOMETRY */
+/* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */
 struct hd_big_geometry {
 	unsigned char heads;
 	unsigned char sectors;
@@ -327,13 +327,14 @@
 };
 
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
-#define HDIO_GETGEO_BIG		0x0330	/* */
+/* 0x330 is reserved - used to be HDIO_GETGEO_BIG */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
 #define __NEW_HD_DRIVE_ID
 /* structure returned by HDIO_GET_IDENTITY,
  * as per ANSI NCITS ATA6 rev.1b spec
  */
+/* if you change something here remember to update ide_fix_driveid() */
 struct hd_driveid {
 	unsigned short	config;		/* lots of obsolete bit flags */
 	unsigned short	cyls;		/* Obsolete, "physical" cyls */
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Thu May  9 15:21:03 2002
+++ b/include/linux/ide.h	Thu May  9 15:21:03 2002
@@ -15,6 +15,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <asm/byteorder.h>
 #include <asm/hdreg.h>
 
 /*
@@ -46,7 +47,7 @@
 # define DISK_RECOVERY_TIME	0	/*  for hardware that needs it */
 #endif
 #ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
-# define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
+# define OK_TO_RESET_CONTROLLER	0	/* 0 for use with AH2372A/B interface */
 #endif
 #ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
 # define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
@@ -265,6 +266,50 @@
 
 struct ide_settings_s;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number: 0/1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bit7		: 1;
+		unsigned lba		: 1;
+		unsigned bit5		: 1;
+		unsigned unit		: 1;
+		unsigned head		: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned HOB		: 1;
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;
+		unsigned SRST		: 1;
+		unsigned nIEN		: 1;
+		unsigned bit0		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} control_t;
+
 /*
  * ATA/ATAPI device structure :
  */
@@ -282,19 +327,9 @@
 	 */
 	request_queue_t	queue;	/* per device request queue */
 
-
 	unsigned long sleep;	/* sleep until this time */
 
-	/* Flags requesting/indicating one of the following special commands
-	 * executed on the request queue.
-	 */
-#define ATA_SPECIAL_GEOMETRY		0x01
-#define ATA_SPECIAL_RECALIBRATE		0x02
-#define ATA_SPECIAL_MMODE		0x04
-#define ATA_SPECIAL_TUNE		0x08
-	unsigned char special_cmd;
-	u8 mult_req;			/* requested multiple sector setting */
-	u8 tune_req;			/* requested drive tuning setting */
+	u8 XXX_tune_req;			/* requested drive tuning setting */
 
 	byte     using_dma;		/* disk is using dma for read/write */
 	byte	 using_tcq;		/* disk is using queueing */
@@ -344,8 +379,7 @@
 
 	void		*driver_data;	/* extra driver data */
 	devfs_handle_t	de;		/* directory for device */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	struct ide_settings_s *settings;    /* /proc/ide/ drive settings */
+	struct ide_settings_s *settings;    /* ioctl entires */
 	char		driver_req[10];	/* requests specific driver */
 
 	int		last_lun;	/* last logical unit */
@@ -364,6 +398,7 @@
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
 	struct device	device;		/* global device tree handle */
+
 	/*
 	 * tcq statistics
 	 */
@@ -386,7 +421,7 @@
 
 	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
 	hw_regs_t	hw;		/* Hardware info */
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_PCI
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
 #endif
 	struct ata_device drives[MAX_DRIVES];	/* drive info */
@@ -424,6 +459,8 @@
 
 	int (*XXX_udma)(struct ata_device *);
 
+	void (*udma_enable)(struct ata_device *, int, int);
+
 	int (*udma_start) (struct ata_device *, struct request *rq);
 	int (*udma_stop) (struct ata_device *);
 
@@ -472,6 +509,8 @@
 	/* driver soft-power interface */
 	int (*busproc)(struct ata_device *, int);
 	byte		bus_state;	/* power state of the IDE bus */
+
+	unsigned long poll_timeout; /* timeout value during polled operations */
 };
 
 /*
@@ -520,17 +559,19 @@
 	return 1;
 }
 #else
-#define ata_pending_commands(drive)	(0)
-#define ata_can_queue(drive)		(1)
+# define ata_pending_commands(drive)	(0)
+# define ata_can_queue(drive)		(1)
 #endif
 
 typedef struct hwgroup_s {
+	/* FIXME: We should look for busy request queues instead of looking at
+	 * the !NULL state of this field.
+	 */
 	ide_startstop_t (*handler)(struct ata_device *, struct request *);	/* irq handler, if active */
 	unsigned long flags;		/* BUSY, SLEEPING */
 	struct ata_device *XXX_drive;	/* current drive */
 	struct request *rq;		/* current request */
 	struct timer_list timer;	/* failsafe timer */
-	unsigned long poll_timeout;	/* timeout value during long polls */
 	int (*expiry)(struct ata_device *, struct request *);	/* irq handler, if active */
 } ide_hwgroup_t;
 
@@ -572,44 +613,7 @@
 extern int ide_write_setting(struct ata_device *, ide_settings_t *, int);
 extern void ide_add_generic_settings(struct ata_device *);
 
-/*
- * /proc/ide interface
- */
-typedef struct {
-	const char	*name;
-	mode_t		mode;
-	read_proc_t	*read_proc;
-	write_proc_t	*write_proc;
-} ide_proc_entry_t;
-
-#ifdef CONFIG_PROC_FS
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void destroy_proc_ide_drives(struct ata_channel *);
-void create_proc_ide_interfaces(void);
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
-read_proc_t proc_ide_read_capacity;
-read_proc_t proc_ide_read_geometry;
-
-/*
- * Standard exit stuff:
- */
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
-{					\
-	len -= off;			\
-	if (len < count) {		\
-		*eof = 1;		\
-		if (len <= 0)		\
-			return 0;	\
-	} else				\
-		len = count;		\
-	*start = page + off;		\
-	return len;			\
-}
-#else
-# define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
-#endif
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 
 /*
  * This structure describes the operations possible on a particular device type
@@ -631,11 +635,7 @@
 	int (*check_media_change)(struct ata_device *);
 	void (*revalidate)(struct ata_device *);
 
-	void (*pre_reset)(struct ata_device *);
 	sector_t (*capacity)(struct ata_device *);
-	ide_startstop_t	(*special)(struct ata_device *);
-
-	ide_proc_entry_t *proc;
 };
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
@@ -783,20 +783,19 @@
  */
 
 extern ide_startstop_t recal_intr(struct ata_device *, struct request *);
-extern ide_startstop_t set_geometry_intr(struct ata_device *, struct request *);
-extern ide_startstop_t set_multmode_intr(struct ata_device *, struct request *);
 extern ide_startstop_t task_no_data_intr(struct ata_device *, struct request *);
 
 
 /* This is setting up all fields in args, which depend upon the command type.
  */
 extern void ide_cmd_type_parser(struct ata_taskfile *args);
-extern int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *cmd, byte *buf);
+extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *);
 extern int ide_cmd_ioctl(struct ata_device *drive, unsigned long arg);
 
 void ide_delay_50ms(void);
 
 extern byte ide_auto_reduce_xfer(struct ata_device *);
+extern void ide_fix_driveid(struct hd_driveid *id);
 extern int ide_driveid_update(struct ata_device *);
 extern int ide_ata66_check(struct ata_device *, struct ata_taskfile *);
 extern int ide_config_drive_speed(struct ata_device *, byte);
@@ -827,7 +826,6 @@
 void ide_init_subdrivers (void);
 
 extern struct block_device_operations ide_fops[];
-extern ide_proc_entry_t generic_subdriver_entries[];
 
 #ifdef CONFIG_BLK_DEV_IDE
 /* Probe for devices attached to the systems host controllers.
@@ -854,9 +852,9 @@
 extern int ide_register_subdriver(struct ata_device *, struct ata_operations *);
 extern int ide_unregister_subdriver(struct ata_device *drive);
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-# define ON_BOARD		1
-# define NEVER_BOARD		0
+#ifdef CONFIG_PCI
+# define ON_BOARD		0
+# define NEVER_BOARD		1
 # ifdef CONFIG_BLK_DEV_OFFBOARD
 #  define OFF_BOARD		ON_BOARD
 # else
@@ -891,8 +889,9 @@
 extern int check_drive_lists(struct ata_device *, int good_bad);
 extern int XXX_ide_dmaproc(struct ata_device *);
 extern void ide_release_dma(struct ata_channel *);
-extern void ide_setup_dma(struct ata_channel *,	unsigned long, unsigned int) __init;
 extern int ata_start_dma(struct ata_device *, struct request *rq);
+
+extern void ata_init_dma(struct ata_channel *,	unsigned long) __init;
 #endif
 
 extern spinlock_t ide_lock;
diff -Nru a/include/linux/ioport.h b/include/linux/ioport.h
--- a/include/linux/ioport.h	Thu May  9 15:21:03 2002
+++ b/include/linux/ioport.h	Thu May  9 15:21:03 2002
@@ -92,7 +92,8 @@
 			     unsigned long size,
 			     unsigned long min, unsigned long max,
 			     unsigned long align,
-			     void (*alignf)(void *, struct resource *, unsigned long),
+			     void (*alignf)(void *, struct resource *,
+					    unsigned long, unsigned long),
 			     void *alignf_data);
 
 /* Convenience shorthand with allocation */
diff -Nru a/include/linux/isdn/capidev.h b/include/linux/isdn/capidev.h
--- a/include/linux/isdn/capidev.h	Thu May  9 15:21:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/* $Id: capidev.h,v 1.6.6.2 2001/09/23 22:24:33 kai Exp $
- *
- * CAPI 2.0 Interface for Linux
- *
- * Copyright 1996 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-struct capidev {
-	struct capidev *next;
-	struct file    *file;
-	__u16		applid;
-	__u16		errcode;
-	unsigned int    minor;
-
-	struct sk_buff_head recv_queue;
-	wait_queue_head_t recv_wait;
-
-	/* Statistic */
-	unsigned long	nrecvctlpkt;
-	unsigned long	nrecvdatapkt;
-	unsigned long	nsentctlpkt;
-	unsigned long	nsentdatapkt;
-};
diff -Nru a/include/linux/isdn/capilli.h b/include/linux/isdn/capilli.h
--- a/include/linux/isdn/capilli.h	Thu May  9 15:21:06 2002
+++ b/include/linux/isdn/capilli.h	Thu May  9 15:21:06 2002
@@ -12,6 +12,8 @@
 #ifndef __CAPILLI_H__
 #define __CAPILLI_H__
 
+#include <linux/list.h>
+
 typedef struct capiloaddatapart {
 	int user;		/* data in userspace ? */
 	int len;
@@ -34,7 +36,7 @@
 struct capi_driver;
 
 struct capi_ctr {
-        struct capi_ctr *next;			/* next ctr of same driver */
+        struct list_head driver_list;		/* contrs by driver */
         struct capi_driver *driver;
 	int cnr;				/* controller number */
 	char name[32];				/* name of controller */
@@ -57,8 +59,6 @@
         void (*resume_output)(struct capi_ctr * card);
         void (*handle_capimsg)(struct capi_ctr * card,
 			   	__u16 appl, struct sk_buff *skb);
-	void (*appl_registered)(struct capi_ctr * card, __u16 appl);
-	void (*appl_released)(struct capi_ctr * card, __u16 appl);
 
         void (*new_ncci)(struct capi_ctr * card,
 			   	__u16 appl, __u32 ncci, __u32 winsize);
@@ -75,39 +75,38 @@
         char procfn[128];
 };
 
-struct capi_driver_interface {
-    struct capi_ctr *(*attach_ctr)(struct capi_driver *driver, char *name, void *data);
-    int (*detach_ctr)(struct capi_ctr *);
-};
-
 struct capi_driver {
-     char name[32];				/* driver name */
-     char revision[32];
-     int (*load_firmware)(struct capi_ctr *, capiloaddata *);
-     void (*reset_ctr)(struct capi_ctr *);
-     void (*remove_ctr)(struct capi_ctr *);
-     void (*register_appl)(struct capi_ctr *, __u16 appl,
-						capi_register_params *);
-     void (*release_appl)(struct capi_ctr *, __u16 appl);
-     void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
-
-     char *(*procinfo)(struct capi_ctr *);
-     int (*ctr_read_proc)(char *page, char **start, off_t off,
-			       int count, int *eof, struct capi_ctr *card);
-     int (*driver_read_proc)(char *page, char **start, off_t off,
-		               int count, int *eof, struct capi_driver *driver);
-
-     int (*add_card)(struct capi_driver *driver, capicardparams *data);
-
-     /* intitialized by kcapi */
-     struct capi_ctr	*controller;		/* list of controllers */
-     struct capi_driver *next;
-     int ncontroller;
-     struct proc_dir_entry *procent;
-     char procfn[128];
+	struct module *owner;
+	char name[32];				/* driver name */
+	char revision[32];
+	int (*load_firmware)(struct capi_ctr *, capiloaddata *);
+	void (*reset_ctr)(struct capi_ctr *);
+	void (*remove_ctr)(struct capi_ctr *);
+	void (*register_appl)(struct capi_ctr *, __u16 appl,
+			      capi_register_params *);
+	void (*release_appl)(struct capi_ctr *, __u16 appl);
+	void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
+	
+	char *(*procinfo)(struct capi_ctr *);
+	int (*ctr_read_proc)(char *page, char **start, off_t off,
+			     int count, int *eof, struct capi_ctr *card);
+	int (*driver_read_proc)(char *page, char **start, off_t off,
+				int count, int *eof, struct capi_driver *driver);
+	
+	int (*add_card)(struct capi_driver *driver, capicardparams *data);
+	
+	/* intitialized by kcapi */
+	struct list_head contr_head;		/* list of controllers */
+	struct list_head driver_list;
+	int ncontroller;
+	struct proc_dir_entry *procent;
+	char procfn[128];
 };
 
-struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver);
+void attach_capi_driver(struct capi_driver *driver);
 void detach_capi_driver(struct capi_driver *driver);
+
+struct capi_ctr *attach_capi_ctr(struct capi_driver *driver, char *name, void *data);
+int detach_capi_ctr(struct capi_ctr *);
 
 #endif				/* __CAPILLI_H__ */
diff -Nru a/include/linux/kd.h b/include/linux/kd.h
--- a/include/linux/kd.h	Thu May  9 15:21:09 2002
+++ b/include/linux/kd.h	Thu May  9 15:21:09 2002
@@ -132,19 +132,6 @@
 
 #define KDSIGACCEPT	0x4B4E	/* accept kbd generated signals */
 
-struct hwclk_time {
-	unsigned	sec;	/* 0..59 */
-	unsigned	min;	/* 0..59 */
-	unsigned	hour;	/* 0..23 */
-	unsigned	day;	/* 1..31 */
-	unsigned	mon;	/* 0..11 */
-	unsigned	year;	/* 70... */
-	int		wday;	/* 0..6, 0 is Sunday, -1 means unknown/don't set */
-};
-
-#define KDGHWCLK        0x4B50	/* get hardware clock */
-#define KDSHWCLK        0x4B51  /* set hardware clock */
-
 struct kbd_repeat {
 	int delay;	/* in msec; <= 0: don't change */
 	int rate;	/* in msec; <= 0: don't change */
diff -Nru a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
--- a/include/linux/kernelcapi.h	Thu May  9 15:21:03 2002
+++ b/include/linux/kernelcapi.h	Thu May  9 15:21:03 2002
@@ -10,6 +10,8 @@
 #ifndef __KERNELCAPI_H__
 #define __KERNELCAPI_H__
 
+#include <linux/list.h>
+
 #define CAPI_MAXAPPL	128	/* maximum number of applications  */
 #define CAPI_MAXCONTR	16	/* maximum number of controller    */
 #define CAPI_MAXDATAWINDOW	8
@@ -67,21 +69,14 @@
 
 };
 
-struct capi_ncciinfo {
-	__u16 applid;
-	__u32 ncci;
-};
-
 #define	KCI_CONTRUP	0	/* struct capi_profile */
 #define	KCI_CONTRDOWN	1	/* NULL */
-#define	KCI_NCCIUP	2	/* struct capi_ncciinfo */
-#define	KCI_NCCIDOWN	3	/* struct capi_ncciinfo */
 
 struct capi_interface_user {
 	char name[20];
 	void (*callback) (unsigned int cmd, __u32 contr, void *data);
 	/* internal */
-	struct capi_interface_user *next;
+	struct list_head user_list;
 };
 
 struct capi_interface *attach_capi_interface(struct capi_interface_user *);
diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Thu May  9 15:21:01 2002
+++ b/include/linux/pagemap.h	Thu May  9 15:21:01 2002
@@ -2,17 +2,11 @@
 #define _LINUX_PAGEMAP_H
 
 /*
- * Page-mapping primitive inline functions
- *
  * Copyright 1995 Linus Torvalds
  */
-
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/list.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
 #include <linux/highmem.h>
 
 /*
@@ -36,10 +30,8 @@
 	return alloc_pages(x->gfp_mask, 0);
 }
 
-/*
- * From a kernel address, get the "struct page *"
- */
-#define page_cache_entry(x)	virt_to_page(x)
+
+typedef int filler_t(void *, struct page *);
 
 extern struct page * find_get_page(struct address_space *mapping,
 				unsigned long index);
@@ -54,6 +46,9 @@
 				unsigned long index);
 extern struct page * grab_cache_page_nowait(struct address_space *mapping,
 				unsigned long index);
+extern struct page * read_cache_page(struct address_space *mapping,
+				unsigned long index, filler_t *filler,
+				void *data);
 
 extern int add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long index);
@@ -73,21 +68,34 @@
 
 extern void FASTCALL(lock_page(struct page *page));
 extern void FASTCALL(unlock_page(struct page *page));
-extern void end_page_writeback(struct page *page);
 
-extern void ___wait_on_page_locked(struct page *);
+/*
+ * This is exported only for wait_on_page_locked/wait_on_page_writeback.
+ * Never use this directly!
+ */
+extern void FASTCALL(wait_on_page_bit(struct page *page, int bit_nr));
 
+/* 
+ * Wait for a page to be unlocked.
+ *
+ * This must be called with the caller "holding" the page,
+ * ie with increased "page->count" so that the page won't
+ * go away during the wait..
+ */
 static inline void wait_on_page_locked(struct page *page)
 {
 	if (PageLocked(page))
-		___wait_on_page_locked(page);
+		wait_on_page_bit(page, PG_locked);
 }
 
-extern void wake_up_page(struct page *);
-extern void wait_on_page_writeback(struct page *page);
-
-typedef int filler_t(void *, struct page*);
+/* 
+ * Wait for a page to complete writeback
+ */
+static inline void wait_on_page_writeback(struct page *page)
+{
+	if (PageWriteback(page))
+		wait_on_page_bit(page, PG_writeback);
+}
 
-extern struct page *read_cache_page(struct address_space *, unsigned long,
-				filler_t *, void *);
-#endif
+extern void end_page_writeback(struct page *page);
+#endif /* _LINUX_PAGEMAP_H */
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Thu May  9 15:21:07 2002
+++ b/include/linux/pci.h	Thu May  9 15:21:07 2002
@@ -464,9 +464,9 @@
 
 struct pbus_set_ranges_data
 {
-	int found_vga;
 	unsigned long io_start, io_end;
 	unsigned long mem_start, mem_end;
+	unsigned long prefetch_start, prefetch_end;
 };
 
 struct pci_device_id {
@@ -495,13 +495,13 @@
 #define pci_for_each_dev(dev) \
 	for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
 
-void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
 int pcibios_enable_device(struct pci_dev *);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-void pcibios_align_resource(void *, struct resource *, unsigned long);
+void pcibios_align_resource(void *, struct resource *,
+			    unsigned long, unsigned long);
 void pcibios_update_resource(struct pci_dev *, struct resource *,
 			     struct resource *, int);
 void pcibios_update_irq(struct pci_dev *, int irq);
@@ -582,8 +582,7 @@
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pdev_enable_device(struct pci_dev *);
-void pdev_sort_resources(struct pci_dev *, struct resource_list *, u32);
-unsigned long pci_bridge_check_io(struct pci_dev *);
+void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
 #define HAVE_PCI_REQ_REGIONS
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Thu May  9 15:21:06 2002
+++ b/include/linux/pci_ids.h	Thu May  9 15:21:06 2002
@@ -932,6 +932,8 @@
 #define PCI_VENDOR_ID_TTI		0x1103
 #define PCI_DEVICE_ID_TTI_HPT343	0x0003
 #define PCI_DEVICE_ID_TTI_HPT366	0x0004
+#define PCI_DEVICE_ID_TTI_HPT372	0x0005
+#define PCI_DEVICE_ID_TTI_HPT374	0x0008
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_8363_0	0x0305 
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Thu May  9 15:21:09 2002
+++ b/include/linux/reiserfs_fs.h	Thu May  9 15:21:09 2002
@@ -1822,9 +1822,13 @@
 void reiserfs_read_inode2(struct inode * inode, void *p) ;
 void reiserfs_delete_inode (struct inode * inode);
 void reiserfs_write_inode (struct inode * inode, int) ;
-struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data,
-									 int len, int fhtype, int parent);
-int reiserfs_dentry_to_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent);
+struct dentry *reiserfs_get_dentry(struct super_block *, void *) ;
+struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 *data,
+                                     int len, int fhtype,
+				  int (*acceptable)(void *contect, struct dentry *de),
+				  void *context) ;
+int reiserfs_encode_fh( struct dentry *dentry, __u32 *data, int *lenp, 
+						int connectable );
 
 int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
 void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
@@ -1849,6 +1853,7 @@
 int search_by_entry_key (struct super_block * sb, const struct cpu_key * key, 
 			 struct path * path, 
 			 struct reiserfs_dir_entry * de);
+struct dentry *reiserfs_get_parent(struct dentry *) ;
 /* procfs.c */
 
 #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
diff -Nru a/include/linux/zorro.h b/include/linux/zorro.h
--- a/include/linux/zorro.h	Thu May  9 15:21:00 2002
+++ b/include/linux/zorro.h	Thu May  9 15:21:00 2002
@@ -155,6 +155,8 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 
+#include <asm/zorro.h>
+
 struct zorro_dev {
     struct ExpansionRom rom;
     zorro_id id;
@@ -172,7 +174,6 @@
      *  Zorro Functions
      */
 
-extern void zorro_init(void);
 extern void zorro_name_device(struct zorro_dev *dev);
 
 extern struct zorro_dev *zorro_find_device(zorro_id id,
diff -Nru a/include/math-emu/op-1.h b/include/math-emu/op-1.h
--- a/include/math-emu/op-1.h	Thu May  9 15:21:03 2002
+++ b/include/math-emu/op-1.h	Thu May  9 15:21:03 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 -Nru a/include/math-emu/op-2.h b/include/math-emu/op-2.h
--- a/include/math-emu/op-2.h	Thu May  9 15:21:02 2002
+++ b/include/math-emu/op-2.h	Thu May  9 15:21:02 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 -Nru a/include/math-emu/op-4.h b/include/math-emu/op-4.h
--- a/include/math-emu/op-4.h	Thu May  9 15:21:05 2002
+++ b/include/math-emu/op-4.h	Thu May  9 15:21:05 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 -Nru a/include/math-emu/op-common.h b/include/math-emu/op-common.h
--- a/include/math-emu/op-common.h	Thu May  9 15:21:06 2002
+++ b/include/math-emu/op-common.h	Thu May  9 15:21:06 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 */					\
@@ -780,7 +779,6 @@
 		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);	\
diff -Nru a/include/net/route.h b/include/net/route.h
--- a/include/net/route.h	Thu May  9 15:21:01 2002
+++ b/include/net/route.h	Thu May  9 15:21:01 2002
@@ -110,6 +110,10 @@
         unsigned int out_hit;
         unsigned int out_slow_tot;
         unsigned int out_slow_mc;
+        unsigned int gc_total;
+        unsigned int gc_ignored;
+        unsigned int gc_goal_miss;
+        unsigned int gc_dst_overflow;
 } ____cacheline_aligned_in_smp;
 
 extern struct ip_rt_acct *ip_rt_acct;
diff -Nru a/include/scsi/sg.h b/include/scsi/sg.h
--- a/include/scsi/sg.h	Thu May  9 15:21:06 2002
+++ b/include/scsi/sg.h	Thu May  9 15:21:06 2002
@@ -11,12 +11,14 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2002 Douglas Gilbert
 
-    Version: 3.5.25 (20020425)
+    Version: 3.5.25 (20020504)
     This version is for 2.5 series kernels.
 
     Changes since 3.5.24 (20020319)
-    	- use Scsi_Request::upper_private_data
-    	- zero buffers for non-root users
+	- off by one fix for last scatter gather element
+	- if possible compact kiobuf_map into scatter gather list
+	- use Scsi_Request::upper_private_data
+	- zero buffers for non-root users
     Changes since 3.5.23 (20011231)
 	- change EACCES to EPERM when O_RDONLY is insufficient
 	- suppress newlines in host string
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Thu May  9 15:21:02 2002
+++ b/kernel/fork.c	Thu May  9 15:21:02 2002
@@ -387,14 +387,14 @@
 	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);
 
 	if (retval)
-		goto free_pt;
-
-	if (init_new_context(tsk,mm))
 		goto free_pt;
 
 good_mm:
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c	Thu May  9 15:21:10 2002
+++ b/kernel/ptrace.c	Thu May  9 15:21:10 2002
@@ -160,6 +160,7 @@
 		put_page(page);
 		len -= bytes;
 		buf += bytes;
+		addr += bytes;
 	}
 	up_read(&mm->mmap_sem);
 	mmput(mm);
diff -Nru a/kernel/resource.c b/kernel/resource.c
--- a/kernel/resource.c	Thu May  9 15:21:02 2002
+++ b/kernel/resource.c	Thu May  9 15:21:02 2002
@@ -152,7 +152,8 @@
 			 unsigned long size,
 			 unsigned long min, unsigned long max,
 			 unsigned long align,
-			 void (*alignf)(void *, struct resource *, unsigned long),
+			 void (*alignf)(void *, struct resource *,
+					unsigned long, unsigned long),
 			 void *alignf_data)
 {
 	struct resource *this = root->child;
@@ -169,7 +170,7 @@
 			new->end = max;
 		new->start = (new->start + align - 1) & ~(align - 1);
 		if (alignf)
-			alignf(alignf_data, new, size);
+			alignf(alignf_data, new, size, align);
 		if (new->start < new->end && new->end - new->start + 1 >= size) {
 			new->end = new->start + size - 1;
 			return 0;
@@ -189,7 +190,8 @@
 		      unsigned long size,
 		      unsigned long min, unsigned long max,
 		      unsigned long align,
-		      void (*alignf)(void *, struct resource *, unsigned long),
+		      void (*alignf)(void *, struct resource *,
+				     unsigned long, unsigned long),
 		      void *alignf_data)
 {
 	int err;
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Thu May  9 15:21:06 2002
+++ b/kernel/signal.c	Thu May  9 15:21:06 2002
@@ -1110,7 +1110,8 @@
 		    || (k->sa.sa_handler == SIG_DFL
 			&& (sig == SIGCONT ||
 			    sig == SIGCHLD ||
-			    sig == SIGWINCH))) {
+			    sig == SIGWINCH ||
+			    sig == SIGURG))) {
 			spin_lock_irq(&current->sigmask_lock);
 			if (rm_sig_from_queue(sig, current))
 				recalc_sigpending();
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Thu May  9 15:21:05 2002
+++ b/mm/filemap.c	Thu May  9 15:21:05 2002
@@ -600,7 +600,7 @@
 	return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
 }
 
-static void wait_on_page_bit(struct page *page, int bit_nr)
+void wait_on_page_bit(struct page *page, int bit_nr)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	struct task_struct *tsk = current;
@@ -617,28 +617,7 @@
 	__set_task_state(tsk, TASK_RUNNING);
 	remove_wait_queue(waitqueue, &wait);
 }
-
-/* 
- * Wait for a page to be unlocked.
- *
- * This must be called with the caller "holding" the page,
- * ie with increased "page->count" so that the page won't
- * go away during the wait..
- */
-void ___wait_on_page_locked(struct page *page)
-{
-	wait_on_page_bit(page, PG_locked);
-}
-EXPORT_SYMBOL(___wait_on_page_locked);
-
-/* 
- * Wait for a page to complete writeback
- */
-void wait_on_page_writeback(struct page *page)
-{
-	wait_on_page_bit(page, PG_writeback);
-}
-EXPORT_SYMBOL(wait_on_page_writeback);
+EXPORT_SYMBOL(wait_on_page_bit);
 
 /**
  * unlock_page() - unlock a locked page
@@ -705,12 +684,6 @@
 	__set_task_state(tsk, TASK_RUNNING);
 	remove_wait_queue(waitqueue, &wait);
 }
-
-void wake_up_page(struct page *page)
-{
-	wake_up(page_waitqueue(page));
-}
-EXPORT_SYMBOL(wake_up_page);
 
 /*
  * Get an exclusive lock on the page, optimistically
diff -Nru a/mm/page_io.c b/mm/page_io.c
--- a/mm/page_io.c	Thu May  9 15:21:02 2002
+++ b/mm/page_io.c	Thu May  9 15:21:02 2002
@@ -117,9 +117,6 @@
 	page->mapping = &swapper_space;
 	if (!rw_swap_page_base(rw, entry, page))
 		unlock_page(page);
-	if (rw == WRITE)
-		wait_on_page_writeback(page);
-	else
-		wait_on_page_locked(page);
+	wait_on_page_locked(page);
 	page->mapping = NULL;
 }
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Thu May  9 15:21:09 2002
+++ b/mm/slab.c	Thu May  9 15:21:09 2002
@@ -839,7 +839,10 @@
 	down(&cache_chain_sem);
 	{
 		struct list_head *p;
+		mm_segment_t old_fs;
 
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
 		list_for_each(p, &cache_chain) {
 			kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
 			char tmp;
@@ -857,6 +860,7 @@
 				BUG(); 
 			}	
 		}
+		set_fs(old_fs);
 	}
 
 	/* There is no reason to lock our new cache before we
@@ -1965,8 +1969,13 @@
 	name = cachep->name; 
 	{
 	char tmp; 
+	mm_segment_t old_fs;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	if (__get_user(tmp, name)) 
 		name = "broken"; 
+	set_fs(old_fs);
 	} 	
 
 	seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Thu May  9 15:21:03 2002
+++ b/mm/swapfile.c	Thu May  9 15:21:03 2002
@@ -1088,7 +1088,7 @@
 	swap_list_unlock();
 	if (swap_map)
 		vfree(swap_map);
-	if (swap_file)
+	if (swap_file && !IS_ERR(swap_file))
 		filp_close(swap_file, NULL);
 out:
 	if (swap_header)
diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c	Thu May  9 15:21:02 2002
+++ b/net/core/neighbour.c	Thu May  9 15:21:02 2002
@@ -54,12 +54,6 @@
 static int neigh_glbl_allocs;
 static struct neigh_table *neigh_tables;
 
-#if defined(__i386__) && defined(CONFIG_SMP)
-#define ASSERT_WL(n) if ((int)((n)->lock.lock) > 0) { printk("WL assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
-#else
-#define ASSERT_WL(n) do { } while(0)
-#endif
-
 /*
    Neighbour hash table buckets are protected with rwlock tbl->lock.
 
@@ -484,8 +478,6 @@
 
 	NEIGH_PRINTK2("neigh %p is suspecteded.\n", neigh);
 
-	ASSERT_WL(neigh);
-
 	neigh->output = neigh->ops->output;
 
 	for (hh = neigh->hh; hh; hh = hh->hh_next)
@@ -503,8 +495,6 @@
 
 	NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
 
-	ASSERT_WL(neigh);
-
 	neigh->output = neigh->ops->connected_output;
 
 	for (hh = neigh->hh; hh; hh = hh->hh_next)
@@ -529,7 +519,6 @@
 	unsigned long now = jiffies;
 	u8 state = n->nud_state;
 
-	ASSERT_WL(n);
 	if (state&(NUD_NOARP|NUD_PERMANENT))
 		return;
 	if (state&NUD_REACHABLE) {
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c	Thu May  9 15:21:05 2002
+++ b/net/ipv4/arp.c	Thu May  9 15:21:05 2002
@@ -513,7 +513,7 @@
 	skb->nh.raw = skb->data;
 	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
 	skb->dev = dev;
-	skb->protocol = __constant_htons (ETH_P_ARP);
+	skb->protocol = htons(ETH_P_ARP);
 	if (src_hw == NULL)
 		src_hw = dev->dev_addr;
 	if (dest_hw == NULL)
@@ -539,33 +539,33 @@
 	switch (dev->type) {
 	default:
 		arp->ar_hrd = htons(dev->type);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 	case ARPHRD_AX25:
-		arp->ar_hrd = __constant_htons(ARPHRD_AX25);
-		arp->ar_pro = __constant_htons(AX25_P_IP);
+		arp->ar_hrd = htons(ARPHRD_AX25);
+		arp->ar_pro = htons(AX25_P_IP);
 		break;
 
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 	case ARPHRD_NETROM:
-		arp->ar_hrd = __constant_htons(ARPHRD_NETROM);
-		arp->ar_pro = __constant_htons(AX25_P_IP);
+		arp->ar_hrd = htons(ARPHRD_NETROM);
+		arp->ar_pro = htons(AX25_P_IP);
 		break;
 #endif
 #endif
 
 #ifdef CONFIG_FDDI
 	case ARPHRD_FDDI:
-		arp->ar_hrd = __constant_htons(ARPHRD_ETHER);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_hrd = htons(ARPHRD_ETHER);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 #endif
 #ifdef CONFIG_TR
 	case ARPHRD_IEEE802_TR:
-		arp->ar_hrd = __constant_htons(ARPHRD_IEEE802);
-		arp->ar_pro = __constant_htons(ETH_P_IP);
+		arp->ar_hrd = htons(ARPHRD_IEEE802);
+		arp->ar_pro = htons(ETH_P_IP);
 		break;
 #endif
 	}
@@ -629,77 +629,49 @@
 
 	switch (dev_type) {
 	default:	
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
-			goto out;
-		if (htons(dev_type) != arp->ar_hrd)
+		if (arp->ar_pro != htons(ETH_P_IP) ||
+		    htons(dev_type) != arp->ar_hrd)
 			goto out;
 		break;
 #ifdef CONFIG_NET_ETHERNET
 	case ARPHRD_ETHER:
-		/*
-		 * ETHERNET devices will accept ARP hardware types of either
-		 * 1 (Ethernet) or 6 (IEEE 802.2).
-		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
-			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
-			goto out;
-		break;
 #endif
 #ifdef CONFIG_TR
 	case ARPHRD_IEEE802_TR:
-		/*
-		 * Token ring devices will accept ARP hardware types of either
-		 * 1 (Ethernet) or 6 (IEEE 802.2).
-		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
-			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
-			goto out;
-		break;
 #endif
 #ifdef CONFIG_FDDI
 	case ARPHRD_FDDI:
-		/*
-		 * According to RFC 1390, FDDI devices should accept ARP hardware types
-		 * of 1 (Ethernet).  However, to be more robust, we'll accept hardware
-		 * types of either 1 (Ethernet) or 6 (IEEE 802.2).
-		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
-			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
-			goto out;
-		break;
 #endif
 #ifdef CONFIG_NET_FC
 	case ARPHRD_IEEE802:
+#endif
+#if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_TR) || \
+    defined(CONFIG_FDDI)	 || defined(CONFIG_NET_FC)
 		/*
-		 * According to RFC 2625, Fibre Channel devices (which are IEEE
-		 * 802 devices) should accept ARP hardware types of 6 (IEEE 802)
-		 * and 1 (Ethernet).
+		 * ETHERNET, Token Ring and Fibre Channel (which are IEEE 802
+		 * devices, according to RFC 2625) devices will accept ARP
+		 * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
+		 * This is the case also of FDDI, where the RFC 1390 says that
+		 * FDDI devices should accept ARP hardware of (1) Ethernet,
+		 * however, to be more robust, we'll accept both 1 (Ethernet)
+		 * or 6 (IEEE 802.2)
 		 */
-		if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
-		    arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
-			goto out;
-		if (arp->ar_pro != __constant_htons(ETH_P_IP))
+		if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+		    arp->ar_pro != htons(ETH_P_IP))
 			goto out;
 		break;
 #endif
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 	case ARPHRD_AX25:
-		if (arp->ar_pro != __constant_htons(AX25_P_IP))
-			goto out;
-		if (arp->ar_hrd != __constant_htons(ARPHRD_AX25))
+		if (arp->ar_pro != htons(AX25_P_IP) ||
+		    arp->ar_hrd != htons(ARPHRD_AX25))
 			goto out;
 		break;
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 	case ARPHRD_NETROM:
-		if (arp->ar_pro != __constant_htons(AX25_P_IP))
-			goto out;
-		if (arp->ar_hrd != __constant_htons(ARPHRD_NETROM))
+		if (arp->ar_pro != htons(AX25_P_IP) ||
+		    arp->ar_hrd != htons(ARPHRD_NETROM))
 			goto out;
 		break;
 #endif
@@ -708,18 +680,18 @@
 
 	/* Understand only these message types */
 
-	if (arp->ar_op != __constant_htons(ARPOP_REPLY) &&
-	    arp->ar_op != __constant_htons(ARPOP_REQUEST))
+	if (arp->ar_op != htons(ARPOP_REPLY) &&
+	    arp->ar_op != htons(ARPOP_REQUEST))
 		goto out;
 
 /*
  *	Extract fields
  */
-	sha=arp_ptr;
+	sha	= arp_ptr;
 	arp_ptr += dev->addr_len;
 	memcpy(&sip, arp_ptr, 4);
 	arp_ptr += 4;
-	tha=arp_ptr;
+	tha	= arp_ptr;
 	arp_ptr += dev->addr_len;
 	memcpy(&tip, arp_ptr, 4);
 /* 
@@ -754,13 +726,13 @@
 
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
-		if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+		if (arp->ar_op == htons(ARPOP_REQUEST) &&
 		    inet_addr_type(tip) == RTN_LOCAL)
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
 		goto out;
 	}
 
-	if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+	if (arp->ar_op == htons(ARPOP_REQUEST) &&
 	    ip_route_input(skb, tip, sip, 0, dev) == 0) {
 
 		rt = (struct rtable*)skb->dst;
@@ -810,7 +782,7 @@
 	   devices (strip is candidate)
 	 */
 	if (n == NULL &&
-	    arp->ar_op == __constant_htons(ARPOP_REPLY) &&
+	    arp->ar_op == htons(ARPOP_REPLY) &&
 	    inet_addr_type(sip) == RTN_UNICAST)
 		n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
 #endif
@@ -830,7 +802,7 @@
 		/* Broadcast replies and request packets
 		   do not assert neighbour reachability.
 		 */
-		if (arp->ar_op != __constant_htons(ARPOP_REPLY) ||
+		if (arp->ar_op != htons(ARPOP_REPLY) ||
 		    skb->pkt_type != PACKET_HOST)
 			state = NUD_STALE;
 		neigh_update(n, sha, state, override, 1);
@@ -983,7 +955,8 @@
 	struct neighbour *neigh;
 
 	if (r->arp_flags & ATF_PUBL) {
-		u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+		u32 mask =
+		       ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
 		if (mask == 0xFFFFFFFF)
 			return pneigh_delete(&arp_tbl, &ip, dev);
 		if (mask == 0) {
@@ -1027,9 +1000,9 @@
 {
 	int err;
 	struct arpreq r;
-	struct net_device * dev = NULL;
+	struct net_device *dev = NULL;
 
-	switch(cmd) {
+	switch (cmd) {
 		case SIOCDARP:
 		case SIOCSARP:
 			if (!capable(CAP_NET_ADMIN))
@@ -1050,8 +1023,8 @@
 	    (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
 		return -EINVAL;
 	if (!(r.arp_flags & ATF_NETMASK))
-		((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=__constant_htonl(0xFFFFFFFFUL);
-
+		((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
+							   htonl(0xFFFFFFFFUL);
 	rtnl_lock();
 	if (r.arp_dev[0]) {
 		err = -ENODEV;
@@ -1091,7 +1064,10 @@
  *	Write the contents of the ARP cache to a PROCfs file.
  */
 #ifndef CONFIG_PROC_FS
-static int arp_get_info(char *buffer, char **start, off_t offset, int length) { return 0; }
+static int arp_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	return 0;
+}
 #else
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 static char *ax2asc2(ax25_address *a, char *buf);
@@ -1100,70 +1076,57 @@
 
 static int arp_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	int len=0;
-	off_t pos=0;
-	int size;
 	char hbuffer[HBUFFERLEN];
 	int i,j,k;
-	const char hexbuf[] =  "0123456789ABCDEF";
+	const char hexbuf[] = "0123456789ABCDEF";
+	int size = sprintf(buffer, "IP address       HW type     Flags       "
+				   "HW address            Mask     Device\n");
+	int len = size;
+	off_t pos = size;
 
-	size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask     Device\n");
-
-	pos+=size;
-	len+=size;
-
-	for(i=0; i<=NEIGH_HASHMASK; i++) {
+	for (i = 0; i <= NEIGH_HASHMASK; i++) {
 		struct neighbour *n;
 		read_lock_bh(&arp_tbl.lock);
-		for (n=arp_tbl.hash_buckets[i]; n; n=n->next) {
+		for (n = arp_tbl.hash_buckets[i]; n; n = n->next) {
+			char tbuf[16];
 			struct net_device *dev = n->dev;
 			int hatype = dev->type;
 
 			/* Do not confuse users "arp -a" with magic entries */
-			if (!(n->nud_state&~NUD_NOARP))
+			if (!(n->nud_state & ~NUD_NOARP))
 				continue;
 
 			read_lock(&n->lock);
-
-/*
- *	Convert hardware address to XX:XX:XX:XX ... form.
- */
+			/* Convert hardware address to XX:XX:XX:XX ... form. */
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 			if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
 				ax2asc2((ax25_address *)n->ha, hbuffer);
 			else {
 #endif
-			for (k=0,j=0;k<HBUFFERLEN-3 && j<dev->addr_len;j++) {
-				hbuffer[k++]=hexbuf[(n->ha[j]>>4)&15 ];
-				hbuffer[k++]=hexbuf[n->ha[j]&15     ];
-				hbuffer[k++]=':';
+			for (k = 0, j = 0; k < HBUFFERLEN - 3 &&
+					   j < dev->addr_len; j++) {
+				hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
+				hbuffer[k++] = hexbuf[n->ha[j] & 15];
+				hbuffer[k++] = ':';
 			}
-			hbuffer[--k]=0;
-
+			hbuffer[--k] = 0;
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-		}
-#endif
-
-			{
-				char tbuf[16];
-				sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key));
-				size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s"
-							"     *        %s\n",
-					tbuf,
-					hatype,
-					arp_state_to_flags(n), 
-					hbuffer,
-					dev->name);
 			}
-
+#endif
+			sprintf(tbuf, "%u.%u.%u.%u",
+				NIPQUAD(*(u32*)n->primary_key));
+			size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
+						     "     *        %s\n",
+				       tbuf, hatype, arp_state_to_flags(n), 
+				       hbuffer, dev->name);
 			read_unlock(&n->lock);
 
 			len += size;
 			pos += size;
 		  
 			if (pos <= offset)
-				len=0;
-			if (pos >= offset+length) {
+				len = 0;
+			if (pos >= offset + length) {
 				read_unlock_bh(&arp_tbl.lock);
  				goto done;
 			}
@@ -1171,41 +1134,32 @@
 		read_unlock_bh(&arp_tbl.lock);
 	}
 
-	for (i=0; i<=PNEIGH_HASHMASK; i++) {
+	for (i = 0; i <= PNEIGH_HASHMASK; i++) {
 		struct pneigh_entry *n;
-		for (n=arp_tbl.phash_buckets[i]; n; n=n->next) {
+		for (n = arp_tbl.phash_buckets[i]; n; n = n->next) {
 			struct net_device *dev = n->dev;
 			int hatype = dev ? dev->type : 0;
-
-			{
-				char tbuf[16];
-				sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
-				size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s"
-							"     *        %s\n",
-					tbuf,
-					hatype,
- 					ATF_PUBL|ATF_PERM,
+			char tbuf[16];
+			sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
+			size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
+						     "     *        %s\n",
+					tbuf, hatype, ATF_PUBL | ATF_PERM,
 					"00:00:00:00:00:00",
 					dev ? dev->name : "*");
-			}
-
 			len += size;
 			pos += size;
 		  
 			if (pos <= offset)
-				len=0;
+				len = 0;
 			if (pos >= offset+length)
 				goto done;
 		}
 	}
-
-done:
-  
-	*start = buffer+len-(pos-offset);	/* Start of wanted data */
-	len = pos-offset;			/* Start slop */
-	if (len>length)
+done:	*start = buffer + len - (pos - offset);	/* Start of wanted data */
+	len = pos - offset;			/* Start slop */
+	if (len > length)
 		len = length;			/* Ending slop */
-	if (len<0)
+	if (len < 0)
 		len = 0;
 	return len;
 }
@@ -1240,7 +1194,8 @@
 	proc_net_create ("arp", 0, arp_get_info);
 
 #ifdef CONFIG_SYSCTL
-	neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
+	neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
+			      NET_IPV4_NEIGH, "ipv4");
 #endif
 }
 
diff -Nru a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
--- a/net/ipv4/netfilter/ipt_ULOG.c	Thu May  9 15:21:05 2002
+++ b/net/ipv4/netfilter/ipt_ULOG.c	Thu May  9 15:21:05 2002
@@ -29,7 +29,7 @@
  *   Specify, after how many clock ticks (intel: 100 per second) the queue
  * should be flushed even if it is not full yet.
  *
- * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ * ipt_ULOG.c,v 1.18 2002/04/16 07:33:00 laforge Exp
  */
 
 #include <linux/module.h>
@@ -339,10 +339,28 @@
 
 static void __exit fini(void)
 {
+	ulog_buff_t *ub;
+	int i;
+
 	DEBUGP("ipt_ULOG: cleanup_module\n");
 
 	ipt_unregister_target(&ipt_ulog_reg);
 	sock_release(nflognl->socket);
+
+	/* remove pending timers and free allocated skb's */
+	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+		ub = &ulog_buffers[i];
+		if (timer_pending(&ub->timer)) {
+			DEBUGP("timer was pending, deleting\n");
+			del_timer(&ub->timer);
+		}
+
+		if (ub->skb) {
+			kfree_skb(ub->skb);
+			ub->skb = NULL;
+		}
+	}
+
 }
 
 module_init(init);
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Thu May  9 15:21:10 2002
+++ b/net/ipv4/route.c	Thu May  9 15:21:10 2002
@@ -286,7 +286,7 @@
         for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) {
                 i = cpu_logical_map(lcpu);
 
-		len += sprintf(buffer+len, "%08x  %08x %08x %08x %08x %08x %08x %08x  %08x %08x %08x\n",
+		len += sprintf(buffer+len, "%08x  %08x %08x %08x %08x %08x %08x %08x  %08x %08x %08x %08x %08x %08x %08x \n",
 			       dst_entries,		       
 			       rt_cache_stat[i].in_hit,
 			       rt_cache_stat[i].in_slow_tot,
@@ -298,7 +298,13 @@
 
 			       rt_cache_stat[i].out_hit,
 			       rt_cache_stat[i].out_slow_tot,
-			       rt_cache_stat[i].out_slow_mc
+			       rt_cache_stat[i].out_slow_mc, 
+
+			       rt_cache_stat[i].gc_total,
+			       rt_cache_stat[i].gc_ignored,
+			       rt_cache_stat[i].gc_goal_miss,
+			       rt_cache_stat[i].gc_dst_overflow
+
 			);
 	}
 	len -= offset;
@@ -499,9 +505,14 @@
 	 * Garbage collection is pretty expensive,
 	 * do not make it too frequently.
 	 */
+
+	rt_cache_stat[smp_processor_id()].gc_total++;
+
 	if (now - last_gc < ip_rt_gc_min_interval &&
-	    atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+	    atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) {
+		rt_cache_stat[smp_processor_id()].gc_ignored++;
 		goto out;
+	}
 
 	/* Calculate number of entries, which we want to expire now. */
 	goal = atomic_read(&ipv4_dst_ops.entries) -
@@ -567,6 +578,8 @@
 		     We will not spin here for long time in any case.
 		 */
 
+		rt_cache_stat[smp_processor_id()].gc_goal_miss++;
+
 		if (expire == 0)
 			break;
 
@@ -584,6 +597,7 @@
 		goto out;
 	if (net_ratelimit())
 		printk(KERN_WARNING "dst cache overflow\n");
+	rt_cache_stat[smp_processor_id()].gc_dst_overflow++;
 	return 1;
 
 work_done:
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Thu May  9 15:21:04 2002
+++ b/net/ipv4/tcp.c	Thu May  9 15:21:04 2002
@@ -204,7 +204,7 @@
  *		Andi Kleen 	:	Make poll agree with SIGIO
  *	Salvatore Sanfilippo	:	Support SO_LINGER with linger == 1 and
  *					lingertime == 0 (RFC 793 ABORT Call)
- *					
+ *
  *		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
@@ -261,7 +261,7 @@
 
 int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
 
-struct tcp_mib	tcp_statistics[NR_CPUS*2];
+struct tcp_mib	tcp_statistics[NR_CPUS * 2];
 
 kmem_cache_t *tcp_openreq_cachep;
 kmem_cache_t *tcp_bucket_cachep;
@@ -270,8 +270,8 @@
 atomic_t tcp_orphan_count = ATOMIC_INIT(0);
 
 int sysctl_tcp_mem[3];
-int sysctl_tcp_wmem[3] = { 4*1024, 16*1024, 128*1024 };
-int sysctl_tcp_rmem[3] = { 4*1024, 87380, 87380*2 };
+int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
+int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
 
 atomic_t tcp_memory_allocated;	/* Current allocated memory. */
 atomic_t tcp_sockets_allocated;	/* Current number of TCP sockets. */
@@ -282,13 +282,13 @@
  * is strict, actions are advisory and have some latency. */
 int tcp_memory_pressure;
 
-#define TCP_PAGES(amt) (((amt)+TCP_MEM_QUANTUM-1)/TCP_MEM_QUANTUM)
+#define TCP_PAGES(amt) (((amt) + TCP_MEM_QUANTUM - 1) / TCP_MEM_QUANTUM)
 
 int tcp_mem_schedule(struct sock *sk, int size, int kind)
 {
 	int amt = TCP_PAGES(size);
 
-	sk->forward_alloc += amt*TCP_MEM_QUANTUM;
+	sk->forward_alloc += amt * TCP_MEM_QUANTUM;
 	atomic_add(amt, &tcp_memory_allocated);
 
 	/* Under limit. */
@@ -317,25 +317,26 @@
 	}
 
 	if (!tcp_memory_pressure ||
-	    sysctl_tcp_mem[2] > atomic_read(&tcp_sockets_allocated)
-	    * TCP_PAGES(sk->wmem_queued+atomic_read(&sk->rmem_alloc)+
-			sk->forward_alloc))
+	    sysctl_tcp_mem[2] > atomic_read(&tcp_sockets_allocated) *
+				TCP_PAGES(sk->wmem_queued +
+					  atomic_read(&sk->rmem_alloc) +
+					  sk->forward_alloc))
 		return 1;
 
 suppress_allocation:
 
-	if (kind == 0) {
+	if (!kind) {
 		tcp_moderate_sndbuf(sk);
 
 		/* Fail only if socket is _under_ its sndbuf.
 		 * In this case we cannot block, so that we have to fail.
 		 */
-		if (sk->wmem_queued+size >= sk->sndbuf)
+		if (sk->wmem_queued + size >= sk->sndbuf)
 			return 1;
 	}
 
 	/* Alas. Undo changes. */
-	sk->forward_alloc -= amt*TCP_MEM_QUANTUM;
+	sk->forward_alloc -= amt * TCP_MEM_QUANTUM;
 	atomic_sub(amt, &tcp_memory_allocated);
 	return 0;
 }
@@ -343,8 +344,9 @@
 void __tcp_mem_reclaim(struct sock *sk)
 {
 	if (sk->forward_alloc >= TCP_MEM_QUANTUM) {
-		atomic_sub(sk->forward_alloc/TCP_MEM_QUANTUM, &tcp_memory_allocated);
-		sk->forward_alloc &= (TCP_MEM_QUANTUM-1);
+		atomic_sub(sk->forward_alloc / TCP_MEM_QUANTUM,
+			   &tcp_memory_allocated);
+		sk->forward_alloc &= TCP_MEM_QUANTUM - 1;
 		if (tcp_memory_pressure &&
 		    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0])
 			tcp_memory_pressure = 0;
@@ -362,7 +364,8 @@
 /*
  * LISTEN is a special case for poll..
  */
-static __inline__ unsigned int tcp_listen_poll(struct sock *sk, poll_table *wait)
+static __inline__ unsigned int tcp_listen_poll(struct sock *sk,
+					       poll_table *wait)
 {
 	return tcp_sk(sk)->accept_queue ? (POLLIN | POLLRDNORM) : 0;
 }
@@ -374,7 +377,7 @@
  *	take care of normal races (between the test and the event) and we don't
  *	go look at any of the socket buffers directly.
  */
-unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
+unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
 	unsigned int mask;
 	struct sock *sk = sock->sk;
@@ -426,13 +429,13 @@
 		mask |= POLLIN | POLLRDNORM;
 
 	/* Connected? */
-	if ((1 << sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
+	if ((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 		/* Potential race condition. If read of tp below will
 		 * escape above sk->state, we can be illegally awaken
 		 * in SYN_* states. */
 		if ((tp->rcv_nxt != tp->copied_seq) &&
 		    (tp->urg_seq != tp->copied_seq ||
-		     tp->rcv_nxt != tp->copied_seq+1 ||
+		     tp->rcv_nxt != tp->copied_seq + 1 ||
 		     sk->urginline || !tp->urg_data))
 			mask |= POLLIN | POLLRDNORM;
 
@@ -471,7 +474,7 @@
 		if (sk->sleep && waitqueue_active(sk->sleep))
 			wake_up_interruptible(sk->sleep);
 
-		if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN))
+		if (sock->fasync_list && !(sk->shutdown & SEND_SHUTDOWN))
 			sock_wake_async(sock, 2, POLL_OUT);
 	}
 }
@@ -481,42 +484,41 @@
 	struct tcp_opt *tp = tcp_sk(sk);
 	int answ;
 
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCINQ:
 		if (sk->state == TCP_LISTEN)
-			return(-EINVAL);
+			return -EINVAL;
 
 		lock_sock(sk);
-		if ((1<<sk->state) & (TCPF_SYN_SENT|TCPF_SYN_RECV))
+		if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
 			answ = 0;
 		else if (sk->urginline || !tp->urg_data ||
-			 before(tp->urg_seq,tp->copied_seq) ||
-			 !before(tp->urg_seq,tp->rcv_nxt)) {
+			 before(tp->urg_seq, tp->copied_seq) ||
+			 !before(tp->urg_seq, tp->rcv_nxt)) {
 			answ = tp->rcv_nxt - tp->copied_seq;
 
 			/* Subtract 1, if FIN is in queue. */
 			if (answ && !skb_queue_empty(&sk->receive_queue))
-				answ -= ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin;
+				answ -=
+			   ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin;
 		} else
 			answ = tp->urg_seq - tp->copied_seq;
 		release_sock(sk);
 		break;
 	case SIOCATMARK:
-		{
-			answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
-			break;
-		}
+		answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
+		break;
 	case SIOCOUTQ:
 		if (sk->state == TCP_LISTEN)
-			return(-EINVAL);
+			return -EINVAL;
 
-		if ((1<<sk->state) & (TCPF_SYN_SENT|TCPF_SYN_RECV))
+		if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
 			answ = 0;
 		else
 			answ = tp->write_seq - tp->snd_una;
 		break;
 	default:
-		return(-ENOIOCTLCMD);
+		return -ENOIOCTLCMD;
 	};
 
 	return put_user(answ, (int *)arg);
@@ -541,7 +543,7 @@
 
 	memset(lopt, 0, sizeof(struct tcp_listen_opt));
 	for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++)
-		if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog)
+		if ((1 << lopt->max_qlen_log) >= sysctl_max_syn_backlog)
 			break;
 
 	write_lock_bh(&tp->syn_wait_lock);
@@ -588,12 +590,12 @@
 
 	/* make all the listen_opt local to us */
 	write_lock_bh(&tp->syn_wait_lock);
-	tp->listen_opt =NULL;
+	tp->listen_opt = NULL;
 	write_unlock_bh(&tp->syn_wait_lock);
 	tp->accept_queue = tp->accept_queue_tail = NULL;
 
 	if (lopt->qlen) {
-		for (i=0; i<TCP_SYNQ_HSIZE; i++) {
+		for (i = 0; i < TCP_SYNQ_HSIZE; i++) {
 			while ((req = lopt->syn_table[i]) != NULL) {
 				lopt->syn_table[i] = req->dl_next;
 				lopt->qlen--;
@@ -601,7 +603,7 @@
 
 		/* Following specs, it would be better either to send FIN
 		 * (and enter FIN-WAIT-1, it is normal close)
-		 * or to send active reset (abort). 
+		 * or to send active reset (abort).
 		 * Certainly, it is pretty dangerous while synflood, but it is
 		 * bad justification for our negligence 8)
 		 * To be honest, we are not able to make either
@@ -610,18 +612,18 @@
 			}
 		}
 	}
-	BUG_TRAP(lopt->qlen == 0);
+	BUG_TRAP(!lopt->qlen);
 
 	kfree(lopt);
 
-	while ((req=acc_req) != NULL) {
+	while ((req = acc_req) != NULL) {
 		struct sock *child = req->sk;
 
 		acc_req = req->dl_next;
 
 		local_bh_disable();
 		bh_lock_sock(child);
-		BUG_TRAP(child->lock.users==0);
+		BUG_TRAP(!child->lock.users);
 		sock_hold(child);
 
 		tcp_disconnect(child, O_NONBLOCK);
@@ -639,7 +641,7 @@
 		tcp_acceptq_removed(sk);
 		tcp_openreq_fastfree(req);
 	}
-	BUG_TRAP(sk->ack_backlog == 0);
+	BUG_TRAP(!sk->ack_backlog);
 }
 
 /*
@@ -647,21 +649,20 @@
  *
  *	Note: Must be called with the socket locked.
  */
-static int wait_for_tcp_connect(struct sock * sk, int flags, long *timeo_p)
+static int wait_for_tcp_connect(struct sock *sk, int flags, long *timeo_p)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
-		if(sk->err)
+	while ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
+		if (sk->err)
 			return sock_error(sk);
-		if((1 << sk->state) &
-		   ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
+		if ((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
 			return -EPIPE;
-		if(!*timeo_p)
+		if (!*timeo_p)
 			return -EAGAIN;
-		if(signal_pending(tsk))
+		if (signal_pending(tsk))
 			return sock_intr_errno(*timeo_p);
 
 		__set_task_state(tsk, TASK_INTERRUPTIBLE);
@@ -687,7 +688,7 @@
 /*
  *	Wait for more memory for a socket
  */
-static int wait_for_tcp_memory(struct sock * sk, long *timeo)
+static int wait_for_tcp_memory(struct sock *sk, long *timeo)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
 	int err = 0;
@@ -696,7 +697,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 
 	if (tcp_memory_free(sk))
-		current_timeo = vm_wait = (net_random()%(HZ/5))+2;
+		current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2;
 
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
@@ -748,27 +749,28 @@
 	goto out;
 }
 
-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags);
+ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
+			 size_t psize, int flags);
 
-static inline int
-can_coalesce(struct sk_buff *skb, int i, struct page *page, int off)
+static inline int can_coalesce(struct sk_buff *skb, int i, struct page *page,
+			       int off)
 {
 	if (i) {
-		skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
 		return page == frag->page &&
-			off == frag->page_offset+frag->size;
+		       off == frag->page_offset + frag->size;
 	}
 	return 0;
 }
 
-static inline void
-fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size)
+static inline void fill_page_desc(struct sk_buff *skb, int i,
+				  struct page *page, int off, int size)
 {
 	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 	frag->page = page;
 	frag->page_offset = off;
 	frag->size = size;
-	skb_shinfo(skb)->nr_frags = i+1;
+	skb_shinfo(skb)->nr_frags = i + 1;
 }
 
 static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb)
@@ -779,11 +781,11 @@
 
 static inline int forced_push(struct tcp_opt *tp)
 {
-	return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1));
+	return after(tp->write_seq, tp->pushed_seq + (tp->max_window >> 1));
 }
 
-static inline void
-skb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
+static inline void skb_entail(struct sock *sk, struct tcp_opt *tp,
+			      struct sk_buff *skb)
 {
 	skb->csum = 0;
 	TCP_SKB_CB(skb)->seq = tp->write_seq;
@@ -792,12 +794,12 @@
 	TCP_SKB_CB(skb)->sacked = 0;
 	__skb_queue_tail(&sk->write_queue, skb);
 	tcp_charge_skb(sk, skb);
-	if (tp->send_head == NULL)
+	if (!tp->send_head)
 		tp->send_head = skb;
 }
 
-static inline void
-tcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb)
+static inline void tcp_mark_urg(struct tcp_opt *tp, int flags,
+				struct sk_buff *skb)
 {
 	if (flags & MSG_OOB) {
 		tp->urg_mode = 1;
@@ -806,15 +808,16 @@
 	}
 }
 
-static inline void
-tcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle)
+static inline void tcp_push(struct sock *sk, struct tcp_opt *tp, int flags,
+			    int mss_now, int nonagle)
 {
 	if (tp->send_head) {
 		struct sk_buff *skb = sk->write_queue.prev;
-		if (!(flags&MSG_MORE) || forced_push(tp))
+		if (!(flags & MSG_MORE) || forced_push(tp))
 			tcp_mark_push(tp, skb);
 		tcp_mark_urg(tp, flags, skb);
-		__tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle);
+		__tcp_push_pending_frames(sk, tp, mss_now,
+					  (flags & MSG_MORE) ? 2 : nonagle);
 	}
 }
 
@@ -822,22 +825,23 @@
 {
 	if (err == -EPIPE)
 		err = sock_error(sk) ? : -EPIPE;
-	if (err == -EPIPE && !(flags&MSG_NOSIGNAL))
+	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
 		send_sig(SIGPIPE, current, 0);
 	return err;
 }
 
-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags)
+ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
+			 size_t psize, int flags)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
 	int mss_now;
 	int err;
 	ssize_t copied;
-	long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);
+	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
 	/* Wait for a connection to finish. */
 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
-		if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0)
+		if ((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0)
 			goto out_err;
 
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
@@ -851,20 +855,19 @@
 
 	while (psize > 0) {
 		struct sk_buff *skb = sk->write_queue.prev;
-		int offset, size, copy, i;
-		struct page *page;
-
-		page = pages[poffset/PAGE_SIZE];
-		offset = poffset % PAGE_SIZE;
-		size = min_t(size_t, psize, PAGE_SIZE-offset);
+		struct page *page = pages[poffset / PAGE_SIZE];
+		int copy, i;
+		int offset = poffset % PAGE_SIZE;
+		int size = min_t(size_t, psize, PAGE_SIZE - offset);
 
-		if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) {
+		if (!tp->send_head || (copy = mss_now - skb->len) <= 0) {
 new_segment:
 			if (!tcp_memory_free(sk))
 				goto wait_for_sndbuf;
 
-			skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation);
-			if (skb == NULL)
+			skb = tcp_alloc_pskb(sk, 0, tp->mss_cache,
+					     sk->allocation);
+			if (!skb)
 				goto wait_for_memory;
 
 			skb_entail(sk, tp, skb);
@@ -876,7 +879,7 @@
 
 		i = skb_shinfo(skb)->nr_frags;
 		if (can_coalesce(skb, i, page, offset)) {
-			skb_shinfo(skb)->frags[i-1].size += copy;
+			skb_shinfo(skb)->frags[i - 1].size += copy;
 		} else if (i < MAX_SKB_FRAGS) {
 			get_page(page);
 			fill_page_desc(skb, i, page, offset, copy);
@@ -899,7 +902,7 @@
 		if (!(psize -= copy))
 			goto out;
 
-		if (skb->len != mss_now || (flags&MSG_OOB))
+		if (skb->len != mss_now || (flags & MSG_OOB))
 			continue;
 
 		if (forced_push(tp)) {
@@ -913,7 +916,7 @@
 		set_bit(SOCK_NOSPACE, &sk->socket->flags);
 wait_for_memory:
 		if (copied)
-			tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);
+			tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, 1);
 
 		if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)
 			goto do_error;
@@ -933,14 +936,15 @@
 	return tcp_error(sk, flags, err);
 }
 
-ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
+ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
+		     size_t size, int flags)
 {
 	ssize_t res;
 	struct sock *sk = sock->sk;
 
-#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
+#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
 
-	if (!(sk->route_caps & NETIF_F_SG) || 
+	if (!(sk->route_caps & NETIF_F_SG) ||
 	    !(sk->route_caps & TCP_ZC_CSUM_FLAGS))
 		return sock_no_sendpage(sock, page, offset, size, flags);
 
@@ -957,14 +961,14 @@
 #define TCP_PAGE(sk)	(tcp_sk(sk)->sndmsg_page)
 #define TCP_OFF(sk)	(tcp_sk(sk)->sndmsg_off)
 
-static inline int
-tcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb,
-		 struct page *page, int off, int copy)
+static inline int tcp_copy_to_page(struct sock *sk, char *from,
+				   struct sk_buff *skb, struct page *page,
+				   int off, int copy)
 {
 	int err = 0;
 	unsigned int csum;
 
-	csum = csum_and_copy_from_user(from, page_address(page)+off,
+	csum = csum_and_copy_from_user(from, page_address(page) + off,
 				       copy, 0, &err);
 	if (!err) {
 		if (skb->ip_summed == CHECKSUM_NONE)
@@ -978,8 +982,7 @@
 	return err;
 }
 
-static inline int
-skb_add_data(struct sk_buff *skb, char *from, int copy)
+static inline int skb_add_data(struct sk_buff *skb, char *from, int copy)
 {
 	int err = 0;
 	unsigned int csum;
@@ -1000,10 +1003,11 @@
 {
 	int tmp = tp->mss_cache;
 
-	if (sk->route_caps&NETIF_F_SG) {
+	if (sk->route_caps & NETIF_F_SG) {
 		int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
 
-		if (tmp >= pgbreak && tmp <= pgbreak + (MAX_SKB_FRAGS-1)*PAGE_SIZE)
+		if (tmp >= pgbreak &&
+		    tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE)
 			tmp = pgbreak;
 	}
 	return tmp;
@@ -1023,11 +1027,11 @@
 	TCP_CHECK_TIMER(sk);
 
 	flags = msg->msg_flags;
-	timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);
+	timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
 	/* Wait for a connection to finish. */
 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
-		if((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0)
+		if ((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0)
 			goto out_err;
 
 	/* This should be in poll */
@@ -1041,21 +1045,21 @@
 	copied = 0;
 
 	err = -EPIPE;
-	if (sk->err || (sk->shutdown&SEND_SHUTDOWN))
+	if (sk->err || (sk->shutdown & SEND_SHUTDOWN))
 		goto do_error;
 
 	while (--iovlen >= 0) {
-		int seglen=iov->iov_len;
-		unsigned char * from=iov->iov_base;
+		int seglen = iov->iov_len;
+		unsigned char *from = iov->iov_base;
 
 		iov++;
 
 		while (seglen > 0) {
 			int copy;
-			
+
 			skb = sk->write_queue.prev;
 
-			if (tp->send_head == NULL ||
+			if (!tp->send_head ||
 			    (copy = mss_now - skb->len) <= 0) {
 
 new_segment:
@@ -1065,8 +1069,9 @@
 				if (!tcp_memory_free(sk))
 					goto wait_for_sndbuf;
 
-				skb = tcp_alloc_pskb(sk, select_size(sk, tp), 0, sk->allocation);
-				if (skb == NULL)
+				skb = tcp_alloc_pskb(sk, select_size(sk, tp),
+						     0, sk->allocation);
+				if (!skb)
 					goto wait_for_memory;
 
 				skb_entail(sk, tp, skb);
@@ -1090,22 +1095,26 @@
 				struct page *page = TCP_PAGE(sk);
 				int off = TCP_OFF(sk);
 
-				if (can_coalesce(skb, i, page, off) && off != PAGE_SIZE) {
-					/* We can extend the last page fragment. */
+				if (can_coalesce(skb, i, page, off) &&
+				    off != PAGE_SIZE) {
+					/* We can extend the last page
+					 * fragment. */
 					merge = 1;
 				} else if (i == MAX_SKB_FRAGS ||
-					   (i == 0 && !(sk->route_caps&NETIF_F_SG))) {
+					   (!i &&
+					    !(sk->route_caps & NETIF_F_SG))) {
 					/* Need to add new fragment and cannot
 					 * do this because interface is non-SG,
-					 * or because all the page slots are busy.
-					 */
+					 * or because all the page slots are
+					 * busy. */
 					tcp_mark_push(tp, skb);
 					goto new_segment;
 				} else if (page) {
 					/* If page is cached, align
 					 * offset to L1 cache boundary
 					 */
-					off = (off+L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES-1);
+					off = (off + L1_CACHE_BYTES - 1) &
+					      ~(L1_CACHE_BYTES - 1);
 					if (off == PAGE_SIZE) {
 						put_page(page);
 						TCP_PAGE(sk) = page = NULL;
@@ -1114,21 +1123,23 @@
 
 				if (!page) {
 					/* Allocate new cache page. */
-					if (!(page=tcp_alloc_page(sk)))
+					if (!(page = tcp_alloc_page(sk)))
 						goto wait_for_memory;
 					off = 0;
 				}
 
-				if (copy > PAGE_SIZE-off)
-					copy = PAGE_SIZE-off;
+				if (copy > PAGE_SIZE - off)
+					copy = PAGE_SIZE - off;
 
-				/* Time to copy data. We are close to the end! */
-				err = tcp_copy_to_page(sk, from, skb, page, off, copy);
+				/* Time to copy data. We are close to
+				 * the end! */
+				err = tcp_copy_to_page(sk, from, skb, page,
+						       off, copy);
 				if (err) {
 					/* If this page was new, give it to the
 					 * socket so it does not get leaked.
 					 */
-					if (TCP_PAGE(sk) == NULL) {
+					if (!TCP_PAGE(sk)) {
 						TCP_PAGE(sk) = page;
 						TCP_OFF(sk) = 0;
 					}
@@ -1137,7 +1148,8 @@
 
 				/* Update the skb. */
 				if (merge) {
-					skb_shinfo(skb)->frags[i-1].size += copy;
+					skb_shinfo(skb)->frags[i - 1].size +=
+									copy;
 				} else {
 					fill_page_desc(skb, i, page, off, copy);
 					if (TCP_PAGE(sk)) {
@@ -1148,7 +1160,7 @@
 					}
 				}
 
-				TCP_OFF(sk) = off+copy;
+				TCP_OFF(sk) = off + copy;
 			}
 
 			if (!copied)
@@ -1161,7 +1173,7 @@
 			copied += copy;
 			seglen -= copy;
 
-			if (skb->len != mss_now || (flags&MSG_OOB))
+			if (skb->len != mss_now || (flags & MSG_OOB))
 				continue;
 
 			if (forced_push(tp)) {
@@ -1175,7 +1187,7 @@
 			set_bit(SOCK_NOSPACE, &sk->socket->flags);
 wait_for_memory:
 			if (copied)
-				tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);
+				tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, 1);
 
 			if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)
 				goto do_error;
@@ -1192,7 +1204,7 @@
 	return copied;
 
 do_fault:
-	if (skb->len == 0) {
+	if (!skb->len) {
 		if (tp->send_head == skb)
 			tp->send_head = NULL;
 		__skb_unlink(skb, skb->list);
@@ -1214,8 +1226,8 @@
  *	this, no blocking and very strange errors 8)
  */
 
-static int tcp_recv_urg(struct sock * sk, long timeo,
-			struct msghdr *msg, int len, int flags, 
+static int tcp_recv_urg(struct sock *sk, long timeo,
+			struct msghdr *msg, int len, int flags,
 			int *addr_len)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -1224,25 +1236,25 @@
 	if (sk->urginline || !tp->urg_data || tp->urg_data == TCP_URG_READ)
 		return -EINVAL;	/* Yes this is right ! */
 
-	if (sk->state==TCP_CLOSE && !sk->done)
+	if (sk->state == TCP_CLOSE && !sk->done)
 		return -ENOTCONN;
 
 	if (tp->urg_data & TCP_URG_VALID) {
-		int err = 0; 
+		int err = 0;
 		char c = tp->urg_data;
 
 		if (!(flags & MSG_PEEK))
 			tp->urg_data = TCP_URG_READ;
 
 		/* Read urgent data. */
-		msg->msg_flags|=MSG_OOB;
+		msg->msg_flags |= MSG_OOB;
 
-		if(len>0) {
+		if (len > 0) {
 			if (!(flags & MSG_TRUNC))
 				err = memcpy_toiovec(msg->msg_iov, &c, 1);
 			len = 1;
 		} else
-			msg->msg_flags|=MSG_TRUNC;
+			msg->msg_flags |= MSG_TRUNC;
 
 		return err ? -EFAULT : len;
 	}
@@ -1265,7 +1277,7 @@
  *	socket locked so that the sk_buff queue operation is ok.
  */
 
-static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
+static inline void tcp_eat_skb(struct sock *sk, struct sk_buff *skb)
 {
 	__skb_unlink(skb, &sk->receive_queue);
 	__kfree_skb(skb);
@@ -1285,35 +1297,33 @@
 #if TCP_DEBUG
 	struct sk_buff *skb = skb_peek(&sk->receive_queue);
 
-	BUG_TRAP(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq));
+	BUG_TRAP(!skb || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq));
 #endif
 
 	if (tcp_ack_scheduled(tp)) {
-		   /* Delayed ACKs frequently hit locked sockets during bulk receive. */
-		if (tp->ack.blocked
+		   /* Delayed ACKs frequently hit locked sockets during bulk
+		    * receive. */
+		if (tp->ack.blocked ||
 		    /* Once-per-two-segments ACK was not sent by tcp_input.c */
-		    || tp->rcv_nxt - tp->rcv_wup > tp->ack.rcv_mss
+		    tp->rcv_nxt - tp->rcv_wup > tp->ack.rcv_mss ||
 		    /*
 		     * If this read emptied read buffer, we send ACK, if
 		     * connection is not bidirectional, user drained
 		     * receive buffer and there was a small segment
 		     * in queue.
 		     */
-		    || (copied > 0 &&
-			(tp->ack.pending&TCP_ACK_PUSHED) &&
-			!tp->ack.pingpong &&
-			atomic_read(&sk->rmem_alloc) == 0)) {
+		    (copied > 0 && (tp->ack.pending & TCP_ACK_PUSHED) &&
+		     !tp->ack.pingpong && !atomic_read(&sk->rmem_alloc)))
 			time_to_ack = 1;
-		}
 	}
 
-  	/* We send an ACK if we can now advertise a non-zero window
+	/* We send an ACK if we can now advertise a non-zero window
 	 * which has been raised "significantly".
 	 *
 	 * Even if window raised up to infinity, do not send window open ACK
 	 * in states, where we will not receive more. It is useless.
-  	 */
-	if(copied > 0 && !time_to_ack && !(sk->shutdown&RCV_SHUTDOWN)) {
+	 */
+	if (copied > 0 && !time_to_ack && !(sk->shutdown & RCV_SHUTDOWN)) {
 		__u32 rcv_window_now = tcp_receive_window(tp);
 
 		/* Optimize, __tcp_select_window() is not cheap. */
@@ -1325,7 +1335,7 @@
 			 * We can advertise it now, if it is not less than current one.
 			 * "Lots" means "at least twice" here.
 			 */
-			if(new_window && new_window >= 2*rcv_window_now)
+			if (new_window && new_window >= 2 * rcv_window_now)
 				time_to_ack = 1;
 		}
 	}
@@ -1366,9 +1376,11 @@
 	struct sk_buff *skb;
 	struct tcp_opt *tp = tcp_sk(sk);
 
-	net_statistics[smp_processor_id()*2+1].TCPPrequeued += skb_queue_len(&tp->ucopy.prequeue);
+	net_statistics[smp_processor_id() * 2 + 1].TCPPrequeued +=
+					    skb_queue_len(&tp->ucopy.prequeue);
 
-	/* RX process wants to run with disabled BHs, though it is not necessary */
+	/* RX process wants to run with disabled BHs, though it is not
+	 * necessary */
 	local_bh_disable();
 	while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
 		sk->backlog_rcv(sk, skb);
@@ -1378,8 +1390,7 @@
 	tp->ucopy.memory = 0;
 }
 
-static inline
-struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
+static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
 {
 	struct sk_buff *skb;
 	u32 offset;
@@ -1457,13 +1468,13 @@
 }
 
 /*
- *	This routine copies from a sock struct into the user buffer. 
+ *	This routine copies from a sock struct into the user buffer.
  *
  *	Technical note: in 2.3 we work on _locked_ socket, so that
  *	tricks with *seq access order and skb->users are not required.
  *	Probably, code can be easily improved even more.
  */
- 
+
 int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
 		int len, int nonblock, int flags, int *addr_len)
 {
@@ -1500,7 +1511,7 @@
 	target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
 
 	do {
-		struct sk_buff * skb;
+		struct sk_buff *skb;
 		u32 offset;
 
 		/* Are we at urgent data? Stop if we have read anything. */
@@ -1525,12 +1536,12 @@
 			if (!skb)
 				break;
 
-			/* Now that we have two receive queues this 
+			/* Now that we have two receive queues this
 			 * shouldn't happen.
 			 */
 			if (before(*seq, TCP_SKB_CB(skb)->seq)) {
-				printk(KERN_INFO "recvmsg bug: copied %X seq %X\n",
-				       *seq, TCP_SKB_CB(skb)->seq);
+				printk(KERN_INFO "recvmsg bug: copied %X "
+				       "seq %X\n", *seq, TCP_SKB_CB(skb)->seq);
 				break;
 			}
 			offset = *seq - TCP_SKB_CB(skb)->seq;
@@ -1540,13 +1551,13 @@
 				goto found_ok_skb;
 			if (skb->h.th->fin)
 				goto found_fin_ok;
-			BUG_TRAP(flags&MSG_PEEK);
+			BUG_TRAP(flags & MSG_PEEK);
 			skb = skb->next;
 		} while (skb != (struct sk_buff *)&sk->receive_queue);
 
 		/* Well, if we have backlog, try to process it now yet. */
 
-		if (copied >= target && sk->backlog.tail == NULL)
+		if (copied >= target && !sk->backlog.tail)
 			break;
 
 		if (copied) {
@@ -1589,7 +1600,7 @@
 
 		if (tp->ucopy.task == user_recv) {
 			/* Install new reader */
-			if (user_recv == NULL && !(flags&(MSG_TRUNC|MSG_PEEK))) {
+			if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) {
 				user_recv = current;
 				tp->ucopy.task = user_recv;
 				tp->ucopy.iov = msg->msg_iov;
@@ -1597,7 +1608,8 @@
 
 			tp->ucopy.len = len;
 
-			BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&(MSG_PEEK|MSG_TRUNC)));
+			BUG_TRAP(tp->copied_seq == tp->rcv_nxt ||
+				 (flags & (MSG_PEEK | MSG_TRUNC)));
 
 			/* Ugly... If prequeue is not empty, we have to
 			 * process it before releasing socket, otherwise
@@ -1613,7 +1625,7 @@
 			 *
 			 * Each queue can be processed only if the next ones
 			 * are empty. At this point we have empty receive_queue.
-			 * But prequeue _can_ be not empty after second iteration,
+			 * But prequeue _can_ be not empty after 2nd iteration,
 			 * when we jumped to start of loop because backlog
 			 * processing added something to receive_queue.
 			 * We cannot release_sock(), because backlog contains
@@ -1645,7 +1657,7 @@
 			/* __ Restore normal policy in scheduler __ */
 
 			if ((chunk = len - tp->ucopy.len) != 0) {
-				net_statistics[smp_processor_id()*2+1].TCPDirectCopyFromBacklog += chunk;
+				net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromBacklog += chunk;
 				len -= chunk;
 				copied += chunk;
 			}
@@ -1656,7 +1668,7 @@
 				tcp_prequeue_process(sk);
 
 				if ((chunk = len - tp->ucopy.len) != 0) {
-					net_statistics[smp_processor_id()*2+1].TCPDirectCopyFromPrequeue += chunk;
+					net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromPrequeue += chunk;
 					len -= chunk;
 					copied += chunk;
 				}
@@ -1687,8 +1699,9 @@
 			}
 		}
 
-		if (!(flags&MSG_TRUNC)) {
-			err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used);
+		if (!(flags & MSG_TRUNC)) {
+			err = skb_copy_datagram_iovec(skb, offset,
+						      msg->msg_iov, used);
 			if (err) {
 				/* Exception. Bailout! */
 				if (!copied)
@@ -1702,7 +1715,7 @@
 		len -= used;
 
 skip_copy:
-		if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) {
+		if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) {
 			tp->urg_data = 0;
 			tcp_fast_path_check(sk, tp);
 		}
@@ -1732,7 +1745,7 @@
 			tcp_prequeue_process(sk);
 
 			if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) {
-				net_statistics[smp_processor_id()*2+1].TCPDirectCopyFromPrequeue += chunk;
+				net_statistics[smp_processor_id() * 2 + 1].TCPDirectCopyFromPrequeue += chunk;
 				len -= chunk;
 				copied += chunk;
 			}
@@ -1788,12 +1801,12 @@
 
 static int tcp_close_state(struct sock *sk)
 {
-	int next = (int) new_state[sk->state];
-	int ns = (next & TCP_STATE_MASK);
+	int next = (int)new_state[sk->state];
+	int ns = next & TCP_STATE_MASK;
 
 	tcp_set_state(sk, ns);
 
-	return (next & TCP_ACTION_FIN);
+	return next & TCP_ACTION_FIN;
 }
 
 /*
@@ -1812,7 +1825,8 @@
 
 	/* If we've already sent a FIN, or it's a closed state, skip this. */
 	if ((1 << sk->state) &
-	    (TCPF_ESTABLISHED|TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE_WAIT)) {
+	    (TCPF_ESTABLISHED | TCPF_SYN_SENT |
+	     TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) {
 		/* Clear out any half completed packets.  FIN if needed. */
 		if (tcp_close_state(sk))
 			tcp_send_fin(sk);
@@ -1824,9 +1838,10 @@
  *	Return 1 if we still have things to send in our buffers.
  */
 
-static inline int closing(struct sock * sk)
+static inline int closing(struct sock *sk)
 {
-	return ((1 << sk->state) & (TCPF_FIN_WAIT1|TCPF_CLOSING|TCPF_LAST_ACK));
+	return (1 << sk->state) &
+	       (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK);
 }
 
 static __inline__ void tcp_kill_sk_queues(struct sock *sk)
@@ -1843,8 +1858,8 @@
 	/* Account for returned memory. */
 	tcp_mem_reclaim(sk);
 
-	BUG_TRAP(sk->wmem_queued == 0);
-	BUG_TRAP(sk->forward_alloc == 0);
+	BUG_TRAP(!sk->wmem_queued);
+	BUG_TRAP(!sk->forward_alloc);
 
 	/* It is _impossible_ for the backlog to contain anything
 	 * when we get here.  All user references to this socket
@@ -1860,11 +1875,11 @@
  */
 void tcp_destroy_sock(struct sock *sk)
 {
-	BUG_TRAP(sk->state==TCP_CLOSE);
+	BUG_TRAP(sk->state == TCP_CLOSE);
 	BUG_TRAP(sk->dead);
 
 	/* It cannot be in hash table! */
-	BUG_TRAP(sk->pprev==NULL);
+	BUG_TRAP(!sk->pprev);
 
 	/* If it has not 0 inet_sk(sk)->num, it must be bound */
 	BUG_TRAP(!inet_sk(sk)->num || sk->prev);
@@ -1883,7 +1898,8 @@
 
 #ifdef INET_REFCNT_DEBUG
 	if (atomic_read(&sk->refcnt) != 1) {
-		printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n", sk, atomic_read(&sk->refcnt));
+		printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n",
+		       sk, atomic_read(&sk->refcnt));
 	}
 #endif
 
@@ -1899,7 +1915,7 @@
 	lock_sock(sk);
 	sk->shutdown = SHUTDOWN_MASK;
 
-	if(sk->state == TCP_LISTEN) {
+	if (sk->state == TCP_LISTEN) {
 		tcp_set_state(sk, TCP_CLOSE);
 
 		/* Special case. */
@@ -1912,8 +1928,9 @@
 	 *  descriptor close, not protocol-sourced closes, because the
 	 *  reader process may not have drained the data yet!
 	 */
-	while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) {
-		u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin;
+	while ((skb = __skb_dequeue(&sk->receive_queue)) != NULL) {
+		u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq -
+			  skb->h.th->fin;
 		data_was_unread += len;
 		__kfree_skb(skb);
 	}
@@ -1929,12 +1946,12 @@
 	 * the FTP client, wheee...  Note: timeout is always zero
 	 * in such a case.
 	 */
-	if(data_was_unread != 0) {
+	if (data_was_unread) {
 		/* Unread data was tossed, zap the connection. */
 		NET_INC_STATS_USER(TCPAbortOnClose);
 		tcp_set_state(sk, TCP_CLOSE);
 		tcp_send_active_reset(sk, GFP_KERNEL);
-	} else if (sk->linger && sk->lingertime==0) {
+	} else if (sk->linger && !sk->lingertime) {
 		/* Check zero linger _after_ checking for unread data. */
 		sk->prot->disconnect(sk, 0);
 		NET_INC_STATS_USER(TCPAbortOnData);
@@ -1996,7 +2013,7 @@
 	 */
 	local_bh_disable();
 	bh_lock_sock(sk);
-	BUG_TRAP(sk->lock.users==0);
+	BUG_TRAP(!sk->lock.users);
 
 	sock_hold(sk);
 	sock_orphan(sk);
@@ -2039,7 +2056,8 @@
 		    (sk->wmem_queued > SOCK_MIN_SNDBUF &&
 		     atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) {
 			if (net_ratelimit())
-				printk(KERN_INFO "TCP: too many of orphaned sockets\n");
+				printk(KERN_INFO "TCP: too many of orphaned "
+				       "sockets\n");
 			tcp_set_state(sk, TCP_CLOSE);
 			tcp_send_active_reset(sk, GFP_ATOMIC);
 			NET_INC_STATS_BH(TCPAbortOnMemory);
@@ -2061,9 +2079,9 @@
 
 extern __inline__ int tcp_need_reset(int state)
 {
-	return ((1 << state) &
-	       	(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1|
-		 TCPF_FIN_WAIT2|TCPF_SYN_RECV));
+	return (1 << state) &
+	       (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 |
+		TCPF_FIN_WAIT2 | TCPF_SYN_RECV);
 }
 
 int tcp_disconnect(struct sock *sk, int flags)
@@ -2082,7 +2100,7 @@
 		tcp_listen_stop(sk);
 	} else if (tcp_need_reset(old_state) ||
 		   (tp->snd_nxt != tp->write_seq &&
-		    (1<<old_state)&(TCPF_CLOSING|TCPF_LAST_ACK))) {
+		    (1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
 		/* The last check adjusts for discrepance of Linux wrt. RFC
 		 * states
 		 */
@@ -2093,12 +2111,12 @@
 
 	tcp_clear_xmit_timers(sk);
 	__skb_queue_purge(&sk->receive_queue);
-  	tcp_writequeue_purge(sk);
-  	__skb_queue_purge(&tp->out_of_order_queue);
+	tcp_writequeue_purge(sk);
+	__skb_queue_purge(&tp->out_of_order_queue);
 
 	inet->dport = 0;
 
-	if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) {
+	if (!(sk->userlocks & SOCK_BINDADDR_LOCK)) {
 		inet->rcv_saddr = inet->saddr = 0;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		if (sk->family == PF_INET6) {
@@ -2113,7 +2131,7 @@
 	sk->shutdown = 0;
 	sk->done = 0;
 	tp->srtt = 0;
-	if ((tp->write_seq += tp->max_window+2) == 0)
+	if ((tp->write_seq += tp->max_window + 2) == 0)
 		tp->write_seq = 1;
 	tp->backoff = 0;
 	tp->snd_cwnd = 2;
@@ -2139,7 +2157,7 @@
  *	Wait for an incoming connection, avoid race
  *	conditions. This must be called with the socket locked.
  */
-static int wait_for_connect(struct sock * sk, long timeo)
+static int wait_for_connect(struct sock *sk, long timeo)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
 	DECLARE_WAITQUEUE(wait, current);
@@ -2163,7 +2181,7 @@
 	for (;;) {
 		current->state = TASK_INTERRUPTIBLE;
 		release_sock(sk);
-		if (tp->accept_queue == NULL)
+		if (!tp->accept_queue)
 			timeo = schedule_timeout(timeo);
 		lock_sock(sk);
 		err = 0;
@@ -2195,7 +2213,7 @@
 	struct sock *newsk;
 	int error;
 
-	lock_sock(sk); 
+	lock_sock(sk);
 
 	/* We need to make sure that this socket is listening,
 	 * and that it has something pending.
@@ -2231,15 +2249,14 @@
 
 out:
 	release_sock(sk);
-	*err = error; 
+	*err = error;
 	return NULL;
 }
 
 /*
- *	Socket option code for TCP. 
+ *	Socket option code for TCP.
  */
-  
-int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, 
+int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval,
 		   int optlen)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2247,10 +2264,10 @@
 	int err = 0;
 
 	if (level != SOL_TCP)
-		return tp->af_specific->setsockopt(sk, level, optname, 
+		return tp->af_specific->setsockopt(sk, level, optname,
 						   optval, optlen);
 
-	if(optlen<sizeof(int))
+	if (optlen < sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int *)optval))
@@ -2258,13 +2275,12 @@
 
 	lock_sock(sk);
 
-	switch(optname) {
+	switch (optname) {
 	case TCP_MAXSEG:
-		/* values greater than interface MTU won't take effect.  however at
-		 * the point when this call is done we typically don't yet know
-		 * which interface is going to be used
-		 */
-		if(val < 8 || val > MAX_TCP_WINDOW) {
+		/* Values greater than interface MTU won't take effect. However
+		 * at the point when this call is done we typically don't yet
+		 * know which interface is going to be used */
+		if (val < 8 || val > MAX_TCP_WINDOW) {
 			err = -EINVAL;
 			break;
 		}
@@ -2279,7 +2295,7 @@
 			err = -EINVAL;
 			break;
 		}
-		tp->nonagle = (val == 0) ? 0 : 1;
+		tp->nonagle = !val ? 0 : 1;
 		if (val)
 			tcp_push_pending_frames(sk, tp);
 		break;
@@ -2308,13 +2324,14 @@
 			tcp_push_pending_frames(sk, tp);
 		}
 		break;
-		
+
 	case TCP_KEEPIDLE:
 		if (val < 1 || val > MAX_TCP_KEEPIDLE)
 			err = -EINVAL;
 		else {
 			tp->keepalive_time = val * HZ;
-			if (sk->keepopen && !((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN))) {
+			if (sk->keepopen &&
+			    !((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN))) {
 				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
 				if (tp->keepalive_time > elapsed)
 					elapsed = tp->keepalive_time - elapsed;
@@ -2346,33 +2363,35 @@
 	case TCP_LINGER2:
 		if (val < 0)
 			tp->linger2 = -1;
-		else if (val > sysctl_tcp_fin_timeout/HZ)
+		else if (val > sysctl_tcp_fin_timeout / HZ)
 			tp->linger2 = 0;
 		else
-			tp->linger2 = val*HZ;
+			tp->linger2 = val * HZ;
 		break;
 
 	case TCP_DEFER_ACCEPT:
 		tp->defer_accept = 0;
 		if (val > 0) {
-			/* Translate value in seconds to number of retransmits */
-			while (tp->defer_accept < 32 && val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept))
+			/* Translate value in seconds to number of
+			 * retransmits */
+			while (tp->defer_accept < 32 &&
+			       val > ((TCP_TIMEOUT_INIT / HZ) <<
+				       tp->defer_accept))
 				tp->defer_accept++;
 			tp->defer_accept++;
 		}
 		break;
 
 	case TCP_WINDOW_CLAMP:
-		if (val==0) {
+		if (!val) {
 			if (sk->state != TCP_CLOSE) {
 				err = -EINVAL;
 				break;
 			}
 			tp->window_clamp = 0;
-		} else {
-			tp->window_clamp = val<SOCK_MIN_RCVBUF/2 ?
-				SOCK_MIN_RCVBUF/2 : val;
-		}
+		} else
+			tp->window_clamp = val < SOCK_MIN_RCVBUF / 2 ?
+						SOCK_MIN_RCVBUF / 2 : val;
 		break;
 
 	case TCP_QUICKACK:
@@ -2380,7 +2399,8 @@
 			tp->ack.pingpong = 1;
 		} else {
 			tp->ack.pingpong = 0;
-			if ((1<<sk->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT) &&
+			if ((1 << sk->state) &
+			    (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) &&
 			    tcp_ack_scheduled(tp)) {
 				tp->ack.pending |= TCP_ACK_PUSHED;
 				cleanup_rbuf(sk, 1);
@@ -2404,22 +2424,22 @@
 	struct tcp_opt *tp = tcp_sk(sk);
 	int val, len;
 
-	if(level != SOL_TCP)
+	if (level != SOL_TCP)
 		return tp->af_specific->getsockopt(sk, level, optname,
 						   optval, optlen);
 
-	if(get_user(len,optlen))
+	if (get_user(len, optlen))
 		return -EFAULT;
 
 	len = min_t(unsigned int, len, sizeof(int));
-	
-	if(len < 0)
+
+	if (len < 0)
 		return -EINVAL;
 
-	switch(optname) {
+	switch (optname) {
 	case TCP_MAXSEG:
 		val = tp->mss_cache;
-		if (val == 0 && ((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN)))
+		if (!val && ((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN)))
 			val = tp->user_mss;
 		break;
 	case TCP_NODELAY:
@@ -2429,10 +2449,10 @@
 		val = (tp->nonagle == 2);
 		break;
 	case TCP_KEEPIDLE:
-		val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time)/HZ;
+		val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time) / HZ;
 		break;
 	case TCP_KEEPINTVL:
-		val = (tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl)/HZ;
+		val = (tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl) / HZ;
 		break;
 	case TCP_KEEPCNT:
 		val = tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
@@ -2443,20 +2463,20 @@
 	case TCP_LINGER2:
 		val = tp->linger2;
 		if (val >= 0)
-			val = (val ? : sysctl_tcp_fin_timeout)/HZ;
+			val = (val ? : sysctl_tcp_fin_timeout) / HZ;
 		break;
 	case TCP_DEFER_ACCEPT:
-		val = tp->defer_accept == 0 ? 0 : ((TCP_TIMEOUT_INIT/HZ)<<(tp->defer_accept-1));
+		val = !tp->defer_accept ? 0 : ((TCP_TIMEOUT_INIT / HZ) <<
+					       (tp->defer_accept - 1));
 		break;
 	case TCP_WINDOW_CLAMP:
 		val = tp->window_clamp;
 		break;
-	case TCP_INFO:
-	{
+	case TCP_INFO: {
 		struct tcp_info info;
 		u32 now = tcp_time_stamp;
 
-		if(get_user(len,optlen))
+		if (get_user(len, optlen))
 			return -EFAULT;
 		info.tcpi_state = sk->state;
 		info.tcpi_ca_state = tp->ca_state;
@@ -2476,11 +2496,11 @@
 			info.tcpi_snd_wscale = 0;
 			info.tcpi_rcv_wscale = 0;
 		}
-		if (tp->ecn_flags&TCP_ECN_OK)
+		if (tp->ecn_flags & TCP_ECN_OK)
 			info.tcpi_options |= TCPI_OPT_ECN;
 
-		info.tcpi_rto = (1000000*tp->rto)/HZ;
-		info.tcpi_ato = (1000000*tp->ack.ato)/HZ;
+		info.tcpi_rto = (1000000 * tp->rto) / HZ;
+		info.tcpi_ato = (1000000 * tp->ack.ato) / HZ;
 		info.tcpi_snd_mss = tp->mss_cache;
 		info.tcpi_rcv_mss = tp->ack.rcv_mss;
 
@@ -2490,24 +2510,25 @@
 		info.tcpi_retrans = tp->retrans_out;
 		info.tcpi_fackets = tp->fackets_out;
 
-		info.tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ;
+		info.tcpi_last_data_sent = ((now - tp->lsndtime) * 1000) / HZ;
 		info.tcpi_last_ack_sent = 0;
-		info.tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ;
-		info.tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ;
+		info.tcpi_last_data_recv = ((now -
+					     tp->ack.lrcvtime) * 1000) / HZ;
+		info.tcpi_last_ack_recv = ((now - tp->rcv_tstamp) * 1000) / HZ;
 
 		info.tcpi_pmtu = tp->pmtu_cookie;
 		info.tcpi_rcv_ssthresh = tp->rcv_ssthresh;
-		info.tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3;
-		info.tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2;
+		info.tcpi_rtt = ((1000000 * tp->srtt) / HZ) >> 3;
+		info.tcpi_rttvar = ((1000000 * tp->mdev) / HZ) >> 2;
 		info.tcpi_snd_ssthresh = tp->snd_ssthresh;
 		info.tcpi_snd_cwnd = tp->snd_cwnd;
 		info.tcpi_advmss = tp->advmss;
 		info.tcpi_reordering = tp->reordering;
 
 		len = min_t(unsigned int, len, sizeof(info));
-		if(put_user(len, optlen))
+		if (put_user(len, optlen))
 			return -EFAULT;
-		if(copy_to_user(optval, &info,len))
+		if (copy_to_user(optval, &info, len))
 			return -EFAULT;
 		return 0;
 	}
@@ -2518,11 +2539,11 @@
 		return -ENOPROTOOPT;
 	};
 
-  	if(put_user(len, optlen))
-  		return -EFAULT;
-	if(copy_to_user(optval, &val,len))
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
 		return -EFAULT;
-  	return 0;
+	return 0;
 }
 
 
@@ -2535,7 +2556,7 @@
 	unsigned long goal;
 	int order, i;
 
-	if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
+	if (sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
 		__skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
 					   sizeof(skb->cb));
 
@@ -2543,21 +2564,21 @@
 						   sizeof(struct open_request),
 					       0, SLAB_HWCACHE_ALIGN,
 					       NULL, NULL);
-	if(!tcp_openreq_cachep)
+	if (!tcp_openreq_cachep)
 		panic("tcp_init: Cannot alloc open_request cache.");
 
 	tcp_bucket_cachep = kmem_cache_create("tcp_bind_bucket",
 					      sizeof(struct tcp_bind_bucket),
 					      0, SLAB_HWCACHE_ALIGN,
 					      NULL, NULL);
-	if(!tcp_bucket_cachep)
+	if (!tcp_bucket_cachep)
 		panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
 
 	tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",
 						sizeof(struct tcp_tw_bucket),
 						0, SLAB_HWCACHE_ALIGN,
 						NULL, NULL);
-	if(!tcp_timewait_cachep)
+	if (!tcp_timewait_cachep)
 		panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
 
 	/* Size and allocate the main established and bind bucket
@@ -2570,21 +2591,21 @@
 	else
 		goal = num_physpages >> (23 - PAGE_SHIFT);
 
-	for(order = 0; (1UL << order) < goal; order++)
+	for (order = 0; (1UL << order) < goal; order++)
 		;
 	do {
 		tcp_ehash_size = (1UL << order) * PAGE_SIZE /
 			sizeof(struct tcp_ehash_bucket);
 		tcp_ehash_size >>= 1;
-		while (tcp_ehash_size & (tcp_ehash_size-1))
+		while (tcp_ehash_size & (tcp_ehash_size - 1))
 			tcp_ehash_size--;
 		tcp_ehash = (struct tcp_ehash_bucket *)
 			__get_free_pages(GFP_ATOMIC, order);
-	} while (tcp_ehash == NULL && --order > 0);
+	} while (!tcp_ehash && --order > 0);
 
 	if (!tcp_ehash)
 		panic("Failed to allocate TCP established hash table\n");
-	for (i = 0; i < (tcp_ehash_size<<1); i++) {
+	for (i = 0; i < (tcp_ehash_size << 1); i++) {
 		tcp_ehash[i].lock = RW_LOCK_UNLOCKED;
 		tcp_ehash[i].chain = NULL;
 	}
@@ -2596,7 +2617,7 @@
 			continue;
 		tcp_bhash = (struct tcp_bind_hashbucket *)
 			__get_free_pages(GFP_ATOMIC, order);
-	} while (tcp_bhash == NULL && --order >= 0);
+	} while (!tcp_bhash && --order >= 0);
 
 	if (!tcp_bhash)
 		panic("Failed to allocate TCP bind hash table\n");
@@ -2612,33 +2633,34 @@
 		sysctl_local_port_range[0] = 32768;
 		sysctl_local_port_range[1] = 61000;
 		sysctl_tcp_max_tw_buckets = 180000;
-		sysctl_tcp_max_orphans = 4096<<(order-4);
+		sysctl_tcp_max_orphans = 4096 << (order - 4);
 		sysctl_max_syn_backlog = 1024;
 	} else if (order < 3) {
-		sysctl_local_port_range[0] = 1024*(3-order);
-		sysctl_tcp_max_tw_buckets >>= (3-order);
-		sysctl_tcp_max_orphans >>= (3-order);
+		sysctl_local_port_range[0] = 1024 * (3 - order);
+		sysctl_tcp_max_tw_buckets >>= (3 - order);
+		sysctl_tcp_max_orphans >>= (3 - order);
 		sysctl_max_syn_backlog = 128;
 	}
 	tcp_port_rover = sysctl_local_port_range[0] - 1;
 
-	sysctl_tcp_mem[0] = 768<<order;
-	sysctl_tcp_mem[1] = 1024<<order;
-	sysctl_tcp_mem[2] = 1536<<order;
+	sysctl_tcp_mem[0] =  768 << order;
+	sysctl_tcp_mem[1] = 1024 << order;
+	sysctl_tcp_mem[2] = 1536 << order;
 	if (sysctl_tcp_mem[2] - sysctl_tcp_mem[1] > 512)
 		sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 512;
 	if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 512)
 		sysctl_tcp_mem[0] = sysctl_tcp_mem[1] - 512;
 
 	if (order < 3) {
-		sysctl_tcp_wmem[2] = 64*1024;
+		sysctl_tcp_wmem[2] = 64 * 1024;
 		sysctl_tcp_rmem[0] = PAGE_SIZE;
 		sysctl_tcp_rmem[1] = 43689;
-		sysctl_tcp_rmem[2] = 2*43689;
+		sysctl_tcp_rmem[2] = 2 * 43689;
 	}
 
-	printk(KERN_INFO "TCP: Hash tables configured (established %d bind %d)\n",
-	       tcp_ehash_size<<1, tcp_bhash_size);
+	printk(KERN_INFO "TCP: Hash tables configured "
+	       "(established %d bind %d)\n",
+	       tcp_ehash_size << 1, tcp_bhash_size);
 
 	tcpdiag_init();
 }
diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile
--- a/net/ipv6/Makefile	Thu May  9 15:21:09 2002
+++ b/net/ipv6/Makefile	Thu May  9 15:21:09 2002
@@ -9,11 +9,13 @@
 
 O_TARGET := ipv6.o
 
+export-objs :=  ipv6_syms.o
+
 obj-y :=	af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
 		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
 		protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
-		ip6_flowlabel.o
+		ip6_flowlabel.o ipv6_syms.o
 
 obj-m  := $(O_TARGET)
 
diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv6/ipv6_syms.c	Thu May  9 15:21:10 2002
@@ -0,0 +1,12 @@
+
+#include <linux/module.h>
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+EXPORT_SYMBOL(ipv6_addr_type);
+EXPORT_SYMBOL(icmpv6_send);
+EXPORT_SYMBOL(ndisc_mc_map);
+EXPORT_SYMBOL(register_inet6addr_notifier);
+EXPORT_SYMBOL(unregister_inet6addr_notifier);
+EXPORT_SYMBOL(ip6_route_output);
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Thu May  9 15:21:06 2002
+++ b/net/netsyms.c	Thu May  9 15:21:06 2002
@@ -286,15 +286,6 @@
 #endif
 
 
-#ifdef CONFIG_IPV6
-EXPORT_SYMBOL(ipv6_addr_type);
-EXPORT_SYMBOL(icmpv6_send);
-EXPORT_SYMBOL(ndisc_mc_map);
-EXPORT_SYMBOL(register_inet6addr_notifier);
-EXPORT_SYMBOL(unregister_inet6addr_notifier);
-#include <net/ip6_route.h>
-EXPORT_SYMBOL(ip6_route_output);
-#endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
 EXPORT_SYMBOL(inet_release);
@@ -399,11 +390,6 @@
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_tcp_tw_recycle); 
 EXPORT_SYMBOL(sysctl_max_syn_backlog);
-#endif
-
-#if defined (CONFIG_IPV6_MODULE)
-EXPORT_SYMBOL(secure_tcpv6_sequence_number);
-EXPORT_SYMBOL(secure_ipv6_id);
 #endif
 
 #endif
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Thu May  9 15:21:02 2002
+++ b/net/sunrpc/svcsock.c	Thu May  9 15:21:02 2002
@@ -710,7 +710,7 @@
 	 * We randomly choose between newest and oldest (in terms
 	 * of recent activity) and drop it.
 	 */
-	if (serv->sv_tmpcnt > serv->sv_nrthreads*5) {
+	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*5) {
 		struct svc_sock *svsk = NULL;
 		spin_lock_bh(&serv->sv_lock);
 		if (!list_empty(&serv->sv_tempsocks)) {
@@ -924,7 +924,7 @@
 		 * as soon a a complete request arrives.
 		 */
 		svc_sock_setbufsize(svsk->sk_sock,
-				    svsk->sk_server->sv_nrthreads *
+				    (svsk->sk_server->sv_nrthreads+3) *
 				    svsk->sk_server->sv_bufsz,
 				    3 * svsk->sk_server->sv_bufsz);
 	}
@@ -966,7 +966,7 @@
 		if (sock->type == SOCK_STREAM) {
 			/* See svc_tcp_init above for rationale on buffer sizes */
 			svc_sock_setbufsize(sock,
-					    serv->sv_nrthreads *
+					    (serv->sv_nrthreads+3) *
 					    serv->sv_bufsz,
 					    3 * serv->sv_bufsz);
 		} else 
diff -Nru a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
--- a/sound/oss/dmasound/dmasound_atari.c	Thu May  9 15:21:04 2002
+++ b/sound/oss/dmasound/dmasound_atari.c	Thu May  9 15:21:04 2002
@@ -1,10 +1,16 @@
-
 /*
  *  linux/drivers/sound/dmasound/dmasound_atari.c
  *
  *  Atari TT and Falcon DMA Sound Driver
  *
  *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
+ *  prior to 28/01/2001
+ *
+ *  28/01/2001 [0.1] Iain Sandoe
+ *		     - added versioning
+ *		     - put in and populated the hardware_afmts field.
+ *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
+ *  01/02/2001 [0.3] - put in default hard/soft settings.
  */
 
 
@@ -21,10 +27,11 @@
 
 #include "dmasound.h"
 
+#define DMASOUND_ATARI_REVISION 0
+#define DMASOUND_ATARI_EDITION 3
 
 extern void atari_microwire_cmd(int cmd);
 
-
 static int is_falcon;
 static int write_sq_ignore_int = 0;	/* ++TeSche: used for Falcon */
 
@@ -136,10 +143,10 @@
 static int AtaMixerIoctl(u_int cmd, u_long arg);
 static int TTMixerIoctl(u_int cmd, u_long arg);
 static int FalconMixerIoctl(u_int cmd, u_long arg);
-static void AtaWriteSqSetup(void);
-static void AtaSqOpen(void);
-static int TTStateInfo(char *buffer);
-static int FalconStateInfo(char *buffer);
+static int AtaWriteSqSetup(void);
+static int AtaSqOpen(mode_t mode);
+static int TTStateInfo(char *buffer, size_t space);
+static int FalconStateInfo(char *buffer, size_t space);
 
 
 /*** Translations ************************************************************/
@@ -1438,43 +1445,73 @@
 	return AtaMixerIoctl(cmd, arg);
 }
 
-static void AtaWriteSqSetup(void)
+static int AtaWriteSqSetup(void)
 {
 	write_sq_ignore_int = 0;
+	return 0 ;
 }
 
-static void AtaSqOpen(void)
+static int AtaSqOpen(mode_t mode)
 {
 	write_sq_ignore_int = 1;
+	return 0 ;
 }
 
-static int TTStateInfo(char *buffer)
+static int TTStateInfo(char *buffer, size_t space)
 {
 	int len = 0;
-	len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+	len += sprintf(buffer+len, "\tvol left  %ddB [-40...  0]\n",
 		       dmasound.volume_left);
-	len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+	len += sprintf(buffer+len, "\tvol right %ddB [-40...  0]\n",
 		       dmasound.volume_right);
-	len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+	len += sprintf(buffer+len, "\tbass      %ddB [-12...+12]\n",
 		       dmasound.bass);
-	len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+	len += sprintf(buffer+len, "\ttreble    %ddB [-12...+12]\n",
 		       dmasound.treble);
+	if (len >= space) {
+		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;
+		len = space ;
+	}
 	return len;
 }
 
-static int FalconStateInfo(char *buffer)
+static int FalconStateInfo(char *buffer, size_t space)
 {
 	int len = 0;
-	len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+	len += sprintf(buffer+len, "\tvol left  %ddB [-22.5 ... 0]\n",
 		       dmasound.volume_left);
-	len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+	len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n",
 		       dmasound.volume_right);
+	if (len >= space) {
+		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;
+		len = space ;
+	}
 	return len;
 }
 
 
 /*** Machine definitions *****************************************************/
 
+static SETTINGS def_hard_falcon = {
+	format: AFMT_S8,
+	stereo: 0,
+	size: 8,
+	speed: 8195
+} ;
+
+static SETTINGS def_hard_tt = {
+	format: AFMT_S8,
+	stereo: 0,
+	size: 8,
+	speed: 12517
+} ;
+
+static SETTINGS def_soft = {
+	format: AFMT_U8,
+	stereo: 0,
+	size: 8,
+	speed: 8000
+} ;
 
 static MACHINE machTT = {
 	name:		"Atari",
@@ -1501,6 +1538,9 @@
 	sq_open:	AtaSqOpen,
 	state_info:	TTStateInfo,
 	min_dsp_speed:	6258,
+	version:	((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),
+	hardware_afmts:	AFMT_S8,  /* h'ware-supported formats *only* here */
+	capabilities:	 DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */
 };
 
 static MACHINE machFalcon = {
@@ -1525,6 +1565,9 @@
 	sq_open:	AtaSqOpen,
 	state_info:	FalconStateInfo,
 	min_dsp_speed:	8195,
+	version:	((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),
+	hardware_afmts:	(AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */
+	capabilities:	 DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */
 };
 
 
@@ -1536,9 +1579,13 @@
 	if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {
 	    if (ATARIHW_PRESENT(CODEC)) {
 		dmasound.mach = machFalcon;
+		dmasound.mach.default_soft = def_soft ;
+		dmasound.mach.default_hard = def_hard_falcon ;
 		is_falcon = 1;
 	    } else if (ATARIHW_PRESENT(MICROWIRE)) {
 		dmasound.mach = machTT;
+		dmasound.mach.default_soft = def_soft ;
+		dmasound.mach.default_hard = def_hard_tt ;
 		is_falcon = 0;
 	    } else
 		return -ENODEV;
diff -Nru a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
--- a/sound/oss/dmasound/dmasound_awacs.c	Thu May  9 15:21:05 2002
+++ b/sound/oss/dmasound/dmasound_awacs.c	Thu May  9 15:21:05 2002
@@ -1,13 +1,60 @@
-
 /*
  *  linux/drivers/sound/dmasound/dmasound_awacs.c
  *
  *  PowerMac `AWACS' and `Burgundy' DMA Sound Driver
+ *  with some limited support for DACA & Tumbler
  *
- *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
- */
-
+ *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and
+ *  history prior to 2001/01/26.
+ *
+ *	26/01/2001 ed 0.1 Iain Sandoe
+ *		- added version info.
+ *		- moved dbdma command buffer allocation to PMacXXXSqSetup()
+ *		- fixed up beep dbdma cmd buffers
+ *
+ *	08/02/2001 [0.2]
+ *		- make SNDCTL_DSP_GETFMTS return the correct info for the h/w
+ *		- move soft format translations to a separate file
+ *		- [0.3] make SNDCTL_DSP_GETCAPS return correct info.
+ *		- [0.4] more informative machine name strings.
+ *		- [0.5]
+ *		- record changes.
+ *		- made the default_hard/soft entries.
+ *	04/04/2001 [0.6]
+ *		- minor correction to bit assignments in awacs_defs.h
+ *		- incorporate mixer changes from 2.2.x back-port.
+ *		- take out passthru as a rec input (it isn't).
+ *              - make Input Gain slider work the 'right way up'.
+ *              - try to make the mixer sliders more logical - so now the
+ *                input selectors are just two-state (>50% == ON) and the
+ *                Input Gain slider handles the rest of the gain issues.
+ *              - try to pick slider representations that most closely match
+ *                the actual use - e.g. IGain for input gain... 
+ *              - first stab at over/under-run detection.
+ *		- minor cosmetic changes to IRQ identification.
+ *		- fix bug where rates > max would be reported as supported.
+ *              - first stab at over/under-run detection.
+ *              - make use of i2c for mixer settings conditional on perch
+ *                rather than cuda (some machines without perch have cuda).
+ *              - fix bug where TX stops when dbdma status comes up "DEAD"
+ *		  so far only reported on PowerComputing clones ... but.
+ *		- put in AWACS/Screamer register write timeouts.
+ *		- part way to partitioning the init() stuff
+ *		- first pass at 'tumbler' stuff (not support - just an attempt
+ *		  to allow the driver to load on new G4s).
+ *      01/02/2002 [0.7] - BenH
+ *	        - all sort of minor bits went in since the latest update, I
+ *	          bumped the version number for that reason
+*/
+
+/* GENERAL FIXME/TODO: check that the assumptions about what is written to
+   mac-io is valid for DACA & Tumbler.
+
+   This driver is in bad need of a rewrite. The dbdma code has to be split,
+   some proper device-tree parsing code has to be written, etc...
+*/
 
+#include <linux/types.h>
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/slab.h>
@@ -18,6 +65,9 @@
 #include <linux/nvram.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
+#include <linux/irq.h>
+#include <linux/kmod.h>
+#include <asm/semaphore.h>
 #ifdef CONFIG_ADB_CUDA
 #include <linux/cuda.h>
 #endif
@@ -25,20 +75,30 @@
 #include <linux/pmu.h>
 #endif
 
+#include <linux/i2c-dev.h>
+
 #include <asm/uaccess.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
-#include <asm/feature.h>
+#include <asm/pmac_feature.h>
 #include <asm/irq.h>
+#include <asm/nvram.h>
 
 #include "awacs_defs.h"
 #include "dmasound.h"
 
+#define DMASOUND_AWACS_REVISION	0
+#define DMASOUND_AWACS_EDITION	7
 
+#define AWACS_BURGUNDY	100	/* fake revision # for burgundy */
+#define AWACS_TUMBLER    90	/* fake revision # for tumbler */
+#define AWACS_DACA	 80	/* fake revision # for daca (ibook) */
+#define AWACS_AWACS       2     /* holding revision for AWACS */
+#define AWACS_SCREAMER    3     /* holding revision for Screamer */
 /*
- * Interrupt numbers and addresses, obtained from the device tree.
+ * Interrupt numbers and addresses, & info obtained from the device tree.
  */
 static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
 static volatile struct awacs_regs *awacs;
@@ -50,28 +110,58 @@
 
 static char awacs_name[64];
 static int awacs_revision;
-int awacs_is_screamer = 0;
-int awacs_device_id = 0;
-int awacs_has_iic = 0;
-#define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
+static int awacs_sleeping;
+static DECLARE_MUTEX(dmasound_sem);
+
+static int sound_device_id;		/* exists after iMac revA */
+static int hw_can_byteswap = 1 ;	/* most pmac sound h/w can */
+
+/* model info */
+/* To be replaced with better interaction with pmac_feature.c */
+static int is_pbook_3X00;
+static int is_pbook_g3;
+
+/* expansion info */
+static int has_perch;
+static int has_ziva;
+
+/* for earlier powerbooks which need fiddling with mac-io to enable
+ * cd etc.
+*/
+static unsigned char *latch_base;
+static unsigned char *macio_base;
 
 /*
  * Space for the DBDMA command blocks.
  */
 static void *awacs_tx_cmd_space;
 static volatile struct dbdma_cmd *awacs_tx_cmds;
+static int number_of_tx_cmd_buffers = 0;
 
 static void *awacs_rx_cmd_space;
 static volatile struct dbdma_cmd *awacs_rx_cmds;
+static int number_of_rx_cmd_buffers = 0;
 
 /*
  * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy. XXX
+ * Except on the burgundy (and screamer). XXX
  */
+
 int awacs_reg[8];
+int awacs_reg1_save;
+
+/* tracking values for the mixer contents
+*/
 
-#define HAS_16BIT_TABLES
-#undef HAS_8BIT_TABLES
+static int spk_vol = 0 ;
+static int line_vol = 0 ;
+static int passthru_vol = 0 ;
+
+static int ip_gain = 0 ; /* mic preamp settings */
+static int rec_lev = 0x4545 ; /* default CD gain 69 % */
+static int mic_lev = 0 ;
+static int cd_lev = 0x6363 ; /* 99 % */
+static int line_lev = 0 ;
 
 /*
  * Stuff for outputting a beep.  The values range from -327 to +327
@@ -113,20 +203,18 @@
 	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
 };
 
+/* beep support */
 #define BEEP_SRATE	22050	/* 22050 Hz sample rate */
 #define BEEP_BUFLEN	512
 #define BEEP_VOLUME	15	/* 0 - 100 */
 
-static int beep_volume = BEEP_VOLUME;
+static int beep_vol = BEEP_VOLUME;
 static int beep_playing = 0;
 static int awacs_beep_state = 0;
 static short *beep_buf;
+static void *beep_dbdma_cmd_space;
 static volatile struct dbdma_cmd *beep_dbdma_cmd;
 static void (*orig_mksound)(unsigned int, unsigned int);
-static int is_pbook_3400;
-static unsigned char *latch_base;
-static int is_pbook_G3;
-static unsigned char *macio_base;
 
 /* Burgundy functions */
 static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
@@ -136,6 +224,18 @@
 static void awacs_burgundy_write_mvolume(unsigned address, int volume);
 static int awacs_burgundy_read_mvolume(unsigned address);
 
+/* we will allocate a single 'emergency' dbdma cmd block to use if the
+   tx status comes up "DEAD".  This happens on some PowerComputing Pmac
+   clones, either owing to a bug in dbdma or some interaction between
+   IDE and sound.  However, this measure would deal with DEAD status if
+   if appeared elsewhere.
+
+   for the sake of memory efficiency we'll allocate this cmd as part of
+   the beep cmd stuff.
+*/
+
+static volatile struct dbdma_cmd *emergency_dbdma_cmd;
+
 #ifdef CONFIG_PMAC_PBOOK
 /*
  * Stuff for restoring after a sleep.
@@ -146,78 +246,11 @@
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
-static int expand_bal;	/* Balance factor for expanding (not volume!) */
-static int expand_data;	/* Data for expanding */
-
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-
+/* for (soft) sample rate translations */
+int expand_bal;		/* Balance factor for expanding (not volume!) */
 
 /*** Low level stuff *********************************************************/
 
-
 static void PMacOpen(void);
 static void PMacRelease(void);
 static void *PMacAlloc(unsigned int size, int flags);
@@ -244,565 +277,214 @@
 
 /*** Mid level stuff **********************************************************/
 
-
 static int PMacMixerIoctl(u_int cmd, u_long arg);
-static void PMacWriteSqSetup(void);
-static void PMacReadSqSetup(void);
+static int PMacWriteSqSetup(void);
+static int PMacReadSqSetup(void);
 static void PMacAbortRead(void);
 
+extern TRANS transAwacsNormal ;
+extern TRANS transAwacsExpand ;
+extern TRANS transAwacsNormalRead ;
+
+extern int daca_init(void);
+extern int daca_cleanup(void);
+extern int daca_set_volume(uint left_vol, uint right_vol);
+extern void daca_get_volume(uint * left_vol, uint  *right_vol);
+extern int daca_enter_sleep(void);
+extern int daca_leave_sleep(void);
+
+extern int tas_init(void);
+extern int tas_cleanup(void);
+extern int tumbler_set_volume(uint left_vol, uint right_vol);
+extern void tumbler_get_volume(uint * left_vol, uint  *right_vol);
+extern void tumbler_set_treble(int treble);
+extern void tumbler_get_treble(int *treble);
+extern void tumbler_set_bass(int bass);
+extern void tumbler_get_bass(int *bass);
+extern void tumbler_set_pcm_lvl(int pcm_lvl);
+extern void tumbler_get_pcm_lvl(int *pcm_lvl);
+extern int tumbler_enter_sleep(void);
+extern int tumbler_leave_sleep(void);
+
+#define TRY_LOCK()	\
+	if ((rc = down_interruptible(&dmasound_sem)) != 0)	\
+		return rc;
+#define LOCK()		down(&dmasound_sem);
+
+#define UNLOCK()	up(&dmasound_sem);
+
+/* We use different versions that the ones provided in dmasound.h
+ * 
+ * FIXME: Use different names ;)
+ */
+#undef IOCTL_IN
+#undef IOCTL_OUT
 
-/*** Translations ************************************************************/
-
+#define IOCTL_IN(arg, ret)	\
+	rc = get_user(ret, (int *)(arg)); \
+	if (rc) break;
+#define IOCTL_OUT(arg, ret)	\
+	ioctl_return2((int *)(arg), ret)
 
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	short *table = dmasound.soft.format == AFMT_MU_LAW
-		? dmasound_ulaw2dma16 : dmasound_alaw2dma16;
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = table[data];
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = table[data];
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = data << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = data << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = (data ^ 0x80) << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = (data ^ 0x80) << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = dmasound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			if (get_user(data, up++))
-				return -EFAULT;
-			*fp++ = data;
-			*fp++ = data;
-			count--;
-		}
-	} else {
-		if (copy_from_user(fp, userPtr, count * 4))
-			return -EFAULT;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
+static inline int ioctl_return2(int *addr, int value)
+{
+	return value < 0 ? value : put_user(value, addr);
 }
 
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = dmasound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		int data;
-		if (get_user(data, up++))
-			return -EFAULT;
-		data ^= mask;
-		*fp++ = data;
-		if (stereo) {
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-		}
-		*fp++ = data;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
 
+/*** AE - TUMBLER START *********************************************************/
 
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned short *table = (unsigned short *)
-		(dmasound.soft.format == AFMT_MU_LAW
-		 ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);
-	unsigned int data = expand_data;
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	int bal = expand_bal;
-	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
-	int utotal, ftotal;
-	int stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = table[c];
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + table[c];
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
 
+int gpio_audio_reset, gpio_audio_reset_pol;
+int gpio_amp_mute, gpio_amp_mute_pol;
+int gpio_headphone_mute, gpio_headphone_mute_pol;
+int gpio_headphone_detect, gpio_headphone_detect_pol;
+int gpio_headphone_irq;
 
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	int bal = expand_bal;
-	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
-	int stereo = dmasound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = c << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + (c << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
+int
+setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
+{
+	struct device_node *np;
+	u32* pp;
+	
+	np = find_devices("gpio");
+	if (!np)
+		return -ENODEV;
 
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	int bal = expand_bal;
-	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
-	int stereo = dmasound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
+	np = np->child;
+	while(np != 0) {
+		if (name) {
+			char *property = get_property(np,"audio-gpio",NULL);
+			if (property != 0 && strcmp(property,name) == 0)
 				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = (c ^ 0x80) << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + ((c ^ 0x80) << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
+		} else if (compatible && device_is_compatible(np, compatible))
+			break;
+		np = np->sibling;
+	}
+	if (!np)
+		return -ENODEV;
+	pp = (u32 *)get_property(np, "AAPL,address", NULL);
+	if (!pp)
+		return -ENODEV;
+	*gpio_addr = (*pp) & 0x0000ffff;
+	pp = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+	if (pp)
+		*gpio_pol = *pp;
+	else
+		*gpio_pol = 1;
+	if (np->n_intrs > 0)
+		return np->intrs[0].line;
+	
+	return 0;
 }
 
-
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = expand_bal;
-	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
-	int stereo = dmasound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + c;
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
+static inline void
+write_audio_gpio(int gpio_addr, int data)
+{
+	if (!gpio_addr)
+		return;
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04);
 }
 
+static inline int
+read_audio_gpio(int gpio_addr)
+{
+	if (!gpio_addr)
+		return 0;
+	return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0);
+}
 
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = expand_bal;
-	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
-	int stereo = dmasound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + (c ^ mask);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = val >> 8;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = val >> 8;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = (val >> 8) ^ 0x80;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = (val >> 8) ^ 0x80;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = dmasound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			data = *fp;
-			if (put_user(data, up++))
-				return -EFAULT;
-			fp+=2;
-			count--;
-		}
+static void
+headphone_intr(int irq, void *devid, struct pt_regs *regs)
+{
+	if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) {
+		printk(KERN_INFO "Audio jack plugged, muting speakers.\n");
+		write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
+		write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
 	} else {
-		if (copy_to_user((u_char *)userPtr, fp, count * 4))
-			return -EFAULT;
+		printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n");
+		write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
+		write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
 	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
 }
 
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = dmasound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min_t(unsigned long, userCount, frameLeft);
-	while (count > 0) {
-		int data;
-
-		data = *fp++;
-		data ^= mask;
-		if (put_user(data, up++))
-			return -EFAULT;
-		if (stereo) {
-			data = *fp;
-			data ^= mask;
-			if (put_user(data, up++))
-				return -EFAULT;
-		}
-		fp++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
+
+/* Initialize tumbler */
+
+static int
+awacs_tumbler_init(void)
+{
+	setup_audio_gpio(
+		"audio-hw-reset",
+		NULL,
+		&gpio_audio_reset,
+		&gpio_audio_reset_pol);
+	setup_audio_gpio(
+		"amp-mute",
+		NULL,
+		&gpio_amp_mute,
+		&gpio_amp_mute_pol);
+	setup_audio_gpio("headphone-mute",
+		NULL,
+		&gpio_headphone_mute,
+		&gpio_headphone_mute_pol);
+	gpio_headphone_irq = setup_audio_gpio(
+		"headphone-detect",
+		NULL,
+		&gpio_headphone_detect,
+		&gpio_headphone_detect_pol);
+	/* Fix some broken OF entries in desktop machines */
+	if (!gpio_headphone_irq)
+		gpio_headphone_irq = setup_audio_gpio(
+			NULL,
+			"keywest-gpio15",
+			&gpio_headphone_detect,
+			&gpio_headphone_detect_pol);
+
+	write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);
+	wait_ms(100);
+	write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
+	wait_ms(100);
+  	if (gpio_headphone_irq) {
+		if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",0) < 0) {
+    			printk(KERN_ERR "tumbler: Can't request headphone interrupt\n");
+    			gpio_headphone_irq = 0;
+    		} else {
+			u8 val;
+			/* Activate headphone status interrupts */
+			val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);
+			pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);
+			/* Trigger it */
+  			headphone_intr(0,0,0);
+  		}
+  	}
+  	if (!gpio_headphone_irq) {
+  		/* Some machine enter this case ? */
+  		printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n");
+  		write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
+  		write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
+  	}
+	return 0;
 }
 
 
-static TRANS transAwacsNormal = {
-	ct_ulaw:	pmac_ct_law,
-	ct_alaw:	pmac_ct_law,
-	ct_s8:		pmac_ct_s8,
-	ct_u8:		pmac_ct_u8,
-	ct_s16be:	pmac_ct_s16,
-	ct_u16be:	pmac_ct_u16,
-	ct_s16le:	pmac_ct_s16,
-	ct_u16le:	pmac_ct_u16,
-};
+static int
+awacs_tumbler_cleanup(void)
+{
+	if (gpio_headphone_irq)
+		free_irq(gpio_headphone_irq, 0);
+	return 0;
+}
 
-static TRANS transAwacsExpand = {
-	ct_ulaw:	pmac_ctx_law,
-	ct_alaw:	pmac_ctx_law,
-	ct_s8:		pmac_ctx_s8,
-	ct_u8:		pmac_ctx_u8,
-	ct_s16be:	pmac_ctx_s16,
-	ct_u16be:	pmac_ctx_u16,
-	ct_s16le:	pmac_ctx_s16,
-	ct_u16le:	pmac_ctx_u16,
-};
 
-static TRANS transAwacsNormalRead = {
-	ct_s8:		pmac_ct_s8_read,
-	ct_u8:		pmac_ct_u8_read,
-	ct_s16be:	pmac_ct_s16_read,
-	ct_u16be:	pmac_ct_u16_read,
-	ct_s16le:	pmac_ct_s16_read,
-	ct_u16le:	pmac_ct_u16_read,
-};
+/*** AE - TUMBLER END *********************************************************/
 
-/*** Low level stuff *********************************************************/
 
 
+/*** Low level stuff *********************************************************/
 
 /*
- * PCI PowerMac, with AWACS and DBDMA.
+ * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA.
  */
 
 static void PMacOpen(void)
@@ -827,9 +509,9 @@
 
 static int __init PMacIrqInit(void)
 {
-	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
-	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
-	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
+	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0)
+	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0)
+	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", 0))
 		return 0;
 	return 1;
 }
@@ -837,25 +519,44 @@
 #ifdef MODULE
 static void PMacIrqCleanup(void)
 {
-	/* turn off output dma */
-	out_le32(&awacs_txdma->control, RUN<<16);
+	/* turn off input & output dma */
+	DBDMA_DO_STOP(awacs_txdma);
+	DBDMA_DO_STOP(awacs_rxdma);
+
 	/* disable interrupts from awacs interface */
 	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-#ifdef CONFIG_PMAC_PBOOK
-	if (is_pbook_G3) {
-		feature_clear(awacs_node, FEATURE_Sound_power);
-		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+
+	/* Switch off the sound clock */
+	pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);
+	/* Make sure proper bits are set on pismo & tipb */
+	if (machine_is_compatible("PowerBook3,1") ||
+	    machine_is_compatible("PowerBook3,2")) {
+		awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
+		awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		wait_ms(200);
 	}
-#endif
 	free_irq(awacs_irq, 0);
 	free_irq(awacs_tx_irq, 0);
 	free_irq(awacs_rx_irq, 0);
-	kfree(awacs_tx_cmd_space);
+	/* all OF versions I've seen use this value */
+	iounmap((void *)awacs);
+	iounmap((void *)awacs_txdma);
+	iounmap((void *)awacs_rxdma);
+
+	release_OF_resource(awacs_node, 0);
+	release_OF_resource(awacs_node, 1);
+	release_OF_resource(awacs_node, 2);
+
+	if (awacs_tx_cmd_space)
+		kfree(awacs_tx_cmd_space);
 	if (awacs_rx_cmd_space)
 		kfree(awacs_rx_cmd_space);
-	if (beep_buf)
+	if (beep_dbdma_cmd_space)
+		kfree(beep_dbdma_cmd_space);
+	if (beep_buf) {
 		kfree(beep_buf);
-	kd_mksound = orig_mksound;
+		kd_mksound = orig_mksound;
+	}
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
 #endif
@@ -865,7 +566,32 @@
 static void PMacSilence(void)
 {
 	/* turn off output dma */
-	out_le32(&awacs_txdma->control, RUN<<16);
+	DBDMA_DO_STOP(awacs_txdma);
+}
+
+static int tumbler_freqs[2] = { 48000, 44100 } ;
+static int tumbler_freqs_ok[2] = { 1, 1 } ;
+
+/* don't know what to do really - just have to leave it where
+ * OF left things
+*/
+
+static int tumbler_set_frame_rate(void)
+{
+	dmasound.hard.speed = 44100 ;
+	awacs_rate_index = 0 ;
+	return 44100 ;
+}
+
+/* don't know what to do really - just have to leave it where
+ * OF left things
+*/
+
+static int daca_set_frame_rate(void)
+{
+	dmasound.hard.speed = 44100 ;
+	awacs_rate_index = 0 ;
+	return 44100 ;
 }
 
 static int awacs_freqs[8] = {
@@ -873,59 +599,115 @@
 };
 static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
 
-static void PMacInit(void)
+static int awacs_set_frame_rate(int desired, int catch_r)
 {
-	int i, tolerance;
-
-	switch (dmasound.soft.format) {
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		dmasound.hard.format = AFMT_S16_LE;
-		break;
-	default:
-		dmasound.hard.format = AFMT_S16_BE;
-		break;
-	}
-	dmasound.hard.stereo = 1;
-	dmasound.hard.size = 16;
-
+	int tolerance, i = 8 ;
 	/*
 	 * If we have a sample rate which is within catchRadius percent
 	 * of the requested value, we don't have to expand the samples.
 	 * Otherwise choose the next higher rate.
-	 * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
+	 * N.B.: burgundy awacs only works at 44100 Hz.
 	 */
-	i = 8;
 	do {
-		tolerance = catchRadius * awacs_freqs[--i] / 100;
+		tolerance = catch_r * awacs_freqs[--i] / 100;
 		if (awacs_freqs_ok[i]
 		    && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
 			break;
 	} while (i > 0);
-	if (dmasound.soft.speed >= awacs_freqs[i] - tolerance)
-		dmasound.trans_write = &transAwacsNormal;
-	else
-		dmasound.trans_write = &transAwacsExpand;
-	dmasound.trans_read = &transAwacsNormalRead;
 	dmasound.hard.speed = awacs_freqs[i];
 	awacs_rate_index = i;
 
-	/* XXX disable error interrupt on burgundy for now */
-	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
-		 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 );
 	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
 	awacs_write(awacs_reg[1] | MASK_ADDR1);
-	out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+	return dmasound.hard.speed;
+}
+
+static int burgundy_frame_rates = 1 ;
+static int burgundy_set_frame_rate(void)
+{
+#ifdef DEBUG_DMASOUND
+if (burgundy_frame_rates > 1)
+	printk("dmasound_pmac: warning Burgundy had more than one frame rate\n");
+#endif
+	awacs_rate_index = 0 ;
+	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ;
+	/* XXX disable error interrupt on burgundy for now */
+	out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE);
+	return 44100 ;
+}
 
-	/* We really want to execute a DMA stop command, after the AWACS
-	 * is initialized.
-	 * For reasons I don't understand, it stops the hissing noise
-	 * common to many PowerBook G3 systems (like mine :-).
+static int set_frame_rate(int desired, int catch_r)
+{
+	switch (awacs_revision) {
+		case AWACS_BURGUNDY:
+			dmasound.hard.speed =
+			  burgundy_set_frame_rate();
+			break ;
+		case AWACS_TUMBLER:
+			dmasound.hard.speed =
+			  tumbler_set_frame_rate();
+			break ;
+		case AWACS_DACA:
+			dmasound.hard.speed =
+			  daca_set_frame_rate();
+			break ;
+		default:
+			dmasound.hard.speed =
+			  awacs_set_frame_rate(desired, catch_r);
+			break ;
+	}
+	return dmasound.hard.speed ;
+}
+
+static void
+awacs_recalibrate(void)
+{
+	/* Sorry for the horrible delays... I hope to get that improved
+	 * by making the whole PM process asynchronous in a future version
 	 */
-	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
-	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
-	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+	wait_ms(750);
+	awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE;
+	awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1);
+	wait_ms(1000);
+	awacs_write(awacs_reg[1] | MASK_ADDR1);
+}
+
+static void PMacInit(void)
+{
+	int tolerance;
+
+	switch (dmasound.soft.format) {
+	    case AFMT_S16_LE:
+	    case AFMT_U16_LE:
+		if (hw_can_byteswap)
+			dmasound.hard.format = AFMT_S16_LE;
+		else
+			dmasound.hard.format = AFMT_S16_BE;
+		break;
+	default:
+		dmasound.hard.format = AFMT_S16_BE;
+		break;
+	}
+	dmasound.hard.stereo = 1;
+	dmasound.hard.size = 16;
+
+	/* set dmasound.hard.speed - on the basis of what we want (soft)
+	 * and the tolerance we'll allow.
+	*/
+	set_frame_rate(dmasound.soft.speed, catchRadius) ;
+
+	tolerance = (catchRadius * dmasound.hard.speed) / 100;
+	if (dmasound.soft.speed >= dmasound.hard.speed - tolerance)
+		dmasound.trans_write = &transAwacsNormal;
+	else
+		dmasound.trans_write = &transAwacsExpand;
+	dmasound.trans_read = &transAwacsNormalRead;
+
+	if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
+		out_le32(&awacs->byteswap, BS_VAL);
+	else
+		out_le32(&awacs->byteswap, 0);
 
 	expand_bal = -dmasound.soft.speed;
 }
@@ -933,7 +715,8 @@
 static int PMacSetFormat(int format)
 {
 	int size;
-
+	int req_format = format;
+		
 	switch (format) {
 	case AFMT_QUERY:
 		return dmasound.soft.format;
@@ -943,10 +726,16 @@
 	case AFMT_S8:
 		size = 8;
 		break;
-	case AFMT_S16_BE:
-	case AFMT_U16_BE:
 	case AFMT_S16_LE:
+		if(!hw_can_byteswap)
+			format = AFMT_S16_BE;
+	case AFMT_S16_BE:
+		size = 16;
+		break;
 	case AFMT_U16_LE:
+		if(!hw_can_byteswap)
+			format = AFMT_U16_BE;
+	case AFMT_U16_BE:
 		size = 16;
 		break;
 	default: /* :-) */
@@ -955,16 +744,16 @@
 		size = 8;
 		format = AFMT_U8;
 	}
-
-	dmasound.soft.format = format;
-	dmasound.soft.size = size;
-	if (dmasound.minDev == SND_DEV_DSP) {
-		dmasound.dsp.format = format;
-		dmasound.dsp.size = size;
+	
+	if (req_format == format) {
+		dmasound.soft.format = format;
+		dmasound.soft.size = size;
+		if (dmasound.minDev == SND_DEV_DSP) {
+			dmasound.dsp.format = format;
+			dmasound.dsp.size = size;
+		}
 	}
 
-	PMacInit();
-
 	return format;
 }
 
@@ -1007,48 +796,91 @@
 	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
 }
 
-static void PMacPlay(void)
+static void __PMacPlay(void)
 {
 	volatile struct dbdma_cmd *cp;
-	int i, count;
+	int next_frg, count;
 	unsigned long flags;
 
+	/* CHECK: how much of this *really* needs IRQs masked? */
+
 	save_flags(flags); cli();
+	count = 300 ; /* > two cycles at the lowest sample rate */
+
+	/* what we want to send next */
+	next_frg = (write_sq.front + write_sq.active) % write_sq.max_count;
+
 	if (awacs_beep_state) {
 		/* sound takes precedence over beeps */
+		/* stop the dma channel */
 		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		while ( (in_le32(&awacs_txdma->status) & RUN) && count--)
+			udelay(1);
+		/* FIXME: check that this is OK for other chip sets */
 		out_le32(&awacs->control,
 			 (in_le32(&awacs->control) & ~0x1f00)
 			 | (awacs_rate_index << 8));
-		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
-		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count])));
+
+		if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
+			out_le32(&awacs->byteswap, BS_VAL);
+		else
+			out_le32(&awacs->byteswap, 0);
+		out_le32(&awacs_txdma->cmdptr,
+			 virt_to_bus(&(awacs_tx_cmds[next_frg])));
 
 		beep_playing = 0;
 		awacs_beep_state = 0;
 	}
-	i = write_sq.front + write_sq.active;
-	if (i >= write_sq.max_count)
-		i -= write_sq.max_count;
+	/* this won't allow more than two frags to be in the output queue at
+	   once. (or one, if the max frags is 2 - because count can't exceed
+	   2 in that case)
+	*/
 	while (write_sq.active < 2 && write_sq.active < write_sq.count) {
-		count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size;
-		if (count < write_sq.block_size && !write_sq.syncing)
-			/* last block not yet filled, and we're not syncing. */
-			break;
-		cp = &awacs_tx_cmds[i];
+		count = (write_sq.count == write_sq.active + 1) ?
+				write_sq.rear_size:write_sq.block_size ;
+		if (count < write_sq.block_size) {
+			if (!write_sq.syncing) /* last block not yet filled,*/
+				break; 	/* and we're not syncing or POST-ed */
+			else {
+				/* pretend the block is full to force a new
+				   block to be started on the next write */
+				write_sq.rear_size = write_sq.block_size ;
+				write_sq.syncing &= ~2 ; /* clear POST */
+			}
+		}
+		cp = &awacs_tx_cmds[next_frg];
 		st_le16(&cp->req_count, count);
 		st_le16(&cp->xfer_status, 0);
-		if (++i >= write_sq.max_count)
-			i = 0;
-		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
-		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+		st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+		/* put a STOP at the end of the queue - but only if we have
+		   space for it.  This means that, if we under-run and we only
+		   have two fragments, we might re-play sound from an existing
+		   queued frag.  I guess the solution to that is not to set two
+		   frags if you are likely to under-run...
+		*/
+		if (write_sq.count < write_sq.max_count) {
+			if (++next_frg >= write_sq.max_count)
+				next_frg = 0 ; /* wrap */
+			/* if we get here then we've underrun so we will stop*/
+			st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP);
+		}
+		/* set the dbdma controller going, if it is not already */
 		if (write_sq.active == 0)
 			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+		(void)in_le32(&awacs_txdma->status);
 		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
 		++write_sq.active;
 	}
 	restore_flags(flags);
 }
 
+static void PMacPlay(void)
+{
+	LOCK();
+	if (!awacs_sleeping)
+		__PMacPlay();
+	UNLOCK();
+}
 
 static void PMacRecord(void)
 {
@@ -1067,6 +899,26 @@
 	restore_flags(flags);
 }
 
+/* if the TX status comes up "DEAD" - reported on some Power Computing machines
+   we need to re-start the dbdma - but from a different physical start address
+   and with a different transfer length.  It would get very messy to do this
+   with the normal dbdma_cmd blocks - we would have to re-write the buffer start
+   addresses each time.  So, we will keep a single dbdma_cmd block which can be
+   fiddled with.
+   When DEAD status is first reported the content of the faulted dbdma block is
+   copied into the emergency buffer and we note that the buffer is in use.
+   we then bump the start physical address by the amount that was successfully
+   output before it died.
+   On any subsequent DEAD result we just do the bump-ups (we know that we are
+   already using the emergency dbdma_cmd).
+   CHECK: this just tries to "do it".  It is possible that we should abandon
+   xfers when the number of residual bytes gets below a certain value - I can
+   see that this might cause a loop-forever if too small a transfer causes
+   DEAD status.  However this is a TODO for now - we'll see what gets reported.
+   When we get a successful transfer result with the emergency buffer we just
+   pretend that it completed using the original dmdma_cmd and carry on.  The
+   'next_cmd' field will already point back to the original loop of blocks.
+*/
 
 static void
 pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
@@ -1074,35 +926,94 @@
 	int i = write_sq.front;
 	int stat;
 	volatile struct dbdma_cmd *cp;
+	/* != 0 when we are dealing with a DEAD xfer */
+	static int emergency_in_use = 0 ;
 
-	while (write_sq.active > 0) {
-		cp = &awacs_tx_cmds[i];
+	while (write_sq.active > 0) { /* we expect to have done something*/
+		if (emergency_in_use) /* we are dealing with DEAD xfer */
+			cp = emergency_dbdma_cmd ;
+		else
+			cp = &awacs_tx_cmds[i];
 		stat = ld_le16(&cp->xfer_status);
+		if (stat & DEAD) {
+			unsigned short req, res ;
+			unsigned int phy ;
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;
+#endif
+			/* to clear DEAD status we must first clear RUN
+			   set it to quiescent to be on the safe side */
+			(void)in_le32(&awacs_txdma->status);
+			out_le32(&awacs_txdma->control,
+				(RUN|PAUSE|FLUSH|WAKE) << 16);
+			write_sq.died++ ;
+			if (!emergency_in_use) { /* new problem */
+				memcpy((void *)emergency_dbdma_cmd, (void *)cp,
+					sizeof(struct dbdma_cmd));
+				emergency_in_use = 1;
+				cp = emergency_dbdma_cmd;
+			}
+			/* now bump the values to reflect the amount
+			   we haven't yet shifted */
+			req = ld_le16(&cp->req_count);
+			res = ld_le16(&cp->res_count);
+			phy = ld_le32(&cp->phy_addr);
+			phy += (req - res);
+			st_le16(&cp->req_count, res);
+			st_le16(&cp->res_count, 0);
+			st_le16(&cp->xfer_status, 0);
+			st_le32(&cp->phy_addr, phy);
+			st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count]));
+			st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
+			
+			/* point at our patched up command block */
+			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+			/* we must re-start the controller */
+			(void)in_le32(&awacs_txdma->status);
+			/* should complete clearing the DEAD status */
+			out_le32(&awacs_txdma->control,
+				((RUN|WAKE) << 16) + (RUN|WAKE));
+			break; /* this block is still going */
+		}
 		if ((stat & ACTIVE) == 0)
 			break;	/* this frame is still going */
+		if (emergency_in_use)
+			emergency_in_use = 0 ; /* done that */
 		--write_sq.count;
 		--write_sq.active;
 		if (++i >= write_sq.max_count)
 			i = 0;
 	}
+
+	/* if we stopped and we were not sync-ing - then we under-ran */
+	if( write_sq.syncing == 0 ){
+		stat = in_le32(&awacs_txdma->status) ;
+		/* we hit the dbdma_stop */
+		if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ;
+	}
+
+	/* if we used some data up then wake the writer to supply some more*/
 	if (i != write_sq.front)
 		WAKE_UP(write_sq.action_queue);
 	write_sq.front = i;
 
-	PMacPlay();
-
-	if (!write_sq.active)
-		WAKE_UP(write_sq.sync_queue);
+	/* but make sure we funnel what we've already got */\
+	 if (!awacs_sleeping)
+		__PMacPlay();
+
+	/* make the wake-on-empty conditional on syncing */
+	if (!write_sq.active && (write_sq.syncing & 1))
+		WAKE_UP(write_sq.sync_queue); /* any time we're empty */
 }
 
 
 static void
 pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
 {
-
+	int stat ;
 	/* For some reason on my PowerBook G3, I get one interrupt
 	 * when the interrupt vector is installed (like something is
-	 * pending).  This happens before the dbdma is initialize by
+	 * pending).  This happens before the dbdma is initialized by
 	 * us, so I just check the command pointer and if it is zero,
 	 * just blow it off.
 	 */
@@ -1118,8 +1029,35 @@
 	 * interrupt processing for a long time.  Geeze, I really hope
 	 * this doesn't happen.
 	 */
-	while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+	while ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) {
 
+		/* if we got a "DEAD" status then just log it for now.
+		   and try to restart dma.
+		   TODO: figure out how best to fix it up
+		*/
+		if (stat & DEAD){
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n");
+#endif
+			/* to clear DEAD status we must first clear RUN
+			   set it to quiescent to be on the safe side */
+			(void)in_le32(&awacs_txdma->status);
+			out_le32(&awacs_txdma->control,
+				(RUN|PAUSE|FLUSH|WAKE) << 16);
+			awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+			awacs_rx_cmds[read_sq.rear].res_count = 0;
+			read_sq.died++ ;
+			(void)in_le32(&awacs_txdma->status);
+			/* re-start the same block */
+			out_le32(&awacs_rxdma->cmdptr,
+				virt_to_bus(&awacs_rx_cmds[read_sq.rear]));
+			/* we must re-start the controller */
+			(void)in_le32(&awacs_rxdma->status);
+			/* should complete clearing the DEAD status */
+			out_le32(&awacs_rxdma->control,
+				((RUN|WAKE) << 16) + (RUN|WAKE));
+			return; /* try this block again */
+		}
 		/* Clear status and move on to next buffer.
 		*/
 		awacs_rx_cmds[read_sq.rear].xfer_status = 0;
@@ -1138,6 +1076,7 @@
 		 */
 		if (read_sq.rear == read_sq.front) {
 			read_sq.front++;
+			read_sq.xruns++ ; /* we overan */
 			if (read_sq.front >= read_sq.max_active)
 				read_sq.front = 0;
 		}
@@ -1157,8 +1096,9 @@
 	}
 	if (ctrl & MASK_CNTLERR) {
 		int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
-		if (err != 0 && awacs_revision < AWACS_BURGUNDY)
-			printk(KERN_ERR "AWACS: error %x\n", err);
+		/* CHECK: we just swallow burgundy errors at the moment..*/
+		if (err != 0 && awacs_revision != AWACS_BURGUNDY)
+			printk(KERN_ERR "dmasound_pmac: error %x\n", err);
 	}
 	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
 	out_le32(&awacs->control, ctrl);
@@ -1167,25 +1107,38 @@
 static void
 awacs_write(int val)
 {
-	if (awacs_revision >= AWACS_BURGUNDY)
-		return;
-	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
-		;	/* XXX should have timeout */
+	int count = 300 ;
+	if (awacs_revision >= AWACS_DACA)
+		return ;
+
+	while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)
+		udelay(1) ;	/* timeout is > 2 samples at lowest rate */
 	out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
+	(void)in_le32(&awacs->byteswap);
 }
 
+/* this is called when the beep timer expires... it will be called even
+   if the beep has been overidden by other sound output.
+*/
 static void awacs_nosound(unsigned long xx)
 {
 	unsigned long flags;
+	int count = 600 ; /* > four samples at lowest rate */
 
 	save_flags(flags); cli();
 	if (beep_playing) {
 		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
 		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		while ((in_le32(&awacs_txdma->status) & RUN) && count--)
+			udelay(1);
+		/* FIXME: check this is OK for DACA, Tumbler */
 		out_le32(&awacs->control,
 			 (in_le32(&awacs->control) & ~0x1f00)
 			 | (awacs_rate_index << 8));
-		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+		if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
+			out_le32(&awacs->byteswap, BS_VAL);
+		else
+			out_le32(&awacs->byteswap, 0);
 		beep_playing = 0;
 	}
 	restore_flags(flags);
@@ -1195,6 +1148,11 @@
 	function: awacs_nosound
 };
 
+/* we generate the beep with a single dbdma command that loops a buffer
+   forever - without generating interrupts.
+   So, to stop it you have to stop dma output as per awacs_nosound.
+*/
+
 static void awacs_mksound(unsigned int hz, unsigned int ticks)
 {
 	unsigned long flags;
@@ -1207,11 +1165,19 @@
 	static int beep_nsamples_cache;
 	static int beep_volume_cache;
 
-	for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
-		if (awacs_freqs_ok[i])
-			beep_speed = i;
-	srate = awacs_freqs[beep_speed];
+	if (beep_buf == NULL)
+		return;
+
+	/* quick-hack fix for DACA, Burgundy & Tumbler */
 
+	if (awacs_revision >= AWACS_DACA){
+		srate = 44100 ;
+	} else {
+		for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
+			if (awacs_freqs_ok[i])
+				beep_speed = i;
+		srate = awacs_freqs[beep_speed];
+	}
 	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
 #if 1
 		/* this is a hack for broken X server code */
@@ -1237,7 +1203,7 @@
 	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
 	restore_flags(flags);
 
-	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+	if (hz == beep_hz_cache && beep_vol == beep_volume_cache) {
 		nsamples = beep_nsamples_cache;
 	} else {
 		period = srate * 256 / hz;	/* fixed point */
@@ -1247,11 +1213,11 @@
 		j = 0;
 		p = beep_buf;
 		for (i = 0; i < nsamples; ++i, p += 2) {
-			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+			p[0] = p[1] = beep_wform[j >> 8] * beep_vol;
 			j = (j + f) & 0xffff;
 		}
 		beep_hz_cache = hz;
-		beep_volume_cache = beep_volume;
+		beep_volume_cache = beep_vol;
 		beep_nsamples_cache = nsamples;
 	}
 
@@ -1263,78 +1229,159 @@
 
 	save_flags(flags); cli();
 	if (beep_playing) {	/* i.e. haven't been terminated already */
+		int count = 300 ;
 		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+		while ((in_le32(&awacs_txdma->status) & RUN) && count--)
+			udelay(1); /* timeout > 2 samples at lowest rate*/
+		/* FIXME: check this is OK on DACA, Tumbler */
 		out_le32(&awacs->control,
 			 (in_le32(&awacs->control) & ~0x1f00)
 			 | (beep_speed << 8));
-		out_le32(&awacs->byteswap, 0);
+		out_le32(&awacs->byteswap, 0); /* force BE */
 		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+		(void)in_le32(&awacs_txdma->status);
 		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
 	}
 	restore_flags(flags);
 }
 
+/* used in init and for wake-up */
+
+static void
+load_awacs(void)
+{
+	awacs_write(awacs_reg[0] + MASK_ADDR0);
+	awacs_write(awacs_reg[1] + MASK_ADDR1);
+	awacs_write(awacs_reg[2] + MASK_ADDR2);
+	awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+	if (awacs_revision == AWACS_SCREAMER) {
+		awacs_write(awacs_reg[5] + MASK_ADDR5);
+		wait_ms(100);
+		awacs_write(awacs_reg[6] + MASK_ADDR6);
+		wait_ms(2);
+		awacs_write(awacs_reg[1] + MASK_ADDR1);
+		awacs_write(awacs_reg[7] + MASK_ADDR7);
+	}
+	if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
+		out_le32(&awacs->byteswap, BS_VAL);
+	else
+		out_le32(&awacs->byteswap, 0);
+}
+
 #ifdef CONFIG_PMAC_PBOOK
 /*
  * Save state when going to sleep, restore it afterwards.
  */
+/* FIXME: sort out disabling/re-enabling of read stuff as well */
 static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	switch (when) {
-	case PBOOK_SLEEP_NOW:
-		/* XXX we should stop any dma in progress when going to sleep
-		   and restart it when we wake. */
+	case PBOOK_SLEEP_NOW:		
+		LOCK();
+		awacs_sleeping = 1;
+		/* Tell the rest of the driver we are now going to sleep */
+		mb();
+		if (awacs_revision == AWACS_SCREAMER ||
+		    awacs_revision == AWACS_AWACS) {
+			awacs_reg1_save = awacs_reg[1];
+			awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE;
+			awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		}
+
 		PMacSilence();
+		/* stop rx - if going - a bit of a daft user... but */
+		out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16));
+		/* deny interrupts */
+		switch (awacs_revision) {
+			case AWACS_TUMBLER:
+				tumbler_enter_sleep(); /* Stub for now */
+				break ;
+			case AWACS_DACA:
+				daca_enter_sleep();
+				break ;
+			case AWACS_BURGUNDY:
+				break ;
+			case AWACS_SCREAMER:
+			case AWACS_AWACS:
+			default:
+				out_le32(&awacs->control, 0x11) ;
+				break ;
+		}
 		disable_irq(awacs_irq);
 		disable_irq(awacs_tx_irq);
-		if (is_pbook_G3) {
-			feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
-			feature_clear(awacs_node, FEATURE_Sound_power);
+		disable_irq(awacs_rx_irq);
+		/* Disable sound clock */
+		pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);
+		/* According to Darwin, we do that after turning off the sound
+		 * chip clock. All this will have to be cleaned up once we properly
+		 * parse the OF sound-objects
+		 */
+		if (machine_is_compatible("PowerBook3,1") ||
+		    machine_is_compatible("PowerBook3,2")) {
+			awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
+			awacs_write(MASK_ADDR1 | awacs_reg[1]);
+			wait_ms(200);
 		}
 		break;
 	case PBOOK_WAKE:
-		/* There is still a problem on wake. Sound seems to work fine
-		   if I launch mpg123 and resumes fine if mpg123 was playing,
-		   but the console beep is dead until I do something with the
-		   mixer. Probably yet another timing issue */
-		if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
-		    || !feature_test(awacs_node, FEATURE_Sound_power)) {
-			/* these aren't present on the 3400 AFAIK -- paulus */
-			feature_set(awacs_node, FEATURE_Sound_CLK_enable);
-			feature_set(awacs_node, FEATURE_Sound_power);
-			mdelay(1000);
-		}
-		out_le32(&awacs->control, MASK_IEPC
-			 | (awacs_rate_index << 8) | 0x11
-			 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
-		awacs_write(awacs_reg[0] | MASK_ADDR0);
-		awacs_write(awacs_reg[1] | MASK_ADDR1);
-		awacs_write(awacs_reg[2] | MASK_ADDR2);
-		awacs_write(awacs_reg[4] | MASK_ADDR4);
-		if (awacs_is_screamer) {
-			awacs_write(awacs_reg[5] + MASK_ADDR5);
-			awacs_write(awacs_reg[6] + MASK_ADDR6);
-			awacs_write(awacs_reg[7] + MASK_ADDR7);
-		}
-		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+		/* Enable sound clock */
+		pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1);
+		if (machine_is_compatible("PowerBook3,1") ||
+		    machine_is_compatible("PowerBook3,2")) {
+			wait_ms(100);
+			awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1);
+			awacs_write(MASK_ADDR1 | awacs_reg[1]);
+			wait_ms(300);
+		} else
+			wait_ms(1000);
+ 		/* restore settings */
+		switch (awacs_revision) {
+			case AWACS_TUMBLER:
+				headphone_intr(0,0,0);
+				tumbler_leave_sleep(); /* Stub for now */
+				break;
+			case AWACS_DACA:
+				wait_ms(10); /* Check this !!! */
+				daca_leave_sleep();
+				break ;		/* dont know how yet */
+			case AWACS_BURGUNDY:
+				break ;
+			case AWACS_SCREAMER:
+			case AWACS_AWACS:
+			default:
+		 		load_awacs() ;
+				break ;
+		}
+		/* Recalibrate chip */
+		if (awacs_revision == AWACS_SCREAMER)
+			awacs_recalibrate();
+		/* Make sure dma is stopped */
+		PMacSilence();
 		enable_irq(awacs_irq);
 		enable_irq(awacs_tx_irq);
-		if (awacs_revision == 3) {
-			mdelay(100);
-			awacs_write(0x6000);
-			mdelay(2);
-			awacs_write(awacs_reg[1] | MASK_ADDR1);
-		}
-		/* enable CD sound input */
-		if (macio_base && is_pbook_G3) {
+ 		enable_irq(awacs_rx_irq);
+ 		/* OK, allow ints back again */
+ 		out_le32(&awacs->control, MASK_IEPC
+ 		 	| (awacs_rate_index << 8) | 0x11
+ 			 | (awacs_revision < AWACS_DACA ? MASK_IEE: 0));
+ 		if (macio_base && is_pbook_g3) {
+			/* FIXME: should restore the setup we had...*/
 			out_8(macio_base + 0x37, 3);
-		} else if (is_pbook_3400) {
-			feature_set(awacs_node, FEATURE_IOBUS_enable);
-			udelay(10);
+ 		} else if (is_pbook_3X00) {
 			in_8(latch_base + 0x190);
 		}
+		/* Remove mute */
+		if (awacs_revision == AWACS_SCREAMER ||
+		    awacs_revision == AWACS_AWACS) {
+			awacs_reg[1] = awacs_reg1_save;
+			awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		}
+ 		awacs_sleeping = 0;
 		/* Resume pending sounds. */
-		PMacPlay();
+		/* we don't try to restart input... */
+		__PMacPlay();
+		UNLOCK();
 	}
 	return PBOOK_SLEEP_OK;
 }
@@ -1347,17 +1394,20 @@
 inline static void
 awacs_burgundy_busy_wait(void)
 {
-	while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
-		;
+	int count = 50; /* > 2 samples at 44k1 */
+	while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)
+		udelay(1) ;
 }
 
 inline static void
 awacs_burgundy_extend_wait(void)
 {
-	while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
-		;
-	while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
-		;
+	int count = 50 ; /* > 2 samples at 44k1 */
+	while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--)
+		udelay(1) ;
+	count = 50;
+	while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--)
+		udelay(1);
 }
 
 static void
@@ -1447,7 +1497,7 @@
 awacs_burgundy_init(void)
 {
 	if (awacs_burgundy_check()) {
-		printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
+		printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n");
 		return 1;
 	}
 
@@ -1515,9 +1565,6 @@
 	return softvolume > 0 ? softvolume : 0;
 }
 
-
-
-
 static int
 awacs_burgundy_read_mvolume(unsigned address)
 {
@@ -1533,7 +1580,6 @@
 	return lvolume + (rvolume << 8);
 }
 
-
 static void
 awacs_burgundy_write_mvolume(unsigned address, int volume)
 {
@@ -1550,21 +1596,23 @@
 
 /* End burgundy functions */
 
+/* Set up output volumes on machines with the 'perch/whisper' extension card.
+ * this has an SGS i2c chip (7433) which is accessed using the cuda.
+ *
+ * TODO: split this out and make use of the other parts of the SGS chip to
+ * do Bass, Treble etc.
+ */
 
-
-
-
-/* Turn on sound output, needed on G3 desktop powermacs */
 static void
 awacs_enable_amp(int spkr_vol)
 {
+#ifdef CONFIG_ADB_CUDA
 	struct adb_request req;
 
 	awacs_spkr_vol = spkr_vol;
 	if (sys_ctrler != SYS_CTRLER_CUDA)
 		return;
 
-#ifdef CONFIG_ADB_CUDA
 	/* turn on headphones */
 	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
 		     0x8a, 4, 0);
@@ -1595,22 +1643,105 @@
  * /dev/mixer abstraction
  */
 
+static void do_line_lev(int data)
+{
+		line_lev = data ;
+		awacs_reg[0] &= ~MASK_MUX_AUDIN;
+		if ((data & 0xff) >= 50)
+			awacs_reg[0] |= MASK_MUX_AUDIN;
+		awacs_write(MASK_ADDR0 | awacs_reg[0]);
+}
+
+static void do_ip_gain(int data)
+{
+	ip_gain = data ;
+	data &= 0xff;
+	awacs_reg[0] &= ~MASK_GAINLINE;
+	if (awacs_revision == AWACS_SCREAMER) {
+		awacs_reg[6] &= ~MASK_MIC_BOOST ;
+		if (data >= 33) {
+			awacs_reg[0] |= MASK_GAINLINE;
+			if( data >= 66)
+				awacs_reg[6] |= MASK_MIC_BOOST ;
+		}
+		awacs_write(MASK_ADDR6 | awacs_reg[6]) ;
+	} else {
+		if (data >= 50)
+			awacs_reg[0] |= MASK_GAINLINE;
+	}
+	awacs_write(MASK_ADDR0 | awacs_reg[0]);
+}
+
+static void do_mic_lev(int data)
+{
+	mic_lev = data ;
+	data &= 0xff;
+	awacs_reg[0] &= ~MASK_MUX_MIC;
+	if (data >= 50)
+		awacs_reg[0] |= MASK_MUX_MIC;
+	awacs_write(MASK_ADDR0 | awacs_reg[0]);
+}
+
+static void do_cd_lev(int data)
+{
+	cd_lev = data ;
+	awacs_reg[0] &= ~MASK_MUX_CD;
+	if ((data & 0xff) >= 50)
+		awacs_reg[0] |= MASK_MUX_CD;
+	awacs_write(MASK_ADDR0 | awacs_reg[0]);
+}
+
+static void do_rec_lev(int data)
+{
+	int left, right ;
+	rec_lev = data ;
+	/* need to fudge this to use the volume setter routine */
+	left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ;
+	right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ;
+	left |= (right << 8 );
+	left = awacs_volume_setter(left, 0, 0, 4);
+}
+
+static void do_passthru_vol(int data)
+{
+	passthru_vol = data ;
+	awacs_reg[1] &= ~MASK_LOOPTHRU;
+	if (awacs_revision == AWACS_SCREAMER) {
+		if( data ) { /* switch it on for non-zero */
+			awacs_reg[1] |= MASK_LOOPTHRU;
+			awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		}
+		data = awacs_volume_setter(data, 5, 0, 6) ;
+	} else {
+		if ((data & 0xff) >= 50)
+			awacs_reg[1] |= MASK_LOOPTHRU;
+		awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0;
+	}
+}
+
 static int awacs_mixer_ioctl(u_int cmd, u_long arg)
 {
 	int data;
+	int rc;
 
 	switch (cmd) {
+	case SOUND_MIXER_READ_CAPS:
+		/* say we will allow multiple inputs?  prob. wrong
+			so I'm switching it to single */
+		return IOCTL_OUT(arg, 1);
 	case SOUND_MIXER_READ_DEVMASK:
-		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
-			| SOUND_MASK_LINE | SOUND_MASK_MIC
-			| SOUND_MASK_CD | SOUND_MASK_RECLEV
+		data  = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+			| SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD
+			| SOUND_MASK_IGAIN | SOUND_MASK_RECLEV
 			| SOUND_MASK_ALTPCM
 			| SOUND_MASK_MONITOR;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_RECMASK:
-		data = SOUND_MASK_LINE | SOUND_MASK_MIC
-			| SOUND_MASK_CD;
-		return IOCTL_OUT(arg, data);
+		data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD;
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_RECSRC:
 		data = 0;
 		if (awacs_reg[0] & MASK_MUX_AUDIN)
@@ -1619,122 +1750,122 @@
 			data |= SOUND_MASK_MIC;
 		if (awacs_reg[0] & MASK_MUX_CD)
 			data |= SOUND_MASK_CD;
-		if (awacs_reg[1] & MASK_LOOPTHRU)
-			data |= SOUND_MASK_MONITOR;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_RECSRC:
 		IOCTL_IN(arg, data);
-		data &= (SOUND_MASK_LINE
-			 | SOUND_MASK_MIC | SOUND_MASK_CD
-			 | SOUND_MASK_MONITOR);
+		data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD);
 		awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
 				  | MASK_MUX_AUDIN);
-		awacs_reg[1] &= ~MASK_LOOPTHRU;
 		if (data & SOUND_MASK_LINE)
 			awacs_reg[0] |= MASK_MUX_AUDIN;
 		if (data & SOUND_MASK_MIC)
 			awacs_reg[0] |= MASK_MUX_MIC;
 		if (data & SOUND_MASK_CD)
 			awacs_reg[0] |= MASK_MUX_CD;
-		if (data & SOUND_MASK_MONITOR)
-			awacs_reg[1] |= MASK_LOOPTHRU;
 		awacs_write(awacs_reg[0] | MASK_ADDR0);
-		awacs_write(awacs_reg[1] | MASK_ADDR1);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_STEREODEVS:
-		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
-			| SOUND_MASK_RECLEV;
-		return IOCTL_OUT(arg, data);
-	case SOUND_MIXER_READ_CAPS:
-		return IOCTL_OUT(arg, 0);
-	case SOUND_MIXER_READ_VOLUME:
-		data = (awacs_reg[1] & MASK_AMUTE)? 0:
-			awacs_get_volume(awacs_reg[2], 6);
-		return IOCTL_OUT(arg, data);
+		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV  ;
+		if (awacs_revision == AWACS_SCREAMER)
+			data |= SOUND_MASK_MONITOR ;
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_VOLUME:
 		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, PMacSetVolume(data));
-	case SOUND_MIXER_READ_SPEAKER:
-		if (awacs_revision == 3
-		    && sys_ctrler == SYS_CTRLER_CUDA)
-			data = awacs_spkr_vol;
-		else
-			data = (awacs_reg[1] & MASK_CMUTE)? 0:
-				awacs_get_volume(awacs_reg[4], 6);
-		return IOCTL_OUT(arg, data);
+		line_vol = data ;
+		awacs_volume_setter(data, 2, 0, 6);
+		/* fall through */
+	case SOUND_MIXER_READ_VOLUME:
+		rc = IOCTL_OUT(arg, line_vol);
+		break;
 	case SOUND_MIXER_WRITE_SPEAKER:
 		IOCTL_IN(arg, data);
-		if (awacs_revision == 3
-		    && sys_ctrler == SYS_CTRLER_CUDA)
+		spk_vol = data ;
+		if (has_perch)
 			awacs_enable_amp(data);
 		else
-			data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
-		return IOCTL_OUT(arg, data);
+			(void)awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+		/* fall though */
+	case SOUND_MIXER_READ_SPEAKER:
+		rc = IOCTL_OUT(arg, spk_vol);
+		break;
 	case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
 		IOCTL_IN(arg, data);
-		beep_volume = data & 0xff;
-				/* fall through */
+		beep_vol = data & 0xff;
+		/* fall through */
 	case SOUND_MIXER_READ_ALTPCM:
-		return IOCTL_OUT(arg, beep_volume);
+		rc = IOCTL_OUT(arg, beep_vol);
+		break;
 	case SOUND_MIXER_WRITE_LINE:
 		IOCTL_IN(arg, data);
-		awacs_reg[0] &= ~MASK_MUX_AUDIN;
-		if ((data & 0xff) >= 50)
-			awacs_reg[0] |= MASK_MUX_AUDIN;
-		awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
+		do_line_lev(data) ;
+		/* fall through */
 	case SOUND_MIXER_READ_LINE:
-		data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, line_lev);
+		break;
+	case SOUND_MIXER_WRITE_IGAIN:
+		IOCTL_IN(arg, data);
+		do_ip_gain(data) ;
+		/* fall through */
+	case SOUND_MIXER_READ_IGAIN:
+		rc = IOCTL_OUT(arg, ip_gain);
+		break;
 	case SOUND_MIXER_WRITE_MIC:
 		IOCTL_IN(arg, data);
-		data &= 0xff;
-		awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
-		if (data >= 25) {
-			awacs_reg[0] |= MASK_MUX_MIC;
-			if (data >= 75)
-				awacs_reg[0] |= MASK_GAINLINE;
-		}
-		awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
+		do_mic_lev(data);
+		/* fall through */
 	case SOUND_MIXER_READ_MIC:
-		data = (awacs_reg[0] & MASK_MUX_MIC)?
-			(awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, mic_lev);
+		break;
 	case SOUND_MIXER_WRITE_CD:
 		IOCTL_IN(arg, data);
-		awacs_reg[0] &= ~MASK_MUX_CD;
-		if ((data & 0xff) >= 50)
-			awacs_reg[0] |= MASK_MUX_CD;
-		awacs_write(MASK_ADDR0 | awacs_reg[0]);
-				/* fall through */
+		do_cd_lev(data);
+		/* fall through */
 	case SOUND_MIXER_READ_CD:
-		data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, cd_lev);
+		break;
 	case SOUND_MIXER_WRITE_RECLEV:
 		IOCTL_IN(arg, data);
-		data = awacs_volume_setter(data, 0, 0, 4);
-		return IOCTL_OUT(arg, data);
+		do_rec_lev(data) ;
+		/* fall through */
 	case SOUND_MIXER_READ_RECLEV:
-		data = awacs_get_volume(awacs_reg[0], 4);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, rec_lev);
+		break;
 	case MIXER_WRITE(SOUND_MIXER_MONITOR):
 		IOCTL_IN(arg, data);
-		awacs_reg[1] &= ~MASK_LOOPTHRU;
-		if ((data & 0xff) >= 50)
-			awacs_reg[1] |= MASK_LOOPTHRU;
-		awacs_write(MASK_ADDR1 | awacs_reg[1]);
+		do_passthru_vol(data) ;
 		/* fall through */
 	case MIXER_READ(SOUND_MIXER_MONITOR):
-		data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, passthru_vol);
+		break;
+	default:
+		rc = -EINVAL;
 	}
-	return -EINVAL;
+	
+	return rc;
+}
+
+static void awacs_mixer_init(void)
+{
+	awacs_volume_setter(line_vol, 2, 0, 6);
+	if (has_perch)
+		awacs_enable_amp(spk_vol);
+	else
+		(void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6);
+	do_line_lev(line_lev) ;
+	do_ip_gain(ip_gain) ;
+	do_mic_lev(mic_lev) ;
+	do_cd_lev(cd_lev) ;
+	do_rec_lev(rec_lev) ;
+	do_passthru_vol(passthru_vol) ;
 }
 
 static int burgundy_mixer_ioctl(u_int cmd, u_long arg)
 {
 	int data;
+	int rc;
 
 	/* We are, we are, we are... Burgundy or better */
 	switch(cmd) {
@@ -1742,11 +1873,13 @@
 		data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
 			SOUND_MASK_LINE | SOUND_MASK_MIC |
 			SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_RECMASK:
 		data = SOUND_MASK_LINE | SOUND_MASK_MIC
 			| SOUND_MASK_CD;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_RECSRC:
 		data = 0;
 		if (awacs_reg[0] & MASK_MUX_AUDIN)
@@ -1755,7 +1888,8 @@
 			data |= SOUND_MASK_MIC;
 		if (awacs_reg[0] & MASK_MUX_CD)
 			data |= SOUND_MASK_CD;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_RECSRC:
 		IOCTL_IN(arg, data);
 		data &= (SOUND_MASK_LINE
@@ -1769,23 +1903,26 @@
 		if (data & SOUND_MASK_CD)
 			awacs_reg[0] |= MASK_MUX_CD;
 		awacs_write(awacs_reg[0] | MASK_ADDR0);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_STEREODEVS:
 		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
 			| SOUND_MASK_RECLEV | SOUND_MASK_CD
 			| SOUND_MASK_LINE;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_CAPS:
-		return IOCTL_OUT(arg, 0);
+		rc = IOCTL_OUT(arg, 0);
+		break;
 	case SOUND_MIXER_WRITE_VOLUME:
 		IOCTL_IN(arg, data);
 		awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
 				/* Fall through */
 	case SOUND_MIXER_READ_VOLUME:
-		return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
+		rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
+		break;
 	case SOUND_MIXER_WRITE_SPEAKER:
 		IOCTL_IN(arg, data);
-
 		if (!(data & 0xff)) {
 			/* Mute the left speaker */
 			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
@@ -1806,7 +1943,7 @@
 		}
 
 		data = (((data&0xff)*16)/100 > 0xf ? 0xf :
-			(((data&0xff)*16)/100)) + 
+			(((data&0xff)*16)/100)) +
 			((((data>>8)*16)/100 > 0xf ? 0xf :
 			  ((((data>>8)*16)/100)))<<4);
 
@@ -1815,21 +1952,24 @@
 	case SOUND_MIXER_READ_SPEAKER:
 		data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
 		data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
-		return IOCTL_OUT(arg, ~data);
+		rc = IOCTL_OUT(arg, ~data);
+		break;
 	case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
 		IOCTL_IN(arg, data);
-		beep_volume = data & 0xff;
+		beep_vol = data & 0xff;
 				/* fall through */
 	case SOUND_MIXER_READ_ALTPCM:
-		return IOCTL_OUT(arg, beep_volume);
+		rc = IOCTL_OUT(arg, beep_vol);
+		break;
 	case SOUND_MIXER_WRITE_LINE:
 		IOCTL_IN(arg, data);
 		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
 
 				/* fall through */
 	case SOUND_MIXER_READ_LINE:
-		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);				
-		return IOCTL_OUT(arg, data);
+		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_MIC:
 		IOCTL_IN(arg, data);
 				/* Mic is mono device */
@@ -1837,66 +1977,331 @@
 		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
 				/* fall through */
 	case SOUND_MIXER_READ_MIC:
-		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);				
+		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
 		data <<= 24;
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_CD:
 		IOCTL_IN(arg, data);
 		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
 				/* fall through */
 	case SOUND_MIXER_READ_CD:
 		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_WRITE_RECLEV:
 		IOCTL_IN(arg, data);
 		data = awacs_volume_setter(data, 0, 0, 4);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_READ_RECLEV:
 		data = awacs_get_volume(awacs_reg[0], 4);
-		return IOCTL_OUT(arg, data);
+		rc = IOCTL_OUT(arg, data);
+		break;
 	case SOUND_MIXER_OUTMASK:
+	case SOUND_MIXER_OUTSRC:
+	default:
+		rc = -EINVAL;
+	}
+	
+	return rc;
+}
+
+static int tumbler_mixer_ioctl(u_int cmd, u_long arg)
+{
+	int data;
+	int rc;
+
+	/* We are, we are, we are... Tumbler (and very dumb) */
+	/* Ok, we're not THAT dumb anymore, but still pretty dumb :-) */
+
+	switch(cmd) {
+	case SOUND_MIXER_READ_DEVMASK:
+		data =  SOUND_MASK_VOLUME | SOUND_MASK_ALTPCM |
+			SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+			SOUND_MASK_PCM;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_RECMASK:
+		data = 0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_RECSRC:
+		data = 0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_RECSRC:
+		IOCTL_IN(arg, data);
+		data =0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_STEREODEVS:
+		data = SOUND_MASK_VOLUME | SOUND_MASK_PCM;
+		rc = IOCTL_OUT(arg, data);
 		break;
+	case SOUND_MIXER_READ_CAPS:
+		rc = IOCTL_OUT(arg, 0);
+		break;
+	case SOUND_MIXER_WRITE_BASS:
+		IOCTL_IN(arg, data);
+		tumbler_set_bass(data);
+		/* Fall through */
+	case SOUND_MIXER_READ_BASS:
+		tumbler_get_bass(&data);
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_TREBLE:
+		IOCTL_IN(arg, data);
+		tumbler_set_treble(data);
+		/* Fall through */
+	case SOUND_MIXER_READ_TREBLE:
+		tumbler_get_treble(&data);
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_PCM:
+		IOCTL_IN(arg, data);
+		tumbler_set_pcm_lvl(data);
+		/* Fall through */
+	case SOUND_MIXER_READ_PCM:
+		tumbler_get_pcm_lvl(&data);
+		IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_VOLUME:
+		IOCTL_IN(arg, data);
+		tumbler_set_volume(data, data);
+		/* Fall through */
+	case SOUND_MIXER_READ_VOLUME:
+		tumbler_get_volume(& data, &data);
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
+		IOCTL_IN(arg, data);
+		beep_vol = data & 0xff;
+		/* fall through */
+	case SOUND_MIXER_READ_ALTPCM:
+		rc = IOCTL_OUT(arg, beep_vol);
+		break;
+	case SOUND_MIXER_OUTMASK:
 	case SOUND_MIXER_OUTSRC:
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int daca_mixer_ioctl(u_int cmd, u_long arg)
+{
+	int data;
+	int rc;
+
+	/* And the DACA's no genius either! */
+
+	switch(cmd) {
+	case SOUND_MIXER_READ_DEVMASK:
+		data = SOUND_MASK_VOLUME;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_RECMASK:
+		data = 0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_RECSRC:
+		data = 0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_WRITE_RECSRC:
+		IOCTL_IN(arg, data);
+		data =0;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_STEREODEVS:
+		data = SOUND_MASK_VOLUME;
+		rc = IOCTL_OUT(arg, data);
+		break;
+	case SOUND_MIXER_READ_CAPS:
+		rc = IOCTL_OUT(arg, 0);
+		break;
+	case SOUND_MIXER_WRITE_VOLUME:
+		IOCTL_IN(arg, data);
+		daca_set_volume(data, data);
+		/* Fall through */
+	case SOUND_MIXER_READ_VOLUME:
+		daca_get_volume(& data, &data);
+		rc = IOCTL_OUT(arg, data);
 		break;
+	case SOUND_MIXER_OUTMASK:
+	case SOUND_MIXER_OUTSRC:
+	default:
+		rc = -EINVAL;
 	}
-	return -EINVAL;
+	return rc;
 }
 
 static int PMacMixerIoctl(u_int cmd, u_long arg)
 {
-	/* Different IOCTLS for burgundy*/
-	if (awacs_revision >= AWACS_BURGUNDY)
-		return burgundy_mixer_ioctl(cmd, arg);
-	return awacs_mixer_ioctl(cmd, arg);
+	int rc;
+	
+	/* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */
+
+	TRY_LOCK();
+	
+	switch (awacs_revision){
+		case AWACS_BURGUNDY:
+			rc = burgundy_mixer_ioctl(cmd, arg);
+			break ;
+		case AWACS_DACA:
+			rc = daca_mixer_ioctl(cmd, arg);
+			break;
+		case AWACS_TUMBLER:
+			rc = tumbler_mixer_ioctl(cmd, arg);
+			break ;
+		default: /* ;-)) */
+			rc = awacs_mixer_ioctl(cmd, arg);
+	}
+
+	UNLOCK();
+	
+	return rc;
+}
+
+static void PMacMixerInit(void)
+{
+	switch (awacs_revision) {
+		case AWACS_TUMBLER:
+		  printk("AE-Init tumbler mixer\n");
+		  break ;
+		  
+		case AWACS_DACA:
+		case AWACS_BURGUNDY:
+			break ;	/* don't know yet */
+		case AWACS_AWACS:
+		case AWACS_SCREAMER:
+		default:
+			awacs_mixer_init() ;
+			break ;
+	}
 }
 
+/* Write/Read sq setup functions:
+   Check to see if we have enough (or any) dbdma cmd buffers for the
+   user's fragment settings.  If not, allocate some. If this fails we will
+   point at the beep buffer - as an emergency provision - to stop dma tromping
+   on some random bit of memory (if someone lets it go anyway).
+   The command buffers are then set up to point to the fragment buffers
+   (allocated elsewhere).  We need n+1 commands the last of which holds
+   a NOP + loop to start.
+*/
 
-static void PMacWriteSqSetup(void)
+static int PMacWriteSqSetup(void)
 {
-	int i;
+	int i, count = 600 ;
 	volatile struct dbdma_cmd *cp;
 
+	LOCK();
+	
+	/* stop the controller from doing any output - if it isn't already.
+	   it _should_ be before this is called anyway */
+
+	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	while ((in_le32(&awacs_txdma->status) & RUN) && count--)
+		udelay(1);
+#ifdef DEBUG_DMASOUND
+if (count <= 0)
+	printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n");
+#endif
+
+	if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) {
+		if (awacs_tx_cmd_space)
+			kfree(awacs_tx_cmd_space);
+		number_of_tx_cmd_buffers = 0;
+
+		/* we need nbufs + 1 (for the loop) and we should request + 1
+		   again because the DBDMA_ALIGN might pull the start up by up
+		   to sizeof(struct dbdma_cmd) - 4.
+		*/
+
+		awacs_tx_cmd_space = kmalloc
+			((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd),
+			 GFP_KERNEL);
+		if (awacs_tx_cmd_space == NULL) {
+			/* don't leave it dangling - nasty but better than a
+			   random address */
+			out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+			printk(KERN_ERR
+			   "dmasound_pmac: can't allocate dbdma cmd buffers"
+			   ", driver disabled\n");
+			UNLOCK();
+			return -ENOMEM;
+		}
+		awacs_tx_cmds = (volatile struct dbdma_cmd *)
+			DBDMA_ALIGN(awacs_tx_cmd_space);
+		number_of_tx_cmd_buffers = write_sq.max_count + 1;
+	}
+
 	cp = awacs_tx_cmds;
-	memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd));
-	for (i = 0; i < write_sq.numBufs; ++i, ++cp) {
+	memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd));
+	for (i = 0; i < write_sq.max_count; ++i, ++cp) {
 		st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));
 	}
 	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
 	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
-	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	/* point the controller at the command stack - ready to go */
 	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+	UNLOCK();
+	return 0;
 }
 
-static void PMacReadSqSetup(void)
+static int PMacReadSqSetup(void)
 {
-	int i;
+	int i, count = 600;
 	volatile struct dbdma_cmd *cp;
 
+	LOCK();
+	
+	/* stop the controller from doing any input - if it isn't already.
+	   it _should_ be before this is called anyway */
+	
+	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	while ((in_le32(&awacs_rxdma->status) & RUN) && count--)
+		udelay(1);
+#ifdef DEBUG_DMASOUND
+if (count <= 0)
+	printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n");
+#endif
+
+	if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) {
+		if (awacs_rx_cmd_space)
+			kfree(awacs_rx_cmd_space);
+		number_of_rx_cmd_buffers = 0;
+
+		/* we need nbufs + 1 (for the loop) and we should request + 1 again
+		   because the DBDMA_ALIGN might pull the start up by up to
+		   sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits).
+		*/
+
+		awacs_rx_cmd_space = kmalloc
+			((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd),
+			 GFP_KERNEL);
+		if (awacs_rx_cmd_space == NULL) {
+			/* don't leave it dangling - nasty but better than a
+			   random address */
+			out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+			printk(KERN_ERR
+			   "dmasound_pmac: can't allocate dbdma cmd buffers"
+			   ", driver disabled\n");
+			UNLOCK();
+			return -ENOMEM;
+		}
+		awacs_rx_cmds = (volatile struct dbdma_cmd *)
+			DBDMA_ALIGN(awacs_rx_cmd_space);
+		number_of_rx_cmd_buffers = read_sq.max_count + 1 ;
+	}
 	cp = awacs_rx_cmds;
-	memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+	memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd));
 
 	/* Set dma buffers up in a loop */
-	for (i = 0; i < read_sq.numBufs; i++,cp++) {
+	for (i = 0; i < read_sq.max_count; i++,cp++) {
 		st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));
 		st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
 		st_le16(&cp->req_count, read_sq.block_size);
@@ -1907,37 +2312,105 @@
 	*/
 	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
 	st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
-
-	/* Don't start until the first read is done.
-	 * This will also abort any operations in progress if the DMA
-	 * happens to be running (and it shouldn't).
-	 */
-	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	/* point the controller at the command stack - ready to go */
 	out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
 
+	UNLOCK();
+	return 0;
 }
 
+/* TODO: this needs work to guarantee that when it returns DMA has stopped
+   but in a more elegant way than is done here....
+*/
+
 static void PMacAbortRead(void)
 {
 	int i;
 	volatile struct dbdma_cmd *cp;
 
+	LOCK();
+	/* give it a chance to update the output and provide the IRQ
+	   that is expected.
+	*/
+
+	out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH );
+
 	cp = awacs_rx_cmds;
-	for (i = 0; i < read_sq.numBufs; i++,cp++)
+	for (i = 0; i < read_sq.max_count; i++,cp++)
 		st_le16(&cp->command, DBDMA_STOP);
 	/*
 	 * We should probably wait for the thing to stop before we
-	 * release the memory
+	 * release the memory.
 	 */
+
+	wait_ms(100) ; /* give it a (small) chance to act */
+
+	/* apply the sledgehammer approach - just stop it now */
+
+	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	UNLOCK();
 }
 
+extern char *get_afmt_string(int);
+static int PMacStateInfo(char *b, size_t sp)
+{
+	int i, len = 0;
+	len = sprintf(b,"HW rates: ");
+	switch (awacs_revision){
+		case AWACS_DACA:
+		case AWACS_BURGUNDY:
+			len += sprintf(b,"44100 ") ;
+			break ;
+		case AWACS_TUMBLER:
+			for (i=0; i<2; i++){
+				if (tumbler_freqs_ok[i])
+					len += sprintf(b+len,"%d ", tumbler_freqs[i]) ;
+			}
+			break ;
+
+		case AWACS_AWACS:
+		case AWACS_SCREAMER:
+		default:
+			for (i=0; i<8; i++){
+				if (awacs_freqs_ok[i])
+					len += sprintf(b+len,"%d ", awacs_freqs[i]) ;
+			}
+			break ;
+	}
+	len += sprintf(b+len,"s/sec\n") ;
+	if (len < sp) {
+		len += sprintf(b+len,"HW AFMTS: ");
+		i = AFMT_U16_BE ;
+		while (i) {
+			if (i & dmasound.mach.hardware_afmts)
+				len += sprintf(b+len,"%s ",
+					get_afmt_string(i & dmasound.mach.hardware_afmts));
+			i >>= 1 ;
+		}
+		len += sprintf(b+len,"\n") ;
+	}
+	return len ;
+}
 
 /*** Machine definitions *****************************************************/
 
+static SETTINGS def_hard = {
+	format: AFMT_S16_BE,
+	stereo: 1,
+	size: 16,
+	speed: 44100
+} ;
+
+static SETTINGS def_soft = {
+	format: AFMT_S16_BE,
+	stereo: 1,
+	size: 16,
+	speed: 44100
+} ;
 
 static MACHINE machPMac = {
 	name:		awacs_name,
-	name2:		"AWACS",
+	name2:		"PowerMac Built-in Sound",
 	open:		PMacOpen,
 	release:	PMacRelease,
 	dma_alloc:	PMacAlloc,
@@ -1951,233 +2424,660 @@
 	setFormat:	PMacSetFormat,
 	setVolume:	PMacSetVolume,
 	play:		PMacPlay,
-	record:		PMacRecord,
+	record:		NULL,		/* default to no record */
+	mixer_init:	PMacMixerInit,
 	mixer_ioctl:	PMacMixerIoctl,
 	write_sq_setup:	PMacWriteSqSetup,
 	read_sq_setup:	PMacReadSqSetup,
+	state_info:	PMacStateInfo,
 	abort_read:	PMacAbortRead,
-	min_dsp_speed:	8000
+	min_dsp_speed:	7350,
+	max_dsp_speed:	44100,
+	version:	((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION)
 };
 
 
 /*** Config & Setup **********************************************************/
 
+/* Check for pmac models that we care about in terms of special actions.
+*/
 
-int __init dmasound_awacs_init(void)
+void __init
+set_model(void)
 {
-	struct device_node *np;
+	/* portables/lap-tops */
 
-	if (_machine != _MACH_Pmac)
-		return -ENODEV;
+	if (machine_is_compatible("AAPL,3400/2400") ||
+	    machine_is_compatible("AAPL,3500"))	{
+		is_pbook_3X00 = 1 ;
+	}
+	if (machine_is_compatible("PowerBook1,1")  || /* lombard */
+	    machine_is_compatible("AAPL,PowerBook1998")){ /* wallstreet */
+		is_pbook_g3 = 1 ;
+		return ;
+	}
+}
 
-	awacs_subframe = 0;
-	awacs_revision = 0;
-	np = find_devices("awacs");
-	if (np == 0) {
-		/*
-		 * powermac G3 models have a node called "davbus"
-		 * with a child called "sound".
-		 */
-		struct device_node *sound;
-		np = find_devices("davbus");
-		sound = find_devices("sound");
-		if (sound != 0 && sound->parent == np) {
-			unsigned int *prop, l, i;
-			prop = (unsigned int *)
-				get_property(sound, "sub-frame", 0);
-			if (prop != 0 && *prop >= 0 && *prop < 16)
-				awacs_subframe = *prop;
-			if (device_is_compatible(sound, "burgundy"))
-				awacs_revision = AWACS_BURGUNDY;
-			/* This should be verified on older screamers */
-			if (device_is_compatible(sound, "screamer"))
-				awacs_is_screamer = 1;
-			prop = (unsigned int *)get_property(sound, "device-id", 0);
-			if (prop != 0)
-				awacs_device_id = *prop;
-			awacs_has_iic = (find_devices("perch") != NULL);
-
-			/* look for a property saying what sample rates
-			   are available */
-			for (i = 0; i < 8; ++i)
-				awacs_freqs_ok[i] = 0;
-			prop = (unsigned int *) get_property
-				(sound, "sample-rates", &l);
-			if (prop == 0)
-				prop = (unsigned int *) get_property
-					(sound, "output-frame-rates", &l);
-			if (prop != 0) {
-				for (l /= sizeof(int); l > 0; --l) {
-					/* sometimes the rate is in the
-					   high-order 16 bits (?) */
-					unsigned int r = *prop++;
-					if (r >= 0x10000)
-						r >>= 16;
-					for (i = 0; i < 8; ++i) {
-						if (r == awacs_freqs[i]) {
-							awacs_freqs_ok[i] = 1;
-							break;
-						}
-					}
+/* Get the OF node that tells us about the registers, interrupts etc. to use
+   for sound IO.
+
+   On most machines the sound IO OF node is the 'davbus' node.  On newer pmacs
+   with DACA (& Tumbler) the node to use is i2s-a.  On much older machines i.e.
+   before 9500 there is no davbus node and we have to use the 'awacs' property.
+
+  In the latter case we signal this by setting the codec value - so that the
+  code that looks for chip properties knows how to go about it.
+*/
+
+static struct device_node
+__init *get_snd_io_node(void)
+{
+	struct device_node *np = NULL;
+
+	/* set up awacs_node for early OF which doesn't have a full set of
+	 * properties on davbus
+	*/
+
+	awacs_node = find_devices("awacs");
+	if (awacs_node)
+		awacs_revision = AWACS_AWACS;
+
+	/* powermac models after 9500 (other than those which use DACA or
+	 * Tumbler) have a node called "davbus".
+	 */
+	np = find_devices("davbus");
+	/*
+	 * if we didn't find a davbus device, try 'i2s-a' since
+	 * this seems to be what iBooks (& Tumbler) have.
+	 */
+	if (np == NULL)
+		np = find_devices("i2s-a");
+
+	/* if we didn't find this - perhaps we are on an early model
+	 * which _only_ has an 'awacs' node
+	*/
+	if (np == NULL && awacs_node)
+		np = awacs_node ;
+
+	/* if we failed all these return null - this will cause the
+	 * driver to give up...
+	*/
+	return np ;
+}
+
+/* Get the OF node that contains the info about the sound chip, inputs s-rates
+   etc.
+   This node does not exist (or contains much reduced info) on earlier machines
+   we have to deduce the info other ways for these.
+*/
+
+static struct device_node
+__init *get_snd_info_node(struct device_node *io)
+{
+	struct device_node *info;
+
+	info = find_devices("sound");
+	while (info != 0 && info->parent != io)
+		info = info->next;
+
+	return info ;
+}
+
+/* Find out what type of codec we have.
+*/
+
+static int
+__init get_codec_type(struct device_node *info)
+{
+	/* already set if pre-davbus model and info will be NULL */
+	int codec = awacs_revision ;
+
+	if (info) {
+		/* must do awacs first to allow screamer to overide it */
+		if (device_is_compatible(info, "awacs"))
+			codec = AWACS_AWACS ;
+		if (device_is_compatible(info, "screamer"))
+			codec = AWACS_SCREAMER;
+		if (device_is_compatible(info, "burgundy"))
+			codec = AWACS_BURGUNDY ;
+		if (device_is_compatible(info, "daca"))
+			codec = AWACS_DACA;
+		if (device_is_compatible(info, "tumbler"))
+			codec = AWACS_TUMBLER;
+	}
+	return codec ;
+}
+
+/* find out what type, if any, of expansion card we have
+*/
+static void
+__init get_expansion_type(void)
+{
+	if (find_devices("perch") != NULL)
+		has_perch = 1;
+
+	if (find_devices("pb-ziva-pc") != NULL)
+		has_ziva = 1;
+	/* need to work out how we deal with iMac SRS module */
+}
+
+/* set up frame rates.
+ * I suspect that these routines don't quite go about it the right way:
+ * - where there is more than one rate - I think that the first property
+ * value is the number of rates.
+ * TODO: check some more device trees and modify accordingly
+ *       Set dmasound.mach.max_dsp_rate on the basis of these routines.
+*/
+
+static void
+__init init_awacs_frame_rates(unsigned int *prop, unsigned int l)
+{
+	int i ;
+	if (prop) {
+		for (i=0; i<8; i++)
+			awacs_freqs_ok[i] = 0 ;
+		for (l /= sizeof(int); l > 0; --l) {
+			unsigned int r = *prop++;
+			/* Apple 'Fixed' format */
+			if (r >= 0x10000)
+				r >>= 16;
+			for (i = 0; i < 8; ++i) {
+				if (r == awacs_freqs[i]) {
+					awacs_freqs_ok[i] = 1;
+					break;
 				}
-			} else {
-				/* assume just 44.1k is OK */
-				awacs_freqs_ok[0] = 1;
 			}
 		}
 	}
-	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
-		int vol;
-		dmasound.mach = machPMac;
-
-		awacs = (volatile struct awacs_regs *)
-			ioremap(np->addrs[0].address, 0x80);
-		awacs_txdma = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[1].address, 0x100);
-		awacs_rxdma = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[2].address, 0x100);
-
-		awacs_irq = np->intrs[0].line;
-		awacs_tx_irq = np->intrs[1].line;
-		awacs_rx_irq = np->intrs[2].line;
+	/* else we assume that all the rates are available */
+}
 
-		awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
-					     GFP_KERNEL);
-		if (awacs_tx_cmd_space == NULL) {
-			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
-			return -ENOMEM;
+static void
+__init init_tumbler_frame_rates(unsigned int *prop, unsigned int l)
+{
+	int i ;
+	if (prop) {
+		for (i=0; i<2; i++)
+			tumbler_freqs_ok[i] = 0;
+		for (l /= sizeof(int); l > 0; --l) {
+			unsigned int r = *prop++;
+			/* Apple 'Fixed' format */
+			if (r >= 0x10000)
+				r >>= 16;
+			for (i = 0; i < 2; ++i) {
+				if (r == tumbler_freqs[i]) {
+					tumbler_freqs_ok[i] = 1;
+					break;
+				}
+			}
 		}
-		awacs_node = np;
-#ifdef CONFIG_PMAC_PBOOK
-		if (machine_is_compatible("PowerBook1,1")
-		    || machine_is_compatible("AAPL,PowerBook1998")) {
-			pmu_suspend();
-			feature_set(np, FEATURE_Sound_CLK_enable);
-			feature_set(np, FEATURE_Sound_power);
-			/* Shorter delay will not work */
-			mdelay(1000);
-			pmu_resume();
+	}
+	/* else we assume that all the rates are available */
+}
+
+static void
+__init init_burgundy_frame_rates(unsigned int *prop, unsigned int l)
+{
+	int temp[9] ;
+	int i = 0 ;
+	if (prop) {
+		for (l /= sizeof(int); l > 0; --l) {
+			unsigned int r = *prop++;
+			/* Apple 'Fixed' format */
+			if (r >= 0x10000)
+				r >>= 16;
+			temp[i] = r ;
+			i++ ; if(i>=9) i=8;
+		}
+	}
+#ifdef DEBUG_DMASOUND
+if (i > 1){
+	int j;
+	printk("dmasound_pmac: burgundy with multiple frame rates\n");
+	for(j=0; j<i; j++)
+		printk("%d ", temp[j]) ;
+	printk("\n") ;
+}
+#endif
+}
+
+static void
+__init init_daca_frame_rates(unsigned int *prop, unsigned int l)
+{
+	int temp[9] ;
+	int i = 0 ;
+	if (prop) {
+		for (l /= sizeof(int); l > 0; --l) {
+			unsigned int r = *prop++;
+			/* Apple 'Fixed' format */
+			if (r >= 0x10000)
+				r >>= 16;
+			temp[i] = r ;
+			i++ ; if(i>=9) i=8;
+
 		}
+	}
+#ifdef DEBUG_DMASOUND
+if (i > 1){
+	int j;
+	printk("dmasound_pmac: DACA with multiple frame rates\n");
+	for(j=0; j<i; j++)
+		printk("%d ", temp[j]) ;
+	printk("\n") ;
+}
 #endif
-		awacs_tx_cmds = (volatile struct dbdma_cmd *)
-			DBDMA_ALIGN(awacs_tx_cmd_space);
+}
 
+static void
+__init init_frame_rates(unsigned int *prop, unsigned int l)
+{
+	switch (awacs_revision){
+		case AWACS_TUMBLER:
+			init_tumbler_frame_rates(prop, l);
+			break ;
+		case AWACS_DACA:
+			init_daca_frame_rates(prop, l);
+			break ;
+		case AWACS_BURGUNDY:
+			init_burgundy_frame_rates(prop, l);
+			break ;
+		default: /* ;-))) */
+			init_awacs_frame_rates(prop, l);
+			break ;
+	}
+}
 
-		awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
-					     GFP_KERNEL);
-		if (awacs_rx_cmd_space == NULL) {
-		  printk("DMA sound driver: No memory for input");
+/* find things/machines that can't do mac-io byteswap
+*/
+
+static void
+__init set_hw_byteswap(struct device_node *io)
+{
+	struct device_node *mio ;
+	unsigned int *p, kl = 0 ;
+
+	/* if seems that Keylargo can't byte-swap  */
+
+	for (mio = io->parent; mio ; mio = mio->parent) {
+		if (strcmp(mio->name, "mac-io") == 0) {
+			if (device_is_compatible(mio, "Keylargo"))
+				kl = 1;
+			break;
 		}
-		awacs_rx_cmds = (volatile struct dbdma_cmd *)
-		  DBDMA_ALIGN(awacs_rx_cmd_space);
+	}
+	hw_can_byteswap = !kl;
+}
 
+/* Allocate the resources necessary for beep generation.  This cannot be (quite)
+   done statically (yet) because we cannot do virt_to_bus() on static vars when
+   the code is loaded as a module.
 
+   for the sake of saving the possibility that two allocations will incur the
+   overhead of two pull-ups in DBDMA_ALIGN() we allocate the 'emergency' dmdma
+   command here as well... even tho' it is not part of the beep process.
+*/
 
-		awacs_reg[0] = MASK_MUX_CD;
-		/* FIXME: Only machines with external SRS module need MASK_PAROUT */
-		awacs_reg[1] = MASK_LOOPTHRU;
-		if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8
-			|| */awacs_device_id == 0xb)
-			awacs_reg[1] |= MASK_PAROUT;
-		/* get default volume from nvram */
-		vol = (~nvram_read_byte(0x1308) & 7) << 1;
-		awacs_reg[2] = vol + (vol << 6);
-		awacs_reg[4] = vol + (vol << 6);
-		awacs_reg[5] = 0;
-		awacs_reg[6] = 0;
-		awacs_reg[7] = 0;
-		out_le32(&awacs->control, 0x11);
-		awacs_write(awacs_reg[0] + MASK_ADDR0);
-		awacs_write(awacs_reg[1] + MASK_ADDR1);
-		awacs_write(awacs_reg[2] + MASK_ADDR2);
-		awacs_write(awacs_reg[4] + MASK_ADDR4);
-		if (awacs_is_screamer) {
-			awacs_write(awacs_reg[5] + MASK_ADDR5);
-			awacs_write(awacs_reg[6] + MASK_ADDR6);
-			awacs_write(awacs_reg[7] + MASK_ADDR7);
-		}
-
-		/* Initialize recent versions of the awacs */
-		if (awacs_revision == 0) {
-			awacs_revision =
-				(in_le32(&awacs->codec_stat) >> 12) & 0xf;
-			if (awacs_revision == 3) {
-				mdelay(100);
-				awacs_write(0x6000);
-				mdelay(2);
-				awacs_write(awacs_reg[1] + MASK_ADDR1);
-				awacs_enable_amp(100 * 0x101);
+int32_t
+__init setup_beep(void)
+{
+	/* Initialize beep stuff */
+	/* want one cmd buffer for beeps, and a second one for emergencies
+	   - i.e. dbdma error conditions.
+	   ask for three to allow for pull up in DBDMA_ALIGN().
+	*/
+	beep_dbdma_cmd_space =
+		kmalloc((2 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL);
+	if(beep_dbdma_cmd_space == NULL) {
+		printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ;
+		return -ENOMEM ;
+	}
+	beep_dbdma_cmd = (volatile struct dbdma_cmd *)
+			DBDMA_ALIGN(beep_dbdma_cmd_space);
+	/* set up emergency dbdma cmd */
+	emergency_dbdma_cmd = beep_dbdma_cmd+1 ;
+	beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+	if (beep_buf == NULL) {
+		printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n");
+		if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ;
+		return -ENOMEM ;
+	}
+	/* OK, we should be safe to claim the mksound vector now */
+	orig_mksound = kd_mksound;
+	kd_mksound = awacs_mksound;
+	return 0 ;
+}
+
+int __init dmasound_awacs_init(void)
+{
+	struct device_node *io = NULL, *info = NULL;
+	int vol, res;
+
+	if (_machine != _MACH_Pmac)
+		return -ENODEV;
+
+	awacs_subframe = 0;
+	awacs_revision = 0;
+	hw_can_byteswap = 1 ; /* most can */
+
+	/* look for models we need to handle specially */
+	set_model() ;
+
+	/* find the OF node that tells us about the dbdma stuff
+	*/
+	io = get_snd_io_node();
+	if (io == NULL) {
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: couldn't find sound io OF node\n");
+#endif
+		return -ENODEV ;
+	}
+
+	/* find the OF node that tells us about the sound sub-system
+	 * this doesn't exist on pre-davbus machines (earlier than 9500)
+	*/
+	if (awacs_revision != AWACS_AWACS) { /* set for pre-davbus */
+		info = get_snd_info_node(io) ;
+		if (info == NULL){
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: couldn't find 'sound' OF node\n");
+#endif
+			return -ENODEV ;
+		}
+	}
+
+	awacs_revision = get_codec_type(info) ;
+	if (awacs_revision == 0) {
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: couldn't find a Codec we can handle\n");
+#endif
+		return -ENODEV ; /* we don't know this type of h/w */
+	}
+
+	/* set up perch, ziva, SRS or whatever else we have as sound
+	 *  expansion.
+	*/
+	get_expansion_type();
+
+	/* we've now got enough information to make up the audio topology.
+	 * we will map the sound part of mac-io now so that we can probe for
+	 * other info if necessary (early AWACS we want to read chip ids)
+	 */
+
+	if (io->n_addrs < 3 || io->n_intrs < 3) {
+		/* OK - maybe we need to use the 'awacs' node (on earlier
+		 * machines).
+		*/
+		if (awacs_node) {
+			io = awacs_node ;
+			if (io->n_addrs < 3 || io->n_intrs < 3) {
+				printk("dmasound_pmac: can't use %s"
+					" (%d addrs, %d intrs)\n",
+		      		 io->full_name, io->n_addrs, io->n_intrs);
+				return -ENODEV;
 			}
+		} else {
+			printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n",
+		 	      io->full_name, io->n_addrs, io->n_intrs);
 		}
-		if (awacs_revision >= AWACS_BURGUNDY)
+	}
+
+	if (!request_OF_resource(io, 0, NULL)) {
+		printk(KERN_ERR "dmasound: can't request IO resource !\n");
+		return -ENODEV;
+	}
+	if (!request_OF_resource(io, 1, " (tx dma)")) {
+		release_OF_resource(io, 0);
+		printk(KERN_ERR "dmasound: can't request TX DMA resource !\n");
+		return -ENODEV;
+	}
+
+	if (!request_OF_resource(io, 2, " (rx dma)")) {
+		release_OF_resource(io, 0);
+		release_OF_resource(io, 1);
+		printk(KERN_ERR "dmasound: can't request RX DMA resource !\n");
+		return -ENODEV;
+	}
+
+	/* all OF versions I've seen use this value */
+	awacs = (volatile struct awacs_regs *)
+		ioremap(io->addrs[0].address, 0x1000);
+	awacs_txdma = (volatile struct dbdma_regs *)
+		ioremap(io->addrs[1].address, 0x100);
+	awacs_rxdma = (volatile struct dbdma_regs *)
+		ioremap(io->addrs[2].address, 0x100);
+
+#ifdef CONFIG_PMAC_PBOOK
+	/* first of all make sure that the chip is powered up....*/
+	pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1);
+	if (awacs_revision == AWACS_SCREAMER)
+		awacs_recalibrate();
+#endif
+	awacs_irq = io->intrs[0].line;
+	awacs_tx_irq = io->intrs[1].line;
+	awacs_rx_irq = io->intrs[2].line;
+
+	awacs_node = io;
+
+	/* if we have an awacs or screamer - probe the chip to make
+	 * sure we have the right revision.
+	*/
+
+	if (awacs_revision <= AWACS_SCREAMER){
+		uint32_t temp, rev, mfg ;
+		/* find out the awacs revision from the chip */
+		temp = in_le32(&awacs->codec_stat);
+		rev = (temp >> 12) & 0xf;
+		mfg = (temp >>  8) & 0xf;
+#ifdef DEBUG_DMASOUND
+printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
+#endif
+		if (rev >= AWACS_SCREAMER)
+			awacs_revision = AWACS_SCREAMER ;
+		else
+			awacs_revision = rev ;
+	}
+
+	dmasound.mach = machPMac;
+
+	/* find out other bits & pieces from OF, these may be present
+	   only on some models ... so be careful.
+	*/
+
+	/* in the absence of a frame rates property we will use the defaults
+	*/
+
+	if (info) {
+		unsigned int *prop, l;
+
+		sound_device_id = 0;
+		/* device ID appears post g3 b&w */
+		prop = (unsigned int *)get_property(info, "device-id", 0);
+		if (prop != 0)
+			sound_device_id = *prop;
+
+		/* look for a property saying what sample rates
+		   are available */
+
+		prop = (unsigned int *)get_property(info, "sample-rates", &l);
+		if (prop == 0)
+			prop = (unsigned int *) get_property
+				(info, "output-frame-rates", &l);
+
+		/* if it's there use it to set up frame rates */
+		init_frame_rates(prop, l) ;
+	}
+	
+	out_le32(&awacs->control, 0x11); /* set everything quiesent */
+
+	set_hw_byteswap(io) ; /* figure out if the h/w can do it */
+
+	/* get default volume from nvram
+	 * vol = (~nvram_read_byte(0x1308) & 7) << 1;
+	*/
+	vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
+	/* set up tracking values */
+	spk_vol = vol * 100 ;
+	spk_vol /= 7 ; /* get set value to a percentage */
+	spk_vol |= (spk_vol << 8) ; /* equal left & right */
+ 	line_vol = passthru_vol = spk_vol ;
+
+	/* fill regs that are shared between AWACS & Burgundy */
+
+	awacs_reg[2] = vol + (vol << 6);
+	awacs_reg[4] = vol + (vol << 6);
+	awacs_reg[5] = vol + (vol << 6); /* screamer has loopthru vol control */
+	awacs_reg[6] = 0; /* maybe should be vol << 3 for PCMCIA speaker */
+	awacs_reg[7] = 0;
+
+	awacs_reg[0] = MASK_MUX_CD;
+	awacs_reg[1] = MASK_LOOPTHRU;
+
+	/* FIXME: Only machines with external SRS module need MASK_PAROUT */
+	if (has_perch || sound_device_id == 0x5
+	    || /*sound_device_id == 0x8 ||*/ sound_device_id == 0xb)
+		awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
+
+	switch (awacs_revision) {
+		case AWACS_TUMBLER:
+#ifdef CONFIG_KMOD
+			request_module("i2c-keywest");
+#endif /* CONFIG_KMOD */	
+			awacs_tumbler_init();
+			tas_init();
+			break ;
+		case AWACS_DACA:
+#ifdef CONFIG_KMOD
+			request_module("i2c-keywest");
+#endif /* CONFIG_KMOD */
+			daca_init();
+			break ;		/* dont know how yet */
+		case AWACS_BURGUNDY:
 			awacs_burgundy_init();
+			break ;
+		case AWACS_SCREAMER:
+		case AWACS_AWACS:
+		default:
+			load_awacs() ;
+			break ;
+	}
+
+	/* enable/set-up external modules - when we know how */
+
+	if (has_perch)
+		awacs_enable_amp(100 * 0x101);
+
+	/* Reset dbdma channels */
+	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
+	while (in_le32(&awacs_txdma->status) & RUN)
+		udelay(1);
+	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
+	while (in_le32(&awacs_rxdma->status) & RUN)
+		udelay(1);
+
+	/* Initialize beep stuff */
+	if ((res=setup_beep()))
+		return res ;
 
-		/* Initialize beep stuff */
-		beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1);
-		orig_mksound = kd_mksound;
-		kd_mksound = awacs_mksound;
-		beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
-		if (beep_buf == NULL)
-			printk(KERN_WARNING "dmasound: no memory for "
-			       "beep buffer\n");
 #ifdef CONFIG_PMAC_PBOOK
-		pmu_register_sleep_notifier(&awacs_sleep_notifier);
+	pmu_register_sleep_notifier(&awacs_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
-		/* Powerbooks have odd ways of enabling inputs such as
-		   an expansion-bay CD or sound from an internal modem
-		   or a PC-card modem. */
-		if (machine_is_compatible("AAPL,3400/2400")
-			|| machine_is_compatible("AAPL,3500")) {
-			is_pbook_3400 = 1;
-			/*
-			 * Enable CD and PC-card sound inputs.
-			 * This is done by reading from address
-			 * f301a000, + 0x10 to enable the expansion-bay
-			 * CD sound input, + 0x80 to enable the PC-card
-			 * sound input.  The 0x100 enables the SCSI bus
-			 * terminator power.
-			 */
-			latch_base = (unsigned char *) ioremap
-				(0xf301a000, 0x1000);
-			in_8(latch_base + 0x190);
-		} else if (machine_is_compatible("PowerBook1,1")
-			   || machine_is_compatible("AAPL,PowerBook1998")) {
-			struct device_node* mio;
-			macio_base = 0;
-			is_pbook_G3 = 1;
-			for (mio = np->parent; mio; mio = mio->parent) {
-				if (strcmp(mio->name, "mac-io") == 0
-				    && mio->n_addrs > 0) {
-					macio_base = (unsigned char *) ioremap
-						(mio->addrs[0].address, 0x40);
-					break;
-				}
+	/* Powerbooks have odd ways of enabling inputs such as
+	   an expansion-bay CD or sound from an internal modem
+	   or a PC-card modem. */
+	if (is_pbook_3X00) {
+		/*
+		 * Enable CD and PC-card sound inputs.
+		 * This is done by reading from address
+		 * f301a000, + 0x10 to enable the expansion-bay
+		 * CD sound input, + 0x80 to enable the PC-card
+		 * sound input.  The 0x100 enables the SCSI bus
+		 * terminator power.
+		 */
+		latch_base = (unsigned char *) ioremap (0xf301a000, 0x1000);
+		in_8(latch_base + 0x190);
+
+	} else if (is_pbook_g3) {
+		struct device_node* mio;
+		macio_base = 0;
+		for (mio = io->parent; mio; mio = mio->parent) {
+			if (strcmp(mio->name, "mac-io") == 0
+			    && mio->n_addrs > 0) {
+				macio_base = (unsigned char *) ioremap
+					(mio->addrs[0].address, 0x40);
+				break;
 			}
-			/*
-			 * Enable CD sound input.
-			 * The relevant bits for writing to this byte are 0x8f.
-			 * I haven't found out what the 0x80 bit does.
-			 * For the 0xf bits, writing 3 or 7 enables the CD
-			 * input, any other value disables it.  Values
-			 * 1, 3, 5, 7 enable the microphone.  Values 0, 2,
-			 * 4, 6, 8 - f enable the input from the modem.
-			 */
-			if (macio_base)
-				out_8(macio_base + 0x37, 3);
-		}
-		sprintf(awacs_name, "PowerMac (AWACS rev %d) ",
-			awacs_revision);
-		return dmasound_init();
+		}
+		/*
+		 * Enable CD sound input.
+		 * The relevant bits for writing to this byte are 0x8f.
+		 * I haven't found out what the 0x80 bit does.
+		 * For the 0xf bits, writing 3 or 7 enables the CD
+		 * input, any other value disables it.  Values
+		 * 1, 3, 5, 7 enable the microphone.  Values 0, 2,
+		 * 4, 6, 8 - f enable the input from the modem.
+		 *  -- paulus.
+		 */
+		if (macio_base)
+			out_8(macio_base + 0x37, 3);
 	}
-	return -ENODEV;
+
+	if (hw_can_byteswap)
+ 		dmasound.mach.hardware_afmts = (AFMT_S16_BE | AFMT_S16_LE) ;
+ 	else
+		dmasound.mach.hardware_afmts = AFMT_S16_BE ;
+
+	/* shut out chips that do output only.
+	   may need to extend this to machines which have no inputs - even tho'
+	   they use screamer - IIRC one of the powerbooks is like this.
+	*/
+
+	if (awacs_revision != AWACS_TUMBLER && awacs_revision != AWACS_DACA) {
+		dmasound.mach.capabilities = DSP_CAP_DUPLEX ;
+		dmasound.mach.record = PMacRecord ;
+	}
+
+	dmasound.mach.default_hard = def_hard ;
+	dmasound.mach.default_soft = def_soft ;
+
+	switch (awacs_revision) {
+		case AWACS_BURGUNDY:
+			sprintf(awacs_name, "PowerMac Burgundy ") ;
+			break ;
+		case AWACS_DACA:
+			sprintf(awacs_name, "PowerMac DACA ") ;
+			break ;
+		case AWACS_TUMBLER:
+			sprintf(awacs_name, "PowerMac Tumbler ") ;
+			break ;
+		case AWACS_SCREAMER:
+			sprintf(awacs_name, "PowerMac Screamer ") ;
+			break ;
+		case AWACS_AWACS:
+		default:
+			sprintf(awacs_name, "PowerMac AWACS rev %d ", awacs_revision) ;
+			break ;
+	}
+
+	return dmasound_init();
 }
 
 static void __exit dmasound_awacs_cleanup(void)
 {
+	switch (awacs_revision) {
+		case AWACS_TUMBLER:
+			awacs_tumbler_cleanup();
+			tas_cleanup();
+			break ;
+		case AWACS_DACA:
+			daca_cleanup();
+			break;
+	}
 	dmasound_deinit();
 }
 
+MODULE_DESCRIPTION("PowerMac built-in audio driver.");
+MODULE_LICENSE("GPL");
+
 module_init(dmasound_awacs_init);
 module_exit(dmasound_awacs_cleanup);
-MODULE_LICENSE("GPL");
diff -Nru a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
--- a/sound/oss/dmasound/dmasound_core.c	Thu May  9 15:21:03 2002
+++ b/sound/oss/dmasound/dmasound_core.c	Thu May  9 15:21:03 2002
@@ -1,4 +1,3 @@
-
 /*
  *  linux/drivers/sound/dmasound/dmasound_core.c
  *
@@ -103,38 +102,113 @@
  *	2000/3/25	Geert Uytterhoeven:
  *			  - Integration of dmasound_q40
  *			  - Small clean ups
+ *
+ *	2001/01/26 [1.0] Iain Sandoe
+ *			  - make /dev/sndstat show revision & edition info.
+ *			  - since dmasound.mach.sq_setup() can fail on pmac
+ *			    its type has been changed to int and the returns
+ *			    are checked.
+ *		   [1.1]  - stop missing translations from being called.
+ *	2001/02/08 [1.2]  - remove unused translation tables & move machine-
+ *			    specific tables to low-level.
+ *			  - return correct info. for SNDCTL_DSP_GETFMTS.
+ *		   [1.3]  - implement SNDCTL_DSP_GETCAPS fully.
+ *		   [1.4]  - make /dev/sndstat text length usage deterministic.
+ *			  - make /dev/sndstat call to low-level
+ *			    dmasound.mach.state_info() pass max space to ll driver.
+ *			  - tidy startup banners and output info.
+ *		   [1.5]  - tidy up a little (removed some unused #defines in
+ *			    dmasound.h)
+ *			  - fix up HAS_RECORD conditionalisation.
+ *			  - add record code in places it is missing...
+ *			  - change buf-sizes to bytes to allow < 1kb for pmac
+ *			    if user param entry is < 256 the value is taken to
+ *			    be in kb > 256 is taken to be in bytes.
+ *			  - make default buff/frag params conditional on
+ *			    machine to allow smaller values for pmac.
+ *			  - made the ioctls, read & write comply with the OSS
+ *			    rules on setting params.
+ *			  - added parsing of _setup() params for record.
+ *	2001/04/04 [1.6]  - fix bug where sample rates higher than maximum were
+ *			    being reported as OK.
+ *			  - fix open() to return -EBUSY as per OSS doc. when
+ *			    audio is in use - this is independent of O_NOBLOCK.
+ *			  - fix bug where SNDCTL_DSP_POST was blocking.
  */
 
+ /* Record capability notes 30/01/2001:
+  * At present these observations apply only to pmac LL driver (the only one
+  * that can do record, at present).  However, if other LL drivers for machines
+  * with record are added they may apply.
+  *
+  * The fragment parameters for the record and play channels are separate.
+  * However, if the driver is opened O_RDWR there is no way (in the current OSS
+  * API) to specify their values independently for the record and playback
+  * channels.  Since the only common factor between the input & output is the
+  * sample rate (on pmac) it should be possible to open /dev/dspX O_WRONLY and
+  * /dev/dspY O_RDONLY.  The input & output channels could then have different
+  * characteristics (other than the first that sets sample rate claiming the
+  * right to set it for ever).  As it stands, the format, channels, number of
+  * bits & sample rate are assumed to be common.  In the future perhaps these
+  * should be the responsibility of the LL driver - and then if a card really
+  * does not share items between record & playback they can be specified
+  * separately.
+*/
+
+/* Thread-safeness of shared_resources notes: 31/01/2001
+ * If the user opens O_RDWR and then splits record & play between two threads
+ * both of which inherit the fd - and then starts changing things from both
+ * - we will have difficulty telling.
+ *
+ * It's bad application coding - but ...
+ * TODO: think about how to sort this out... without bogging everything down in
+ * semaphores.
+ *
+ * Similarly, the OSS spec says "all changes to parameters must be between
+ * open() and the first read() or write(). - and a bit later on (by
+ * implication) "between SNDCTL_DSP_RESET and the first read() or write() after
+ * it".  If the app is multi-threaded and this rule is broken between threads
+ * we will have trouble spotting it - and the fault will be rather obscure :-(
+ *
+ * We will try and put out at least a kmsg if we see it happen... but I think
+ * it will be quite hard to trap it with an -EXXX return... because we can't
+ * see the fault until after the damage is done.
+*/
 
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/sound.h>
 #include <linux/init.h>
 #include <linux/soundcard.h>
+#include <linux/poll.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
 #include "dmasound.h"
 
+#define DMASOUND_CORE_REVISION 1
+#define DMASOUND_CORE_EDITION 6
 
     /*
      *  Declarations
      */
 
 int dmasound_catchRadius = 0;
-static unsigned int numWriteBufs = 4;
-static unsigned int writeBufSize = 32;	/* in KB! */
-#ifdef HAS_RECORD
-static unsigned int numReadBufs = 4;
-static unsigned int readBufSize = 32;	/* in KB! */
-#endif
-
 MODULE_PARM(dmasound_catchRadius, "i");
+
+static unsigned int numWriteBufs = DEFAULT_N_BUFFERS;
 MODULE_PARM(numWriteBufs, "i");
+static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ;	/* in bytes */
 MODULE_PARM(writeBufSize, "i");
+
+#ifdef HAS_RECORD
+static unsigned int numReadBufs = DEFAULT_N_BUFFERS;
 MODULE_PARM(numReadBufs, "i");
+static unsigned int readBufSize = DEFAULT_BUFF_SIZE;	/* in bytes */
 MODULE_PARM(readBufSize, "i");
+#endif
+
 MODULE_LICENSE("GPL");
 
 #ifdef MODULE
@@ -144,246 +218,9 @@
 static int irq_installed = 0;
 #endif /* MODULE */
 
-
-    /*
-     *  Conversion tables
-     */
-
-#ifdef HAS_8BIT_TABLES
-/* 8 bit mu-law */
-
-char dmasound_ulaw2dma8[] = {
-	-126,	-122,	-118,	-114,	-110,	-106,	-102,	-98,
-	-94,	-90,	-86,	-82,	-78,	-74,	-70,	-66,
-	-63,	-61,	-59,	-57,	-55,	-53,	-51,	-49,
-	-47,	-45,	-43,	-41,	-39,	-37,	-35,	-33,
-	-31,	-30,	-29,	-28,	-27,	-26,	-25,	-24,
-	-23,	-22,	-21,	-20,	-19,	-18,	-17,	-16,
-	-16,	-15,	-15,	-14,	-14,	-13,	-13,	-12,
-	-12,	-11,	-11,	-10,	-10,	-9,	-9,	-8,
-	-8,	-8,	-7,	-7,	-7,	-7,	-6,	-6,
-	-6,	-6,	-5,	-5,	-5,	-5,	-4,	-4,
-	-4,	-4,	-4,	-4,	-3,	-3,	-3,	-3,
-	-3,	-3,	-3,	-3,	-2,	-2,	-2,	-2,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	0,
-	125,	121,	117,	113,	109,	105,	101,	97,
-	93,	89,	85,	81,	77,	73,	69,	65,
-	62,	60,	58,	56,	54,	52,	50,	48,
-	46,	44,	42,	40,	38,	36,	34,	32,
-	30,	29,	28,	27,	26,	25,	24,	23,
-	22,	21,	20,	19,	18,	17,	16,	15,
-	15,	14,	14,	13,	13,	12,	12,	11,
-	11,	10,	10,	9,	9,	8,	8,	7,
-	7,	7,	6,	6,	6,	6,	5,	5,
-	5,	5,	4,	4,	4,	4,	3,	3,
-	3,	3,	3,	3,	2,	2,	2,	2,
-	2,	2,	2,	2,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0
-};
-
-/* 8 bit A-law */
-
-char dmasound_alaw2dma8[] = {
-	-22,	-21,	-24,	-23,	-18,	-17,	-20,	-19,
-	-30,	-29,	-32,	-31,	-26,	-25,	-28,	-27,
-	-11,	-11,	-12,	-12,	-9,	-9,	-10,	-10,
-	-15,	-15,	-16,	-16,	-13,	-13,	-14,	-14,
-	-86,	-82,	-94,	-90,	-70,	-66,	-78,	-74,
-	-118,	-114,	-126,	-122,	-102,	-98,	-110,	-106,
-	-43,	-41,	-47,	-45,	-35,	-33,	-39,	-37,
-	-59,	-57,	-63,	-61,	-51,	-49,	-55,	-53,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
-	-6,	-6,	-6,	-6,	-5,	-5,	-5,	-5,
-	-8,	-8,	-8,	-8,	-7,	-7,	-7,	-7,
-	-3,	-3,	-3,	-3,	-3,	-3,	-3,	-3,
-	-4,	-4,	-4,	-4,	-4,	-4,	-4,	-4,
-	21,	20,	23,	22,	17,	16,	19,	18,
-	29,	28,	31,	30,	25,	24,	27,	26,
-	10,	10,	11,	11,	8,	8,	9,	9,
-	14,	14,	15,	15,	12,	12,	13,	13,
-	86,	82,	94,	90,	70,	66,	78,	74,
-	118,	114,	126,	122,	102,	98,	110,	106,
-	43,	41,	47,	45,	35,	33,	39,	37,
-	59,	57,	63,	61,	51,	49,	55,	53,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	5,	5,	5,	5,	4,	4,	4,	4,
-	7,	7,	7,	7,	6,	6,	6,	6,
-	2,	2,	2,	2,	2,	2,	2,	2,
-	3,	3,	3,	3,	3,	3,	3,	3
-};
-#endif /* HAS_8BIT_TABLES */
-
-#ifdef HAS_16BIT_TABLES
-
-/* 16 bit mu-law */
-
-short dmasound_ulaw2dma16[] = {
-	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
-	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
-	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
-	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
-	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
-	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
-	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
-	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
-	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
-	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
-	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
-	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
-	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
-	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
-	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
-	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
-	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
-	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
-	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
-	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
-	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
-	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
-	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
-	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
-	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
-	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
-	876,	844,	812,	780,	748,	716,	684,	652,
-	620,	588,	556,	524,	492,	460,	428,	396,
-	372,	356,	340,	324,	308,	292,	276,	260,
-	244,	228,	212,	196,	180,	164,	148,	132,
-	120,	112,	104,	96,	88,	80,	72,	64,
-	56,	48,	40,	32,	24,	16,	8,	0,
-};
-
-/* 16 bit A-law */
-
-short dmasound_alaw2dma16[] = {
-	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
-	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
-	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
-	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
-	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
-	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
-	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
-	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
-	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
-	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
-	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
-	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
-	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
-	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
-	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
-	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
-	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
-	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
-	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
-	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
-	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
-	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
-	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
-	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
-	344,	328,	376,	360,	280,	264,	312,	296,
-	472,	456,	504,	488,	408,	392,	440,	424,
-	88,	72,	120,	104,	24,	8,	56,	40,
-	216,	200,	248,	232,	152,	136,	184,	168,
-	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
-	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
-	688,	656,	752,	720,	560,	528,	624,	592,
-	944,	912,	1008,	976,	816,	784,	880,	848,
-};
-#endif /* HAS_16BIT_TABLES */
-
-
-#ifdef HAS_14BIT_TABLES
-
-    /*
-     *  Unused for now. Where are the MSB parts anyway??
-     */
-
-/* 14 bit mu-law (LSB) */
-
-char dmasound_ulaw2dma14l[] = {
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	33,	33,	33,	33,	33,	33,	33,	33,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	1,	1,	1,	1,	1,	1,	1,	1,
-	49,	17,	49,	17,	49,	17,	49,	17,
-	49,	17,	49,	17,	49,	17,	49,	17,
-	41,	57,	9,	25,	41,	57,	9,	25,
-	41,	57,	9,	25,	41,	57,	9,	25,
-	37,	45,	53,	61,	5,	13,	21,	29,
-	37,	45,	53,	61,	5,	13,	21,	29,
-	35,	39,	43,	47,	51,	55,	59,	63,
-	3,	7,	11,	15,	19,	23,	27,	31,
-	34,	36,	38,	40,	42,	44,	46,	48,
-	50,	52,	54,	56,	58,	60,	62,	0,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	31,	31,	31,	31,	31,	31,	31,	31,
-	63,	63,	63,	63,	63,	63,	63,	63,
-	63,	63,	63,	63,	63,	63,	63,	63,
-	15,	47,	15,	47,	15,	47,	15,	47,
-	15,	47,	15,	47,	15,	47,	15,	47,
-	23,	7,	55,	39,	23,	7,	55,	39,
-	23,	7,	55,	39,	23,	7,	55,	39,
-	27,	19,	11,	3,	59,	51,	43,	35,
-	27,	19,	11,	3,	59,	51,	43,	35,
-	29,	25,	21,	17,	13,	9,	5,	1,
-	61,	57,	53,	49,	45,	41,	37,	33,
-	30,	28,	26,	24,	22,	20,	18,	16,
-	14,	12,	10,	8,	6,	4,	2,	0
-};
-
-/* 14 bit A-law (LSB) */
-
-char dmasound_alaw2dma14l[] = {
-	32,	32,	32,	32,	32,	32,	32,	32,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	16,	48,	16,	48,	16,	48,	16,	48,
-	16,	48,	16,	48,	16,	48,	16,	48,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	42,	46,	34,	38,	58,	62,	50,	54,
-	10,	14,	2,	6,	26,	30,	18,	22,
-	42,	46,	34,	38,	58,	62,	50,	54,
-	10,	14,	2,	6,	26,	30,	18,	22,
-	40,	56,	8,	24,	40,	56,	8,	24,
-	40,	56,	8,	24,	40,	56,	8,	24,
-	20,	28,	4,	12,	52,	60,	36,	44,
-	20,	28,	4,	12,	52,	60,	36,	44,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	32,	32,	32,	32,	32,	32,	32,	32,
-	48,	16,	48,	16,	48,	16,	48,	16,
-	48,	16,	48,	16,	48,	16,	48,	16,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	0,	0,	0,	0,	0,	0,	0,	0,
-	22,	18,	30,	26,	6,	2,	14,	10,
-	54,	50,	62,	58,	38,	34,	46,	42,
-	22,	18,	30,	26,	6,	2,	14,	10,
-	54,	50,	62,	58,	38,	34,	46,	42,
-	24,	8,	56,	40,	24,	8,	56,	40,
-	24,	8,	56,	40,	24,	8,	56,	40,
-	44,	36,	60,	52,	12,	4,	28,	20,
-	44,	36,	60,	52,	12,	4,	28,	20
-};
-#endif /* HAS_14BIT_TABLES */
-
+/* control over who can modify resources shared between play/record */
+static mode_t shared_resource_owner = 0 ;
+static int shared_resources_initialised = 0 ;
 
     /*
      *  Mid level stuff
@@ -393,15 +230,7 @@
 
 static inline void sound_silence(void)
 {
-	/* update hardware settings one more */
-	dmasound.mach.init();
-
-	dmasound.mach.silence();
-}
-
-static inline void sound_init(void)
-{
-	dmasound.mach.init();
+	dmasound.mach.silence(); /* _MUST_ stop DMA */
 }
 
 static inline int sound_set_format(int format)
@@ -414,8 +243,17 @@
 	if (speed < 0)
 		return dmasound.soft.speed;
 
+	/* trap out-of-range speed settings.
+	   at present we allow (arbitrarily) low rates - using soft
+	   up-conversion - but we can't allow > max because there is
+	   no soft down-conversion.
+	*/
+	if (dmasound.mach.max_dsp_speed &&
+	   (speed > dmasound.mach.max_dsp_speed))
+		speed = dmasound.mach.max_dsp_speed ;
+
 	dmasound.soft.speed = speed;
-	dmasound.mach.init();
+
 	if (dmasound.minDev == SND_DEV_DSP)
 		dmasound.dsp.speed = dmasound.soft.speed;
 
@@ -432,7 +270,6 @@
 	dmasound.soft.stereo = stereo;
 	if (dmasound.minDev == SND_DEV_DSP)
 		dmasound.dsp.stereo = stereo;
-	dmasound.mach.init();
 
 	return stereo;
 }
@@ -471,10 +308,14 @@
 	    default:
 		return 0;
 	}
-	return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+	/* if the user has requested a non-existent translation don't try
+	   to call it but just return 0 bytes moved
+	*/
+	if (ct_func)
+		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+	return 0;
 }
 
-
     /*
      *  /dev/mixer abstraction
      */
@@ -555,8 +396,10 @@
      */
 
 struct sound_queue dmasound_write_sq;
+static void sq_reset_output(void) ;
 #ifdef HAS_RECORD
 struct sound_queue dmasound_read_sq;
+static void sq_reset_input(void) ;
 #endif
 
 static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
@@ -588,8 +431,6 @@
 	int i;
 
 	if (sq->buffers) {
-		if (sq != &write_sq && dmasound.mach.abort_read)
-			dmasound.mach.abort_read();
 		for (i = 0; i < sq->numBufs; i++)
 			dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
 		kfree(sq->buffers);
@@ -597,15 +438,84 @@
 	}
 }
 
-static void sq_setup(struct sound_queue *sq, int max_count, int max_active,
-		     int block_size)
+
+static int sq_setup(struct sound_queue *sq)
 {
-	void (*setup_func)(void);
+	int (*setup_func)(void) = 0;
+	int hard_frame ;
 
-	sq->max_count = max_count;
-	sq->max_active = max_active;
-	sq->block_size = block_size;
+	if (sq->locked) { /* are we already set? - and not changeable */
+#ifdef DEBUG_DMASOUND
+printk("dmasound_core: tried to sq_setup a locked queue\n") ;
+#endif
+		return -EINVAL ;
+	}
+	sq->locked = 1 ; /* don't think we have a race prob. here _check_ */
+
+	/* make sure that the parameters are set up
+	   This should have been done already...
+	*/
 
+	dmasound.mach.init();
+
+	/* OK.  If the user has set fragment parameters explicitly, then we
+	   should leave them alone... as long as they are valid.
+	   Invalid user fragment params can occur if we allow the whole buffer
+	   to be used when the user requests the fragments sizes (with no soft
+	   x-lation) and then the user subsequently sets a soft x-lation that
+	   requires increased internal buffering.
+
+	   Othwerwise (if the user did not set them) OSS says that we should
+	   select frag params on the basis of 0.5 s output & 0.1 s input
+	   latency. (TODO.  For now we will copy in the defaults.)
+	*/
+
+	if (sq->user_frags <= 0) {
+		sq->max_count = sq->numBufs ;
+		sq->max_active = sq->numBufs ;
+		sq->block_size = sq->bufSize;
+		/* set up the user info */
+		sq->user_frags = sq->numBufs ;
+		sq->user_frag_size = sq->bufSize ;
+		sq->user_frag_size *=
+			(dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
+		sq->user_frag_size /=
+			(dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
+	} else {
+		/* work out requested block size */
+		sq->block_size = sq->user_frag_size ;
+		sq->block_size *=
+			(dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
+		sq->block_size /=
+			(dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
+		/* the user wants to write frag-size chunks */
+		sq->block_size *= dmasound.hard.speed ;
+		sq->block_size /= dmasound.soft.speed ;
+		/* this only works for size values which are powers of 2 */
+		hard_frame =
+			(dmasound.hard.size * (dmasound.hard.stereo+1))/8 ;
+		sq->block_size +=  (hard_frame - 1) ;
+		sq->block_size &= ~(hard_frame - 1) ; /* make sure we are aligned */
+		/* let's just check for obvious mistakes */
+		if ( sq->block_size <= 0 || sq->block_size > sq->bufSize) {
+#ifdef DEBUG_DMASOUND
+printk("dmasound_core: invalid frag size (user set %d)\n", sq->user_frag_size) ;
+#endif
+			sq->block_size = sq->bufSize ;
+		}
+		if ( sq->user_frags <= sq->numBufs ) {
+			sq->max_count = sq->user_frags ;
+			/* if user has set max_active - then use it */
+			sq->max_active = (sq->max_active <= sq->max_count) ?
+				sq->max_active : sq->max_count ;
+		} else {
+#ifdef DEBUG_DMASOUND
+printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ;
+#endif
+			sq->max_count =
+			sq->max_active = sq->numBufs ;
+		}
+	}
 	sq->front = sq->count = sq->rear_size = 0;
 	sq->syncing = 0;
 	sq->active = 0;
@@ -613,12 +523,16 @@
 	if (sq == &write_sq) {
 	    sq->rear = -1;
 	    setup_func = dmasound.mach.write_sq_setup;
-	} else {
+	}
+#ifdef HAS_RECORD
+	else {
 	    sq->rear = 0;
 	    setup_func = dmasound.mach.read_sq_setup;
 	}
+#endif
 	if (setup_func)
-	    setup_func();
+	    return setup_func();
+	return 0 ;
 }
 
 static inline void sq_play(void)
@@ -631,7 +545,8 @@
 {
 	ssize_t uWritten = 0;
 	u_char *dest;
-	ssize_t uUsed, bUsed, bLeft;
+	ssize_t uUsed = 0, bUsed, bLeft;
+	unsigned long flags ;
 
 	/* ++TeSche: Is something like this necessary?
 	 * Hey, that's an honest question! Or does any other part of the
@@ -640,11 +555,52 @@
 	if (uLeft == 0)
 		return 0;
 
+	/* implement any changes we have made to the soft/hard params.
+	   this is not satisfactory really, all we have done up to now is to
+	   say what we would like - there hasn't been any real checking of capability
+	*/
+
+	if (shared_resources_initialised == 0) {
+		dmasound.mach.init() ;
+		shared_resources_initialised = 1 ;
+	}
+
+	/* set up the sq if it is not already done. This may seem a dumb place
+	   to do it - but it is what OSS requires.  It means that write() can
+	   return memory allocation errors.  To avoid this possibility use the
+	   GETBLKSIZE or GETOSPACE ioctls (after you've fiddled with all the
+	   params you want to change) - these ioctls also force the setup.
+	*/
+
+	if (write_sq.locked == 0) {
+		if ((uWritten = sq_setup(&write_sq)) < 0) return uWritten ;
+		uWritten = 0 ;
+	}
+
+/* FIXME: I think that this may be the wrong behaviour when we get strapped
+	for time and the cpu is close to being (or actually) behind in sending data.
+	- because we've lost the time that the N samples, already in the buffer,
+	would have given us to get here with the next lot from the user.
+*/
 	/* The interrupt doesn't start to play the last, incomplete frame.
 	 * Thus we can append to it without disabling the interrupts! (Note
 	 * also that write_sq.rear isn't affected by the interrupt.)
 	 */
 
+	/* as of 1.6 this behaviour changes if SNDCTL_DSP_POST has been issued:
+	   this will mimic the behaviour of syncing and allow the sq_play() to
+	   queue a partial fragment.  Since sq_play() may/will be called from
+	   the IRQ handler - at least on Pmac we have to deal with it.
+	   The strategy - possibly not optimum - is to kill _POST status if we
+	   get here.  This seems, at least, reasonable - in the sense that POST
+	   is supposed to indicate that we might not write before the queue
+	   is drained - and if we get here in time then it does not apply.
+	*/
+
+	save_flags(flags) ; cli() ;
+	write_sq.syncing &= ~2 ; /* take out POST status */
+	restore_flags(flags) ;
+
 	if (write_sq.count > 0 &&
 	    (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
 		dest = write_sq.buffers[write_sq.rear];
@@ -655,12 +611,12 @@
 			return uUsed;
 		src += uUsed;
 		uWritten += uUsed;
-		uLeft -= uUsed;
+		uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ; /* paranoia */
 		write_sq.rear_size = bUsed;
 	}
 
-	do {
-		while (write_sq.count == write_sq.max_active) {
+	while (uLeft) {
+		while (write_sq.count >= write_sq.max_active) {
 			sq_play();
 			if (write_sq.open_mode & O_NONBLOCK)
 				return uWritten > 0 ? uWritten : -EAGAIN;
@@ -685,19 +641,45 @@
 			break;
 		src += uUsed;
 		uWritten += uUsed;
-		uLeft -= uUsed;
+		uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ; /* paranoia */
 		if (bUsed) {
 			write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
 			write_sq.rear_size = bUsed;
 			write_sq.count++;
 		}
-	} while (bUsed);   /* uUsed may have been 0 */
+	} /* uUsed may have been 0 */
 
 	sq_play();
 
 	return uUsed < 0? uUsed: uWritten;
 }
 
+static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+	int retVal;
+	
+	if (write_sq.locked == 0) {
+		if ((retVal = sq_setup(&write_sq)) < 0)
+			return retVal;
+		return 0;
+	}
+	if (file->f_mode & FMODE_WRITE )
+		poll_wait(file, &write_sq.action_queue, wait);
+#ifdef HAS_RECORD
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &read_sq.action_queue, wait);
+	if (file->f_mode & FMODE_READ)
+		if (read_sq.block_size - read_sq.rear_size > 0)
+			mask |= POLLIN | POLLRDNORM;
+#endif
+	if (file->f_mode & FMODE_WRITE)
+		if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0)
+			mask |= POLLOUT | POLLWRNORM;
+	return mask;
+
+}
+
 #ifdef HAS_RECORD
     /*
      *  Here is how the values are used for reading.
@@ -707,9 +689,12 @@
      *  The value 'rear' indicates the buffer the DMA is currently filling.
      *  When 'front' == 'rear' the buffer "ring" is empty (we always have an
      *  empty available).  The 'rear_size' is used to track partial offsets
-     *  into the current buffer.  Right now, I just keep the DMA running.  If
-     *  the reader can't keep up, the interrupt tosses the oldest buffer.  We
-     *  could also shut down the DMA in this case.
+     *  into the buffer we are currently returning to the user.
+
+     *  This level (> [1.5]) doesn't care what strategy the LL driver uses with
+     *  DMA on over-run.  It can leave it running (and keep active == 1) or it
+     *  can kill it and set active == 0 in which case this routine will spot
+     *  it and restart the DMA.
      */
 
 static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
@@ -721,8 +706,25 @@
 	if (uLeft == 0)
 		return 0;
 
-	if (!read_sq.active && dmasound.mach.record)
-		dmasound.mach.record();	/* Kick off the record process. */
+	/* cater for the compatibility mode - record compiled in but no LL */
+	if (dmasound.mach.record == NULL)
+		return -EINVAL ;
+
+	/* see comment in sq_write()
+	*/
+
+	if( shared_resources_initialised == 0) {
+		dmasound.mach.init() ;
+		shared_resources_initialised = 1 ;
+	}
+
+	/* set up the sq if it is not already done. see comments in sq_write().
+	*/
+
+	if (read_sq.locked == 0) {
+		if ((uRead = sq_setup(&read_sq)) < 0)
+			return uRead ;
+	}
 
 	uRead = 0;
 
@@ -730,6 +732,13 @@
 	*/
 	while (uLeft > 0) {
 
+		/* we happened to get behind and the LL driver killed DMA
+		   then we should set it going again.  This also sets it
+		   going the first time through.
+		*/
+		if ( !read_sq.active )
+			dmasound.mach.record();
+
 		/* When front == rear, the DMA is not done yet.
 		*/
 		while (read_sq.front == read_sq.rear) {
@@ -774,14 +783,16 @@
 	sq->busy = 0;
 }
 
+#if 0 /* blocking open() */
 static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
 			      mode_t mode)
 {
 	if (file->f_mode & mode) {
-		sq->busy = 0;
+		sq->busy = 0; /* CHECK: IS THIS OK??? */
 		WAKE_UP(sq->open_queue);
 	}
 }
+#endif
 
 static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
 		    int numbufs, int bufsize)
@@ -790,6 +801,7 @@
 
 	if (file->f_mode & mode) {
 		if (sq->busy) {
+#if 0 /* blocking open() */
 			rc = -EBUSY;
 			if (file->f_flags & O_NONBLOCK)
 				return rc;
@@ -800,84 +812,193 @@
 					return rc;
 			}
 			rc = 0;
+#else
+			/* OSS manual says we will return EBUSY regardless
+			   of O_NOBLOCK.
+			*/
+			return -EBUSY ;
+#endif
 		}
 		sq->busy = 1; /* Let's play spot-the-race-condition */
 
-		if (sq_allocate_buffers(sq, numbufs, bufsize)) {
+		/* allocate the default number & size of buffers.
+		   (i.e. specified in _setup() or as module params)
+		   can't be changed at the moment - but _could_ be perhaps
+		   in the setfragments ioctl.
+		*/
+		if (( rc = sq_allocate_buffers(sq, numbufs, bufsize))) {
+#if 0 /* blocking open() */
 			sq_wake_up(sq, file, mode);
+#else
+			sq->busy = 0 ;
+#endif
 			return rc;
 		}
 
-		sq_setup(sq, numbufs, numbufs, bufsize);
 		sq->open_mode = file->f_mode;
 	}
 	return rc;
 }
 
 #define write_sq_init_waitqueue()	sq_init_waitqueue(&write_sq)
+#if 0 /* blocking open() */
 #define write_sq_wake_up(file)		sq_wake_up(&write_sq, file, FMODE_WRITE)
+#endif
 #define write_sq_release_buffers()	sq_release_buffers(&write_sq)
 #define write_sq_open(file)	\
-	sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10)
+	sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize )
 
 #ifdef HAS_RECORD
 #define read_sq_init_waitqueue()	sq_init_waitqueue(&read_sq)
+#if 0 /* blocking open() */
 #define read_sq_wake_up(file)		sq_wake_up(&read_sq, file, FMODE_READ)
+#endif
 #define read_sq_release_buffers()	sq_release_buffers(&read_sq)
 #define read_sq_open(file)	\
-	sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10)
-#else /* !HAS_RECORD */
+	sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize )
+#else
 #define read_sq_init_waitqueue()	do {} while (0)
+#if 0 /* blocking open() */
 #define read_sq_wake_up(file)		do {} while (0)
+#endif
 #define read_sq_release_buffers()	do {} while (0)
-#define read_sq_open(file)		(0)
-#endif /* !HAS_RECORD */
+#define sq_reset_input()		do {} while (0)
+#endif
 
 static int sq_open(struct inode *inode, struct file *file)
 {
 	int rc;
 
 	dmasound.mach.open();
-	if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) {
+
+	if ((rc = write_sq_open(file))) { /* checks the f_mode */
 		dmasound.mach.release();
 		return rc;
 	}
+#ifdef HAS_RECORD
+	if (dmasound.mach.record) {
+		if ((rc = read_sq_open(file))) { /* checks the f_mode */
+			dmasound.mach.release();
+			return rc;
+		}
+	} else { /* no record function installed; in compat mode */
+		if (file->f_mode & FMODE_READ) {
+			/* TODO: if O_RDWR, release any resources grabbed by write part */
+			dmasound.mach.release() ;
+			/* I think this is what is required by open(2) */
+			return -ENXIO ;
+		}
+	}
+#else /* !HAS_RECORD */
+	if (file->f_mode & FMODE_READ) {
+		/* TODO: if O_RDWR, release any resources grabbed by write part */
+		dmasound.mach.release() ;
+		return -ENXIO ; /* I think this is what is required by open(2) */
+	}
+#endif /* HAS_RECORD */
 
 	if (dmasound.mach.sq_open)
-	    dmasound.mach.sq_open();
+	    dmasound.mach.sq_open(file->f_mode);
+
+	/* CHECK whether this is sensible - in the case that dsp0 could be opened
+	  O_RDONLY and dsp1 could be opened O_WRONLY
+	*/
+
 	dmasound.minDev = MINOR(inode->i_rdev) & 0x0f;
-	dmasound.soft = dmasound.dsp;
-	dmasound.hard = dmasound.dsp;
-	sound_init();
-	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+
+	/* OK. - we should make some attempt at consistency. At least the H'ware
+	   options should be set with a valid mode.  We will make it that the LL
+	   driver must supply defaults for hard & soft params.
+	*/
+
+	if (shared_resource_owner == 0) {
+		/* you can make this AFMT_U8/mono/8K if you want to mimic old
+		   OSS behaviour - while we still have soft translations ;-) */
+		dmasound.soft = dmasound.mach.default_soft ;
+		dmasound.dsp = dmasound.mach.default_soft ;
+		dmasound.hard = dmasound.mach.default_hard ;
+	}
+
+#ifndef DMASOUND_STRICT_OSS_COMPLIANCE
+	/* none of the current LL drivers can actually do this "native" at the moment
+	   OSS does not really require us to supply /dev/audio if we can't do it.
+	*/
+	if (dmasound.minDev == SND_DEV_AUDIO) {
 		sound_set_speed(8000);
 		sound_set_stereo(0);
 		sound_set_format(AFMT_MU_LAW);
 	}
-
-#if 0
-	if (file->f_mode == FMODE_READ && dmasound.mach.record) {
-		/* Start dma'ing straight away */
-		dmasound.mach.record();
-	}
 #endif
 
 	return 0;
 }
 
-static void sq_reset(void)
+static void sq_reset_output(void)
 {
-	sound_silence();
+	sound_silence(); /* this _must_ stop DMA, we might be about to lose the buffers */
 	write_sq.active = 0;
 	write_sq.count = 0;
-	write_sq.front = (write_sq.rear+1) % write_sq.max_count;
+	write_sq.rear_size = 0;
+	/* write_sq.front = (write_sq.rear+1) % write_sq.max_count;*/
+	write_sq.front = 0 ;
+	write_sq.rear = -1 ; /* same as for set-up */
+
+	/* OK - we can unlock the parameters and fragment settings */
+	write_sq.locked = 0 ;
+	write_sq.user_frags = 0 ;
+	write_sq.user_frag_size = 0 ;
+}
+
+#ifdef HAS_RECORD
+
+static void sq_reset_input(void)
+{
+	if (dmasound.mach.record && read_sq.active) {
+		if (dmasound.mach.abort_read) { /* this routine must really be present */
+			read_sq.syncing = 1 ;
+			/* this can use the read_sq.sync_queue to sleep if
+			   necessary - it should not return until DMA
+			   is really stopped - because we might deallocate
+			   the buffers as the next action...
+			*/
+			dmasound.mach.abort_read() ;
+		} else {
+			printk(KERN_ERR
+			"dmasound_core: %s has no abort_read()!! all bets are off\n",
+				dmasound.mach.name) ;
+		}
+	}
+	read_sq.syncing =
+	read_sq.active =
+	read_sq.front =
+	read_sq.count =
+	read_sq.rear = 0 ;
+
+	/* OK - we can unlock the parameters and fragment settings */
+	read_sq.locked = 0 ;
+	read_sq.user_frags = 0 ;
+	read_sq.user_frag_size = 0 ;
+}
+
+#endif
+
+static void sq_reset(void)
+{
+	sq_reset_output() ;
+	sq_reset_input() ;
+	/* we could consider resetting the shared_resources_owner here... but I
+	   think it is probably still rather non-obvious to application writer
+	*/
+
+	/* we release everything else though */
+	shared_resources_initialised = 0 ;
 }
 
 static int sq_fsync(struct file *filp, struct dentry *dentry)
 {
 	int rc = 0;
 
-	write_sq.syncing = 1;
+	write_sq.syncing |= 1;
 	sq_play();	/* there may be an incomplete frame waiting */
 
 	while (write_sq.active) {
@@ -886,13 +1007,14 @@
 			/* While waiting for audio output to drain, an
 			 * interrupt occurred.  Stop audio output immediately
 			 * and clear the queue. */
-			sq_reset();
+			sq_reset_output();
 			rc = -EINTR;
 			break;
 		}
 	}
 
-	write_sq.syncing = 0;
+	/* flag no sync regardless of whether we had a DSP_POST or not */
+	write_sq.syncing = 0 ;
 	return rc;
 }
 
@@ -901,33 +1023,130 @@
 	int rc = 0;
 
 	lock_kernel();
-	if (write_sq.busy)
-		rc = sq_fsync(file, file->f_dentry);
-	dmasound.soft = dmasound.dsp;
-	dmasound.hard = dmasound.dsp;
-	sound_silence();
 
-	write_sq_release_buffers();
-	read_sq_release_buffers();
-	dmasound.mach.release();
+#ifdef HAS_RECORD
+	/* probably best to do the read side first - so that time taken to do it
+	   overlaps with playing any remaining output samples.
+	*/
+	if (file->f_mode & FMODE_READ) {
+		sq_reset_input() ; /* make sure dma is stopped and all is quiet */
+		read_sq_release_buffers();
+		read_sq.busy = 0;
+	}
+#endif
 
-	/* There is probably a DOS atack here. They change the mode flag. */
-	/* XXX add check here */
-	read_sq_wake_up(file);
-	write_sq_wake_up(file);
+	if (file->f_mode & FMODE_WRITE) {
+		if (write_sq.busy)
+			rc = sq_fsync(file, file->f_dentry);
+
+		sq_reset_output() ; /* make sure dma is stopped and all is quiet */
+		write_sq_release_buffers();
+		write_sq.busy = 0;
+	}
+
+	if (file->f_mode & shared_resource_owner) { /* it's us that has them */
+		shared_resource_owner = 0 ;
+		shared_resources_initialised = 0 ;
+		dmasound.hard = dmasound.mach.default_hard ;
+	}
+
+	dmasound.mach.release();
 
+#if 0 /* blocking open() */
 	/* Wake up a process waiting for the queue being released.
 	 * Note: There may be several processes waiting for a call
 	 * to open() returning. */
+
+	/* Iain: hmm I don't understand this next comment ... */
+	/* There is probably a DOS atack here. They change the mode flag. */
+	/* XXX add check here,*/
+	read_sq_wake_up(file); /* checks f_mode */
+	write_sq_wake_up(file); /* checks f_mode */
+#endif /* blocking open() */
+
 	unlock_kernel();
 
 	return rc;
 }
 
+/* here we see if we have a right to modify format, channels, size and so on
+   if no-one else has claimed it already then we do...
+
+   TODO: We might change this to mask O_RDWR such that only one or the other channel
+   is the owner - if we have problems.
+*/
+
+static int shared_resources_are_mine(mode_t md)
+{
+	if (shared_resource_owner)
+		return (shared_resource_owner & md ) ;
+	else {
+		shared_resource_owner = md ;
+		return 1 ;
+	}
+}
+
+/* if either queue is locked we must deny the right to change shared params
+*/
+
+static int queues_are_quiescent(void)
+{
+#ifdef HAS_RECORD
+	if (dmasound.mach.record)
+		if (read_sq.locked)
+			return 0 ;
+#endif
+	if (write_sq.locked)
+		return 0 ;
+	return 1 ;
+}
+
+/* check and set a queue's fragments per user's wishes...
+   we will check against the pre-defined literals and the actual sizes.
+   This is a bit fraught - because soft translations can mess with our
+   buffer requirements *after* this call - OSS says "call setfrags first"
+*/
+
+/* It is possible to replace all the -EINVAL returns with an override that
+   just puts the allowable value in.  This may be what many OSS apps require
+*/
+
+static int set_queue_frags(struct sound_queue *sq, int bufs, int size)
+{
+	if (sq->locked) {
+#ifdef DEBUG_DMASOUND
+printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
+#endif
+		return -EINVAL ;
+	}
+
+	if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE))
+		return -EINVAL ;
+	size = (1<<size) ; /* now in bytes */
+	if (size > sq->bufSize)
+		return -EINVAL ; /* this might still not work */
+
+	if (bufs <= 0)
+		return -EINVAL ;
+	if (bufs > sq->numBufs) /* the user is allowed say "don't care" with 0x7fff */
+		bufs = sq->numBufs ;
+
+	/* there is, currently, no way to specify max_active separately
+	   from max_count.  This could be a LL driver issue - I guess
+	   if there is a requirement for these values to be different then
+	  we will have to pass that info. up to this level.
+	*/
+	sq->user_frags =
+	sq->max_active = bufs ;
+	sq->user_frag_size = size ;
+
+	return 0 ;
+}
+
 static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		    u_long arg)
 {
-	int val;
+	int val, result;
 	u_long fmt;
 	int data;
 	int size, nbufs;
@@ -937,85 +1156,165 @@
 	case SNDCTL_DSP_RESET:
 		sq_reset();
 		return 0;
+		break ;
+	case SNDCTL_DSP_GETFMTS:
+		fmt = dmasound.mach.hardware_afmts ; /* this is what OSS says.. */
+		return IOCTL_OUT(arg, fmt);
+		break ;
+	case SNDCTL_DSP_GETBLKSIZE:
+		/* this should tell the caller about bytes that the app can
+		   read/write - the app doesn't care about our internal buffers.
+		   We force sq_setup() here as per OSS 1.1 (which should
+		   compute the values necessary).
+		   Since there is no mechanism to specify read/write separately, for
+		   fds opened O_RDWR, the write_sq values will, arbitrarily, overwrite
+		   the read_sq ones.
+		*/
+		size = 0 ;
+#ifdef HAS_RECORD
+		if (dmasound.mach.record && (file->f_mode & FMODE_READ)) {
+			if ( !read_sq.locked )
+				sq_setup(&read_sq) ; /* set params */
+			size = read_sq.user_frag_size ;
+		}
+#endif
+		if (file->f_mode & FMODE_WRITE) {
+			if ( !write_sq.locked )
+				sq_setup(&write_sq) ;
+			size = write_sq.user_frag_size ;
+		}
+		return IOCTL_OUT(arg, size);
+		break ;
 	case SNDCTL_DSP_POST:
+		/* all we are going to do is to tell the LL that any
+		   partial frags can be queued for output.
+		   The LL will have to clear this flag when last output
+		   is queued.
+		*/
+		write_sq.syncing |= 0x2 ;
+		sq_play() ;
+		return 0 ;
 	case SNDCTL_DSP_SYNC:
-		return sq_fsync(file, file->f_dentry);
-
-		/* ++TeSche: before changing any of these it's
-		 * probably wise to wait until sound playing has
-		 * settled down. */
+		/* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET
+		   except that it waits for output to finish before resetting
+		   everything - read, however, is killed imediately.
+		*/
+		result = 0 ;
+		if ((file->f_mode & FMODE_READ) && dmasound.mach.record)
+			sq_reset_input() ;
+		if (file->f_mode & FMODE_WRITE) {
+			result = sq_fsync(file, file->f_dentry);
+			sq_reset_output() ;
+		}
+		/* if we are the shared resource owner then release them */
+		if (file->f_mode & shared_resource_owner)
+			shared_resources_initialised = 0 ;
+		return result ;
+		break ;
 	case SNDCTL_DSP_SPEED:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_speed(data));
+		/* changing this on the fly will have wierd effects on the sound.
+		   Where there are rate conversions implemented in soft form - it
+		   will cause the _ctx_xxx() functions to be substituted.
+		   However, there doesn't appear to be any reason to dis-allow it from
+		   a driver pov.
+		*/
+		if (shared_resources_are_mine(file->f_mode)) {
+			IOCTL_IN(arg, data);
+			data = sound_set_speed(data) ;
+			shared_resources_initialised = 0 ;
+			return IOCTL_OUT(arg, data);
+		} else
+			return -EINVAL ;
+		break ;
+	/* OSS says these next 4 actions are undefined when the device is
+	   busy/active - we will just return -EINVAL.
+	   To be allowed to change one - (a) you have to own the right
+	    (b) the queue(s) must be quiescent
+	*/
 	case SNDCTL_DSP_STEREO:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data));
+		if (shared_resources_are_mine(file->f_mode) &&
+		    queues_are_quiescent()) {
+			IOCTL_IN(arg, data);
+			shared_resources_initialised = 0 ;
+			return IOCTL_OUT(arg, sound_set_stereo(data));
+		} else
+			return -EINVAL ;
+		break ;
 	case SOUND_PCM_WRITE_CHANNELS:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+		if (shared_resources_are_mine(file->f_mode) &&
+		    queues_are_quiescent()) {
+			IOCTL_IN(arg, data);
+			/* the user might ask for 20 channels, we will return 1 or 2 */
+			shared_resources_initialised = 0 ;
+			return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+		} else
+			return -EINVAL ;
+		break ;
 	case SNDCTL_DSP_SETFMT:
-		sq_fsync(file, file->f_dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_format(data));
-	case SNDCTL_DSP_GETFMTS:
-		fmt = 0;
-		if (dmasound.trans_write) {
-			if (dmasound.trans_write->ct_ulaw)
-				fmt |= AFMT_MU_LAW;
-			if (dmasound.trans_write->ct_alaw)
-				fmt |= AFMT_A_LAW;
-			if (dmasound.trans_write->ct_s8)
-				fmt |= AFMT_S8;
-			if (dmasound.trans_write->ct_u8)
-				fmt |= AFMT_U8;
-			if (dmasound.trans_write->ct_s16be)
-				fmt |= AFMT_S16_BE;
-			if (dmasound.trans_write->ct_u16be)
-				fmt |= AFMT_U16_BE;
-			if (dmasound.trans_write->ct_s16le)
-				fmt |= AFMT_S16_LE;
-			if (dmasound.trans_write->ct_u16le)
-				fmt |= AFMT_U16_LE;
-		}
-		return IOCTL_OUT(arg, fmt);
-	case SNDCTL_DSP_GETBLKSIZE:
-		size = write_sq.block_size
-			* dmasound.soft.size * (dmasound.soft.stereo + 1)
-			/ (dmasound.hard.size * (dmasound.hard.stereo + 1));
-		return IOCTL_OUT(arg, size);
+		if (shared_resources_are_mine(file->f_mode) &&
+		    queues_are_quiescent()) {
+		    	int format;
+			IOCTL_IN(arg, data);
+			shared_resources_initialised = 0 ;
+			format = sound_set_format(data);
+			result = IOCTL_OUT(arg, format);
+			if (result < 0)
+				return result;
+			if (format != data)
+				return -EINVAL;
+			return 0;
+		} else
+			return -EINVAL ;
+		break ;
 	case SNDCTL_DSP_SUBDIVIDE:
+		return -EINVAL ;
 		break;
 	case SNDCTL_DSP_SETFRAGMENT:
-		if (write_sq.count || write_sq.active || write_sq.syncing)
-			return -EINVAL;
-		IOCTL_IN(arg, size);
-		nbufs = size >> 16;
-		if (nbufs < 2 || nbufs > write_sq.numBufs)
-			nbufs = write_sq.numBufs;
-		size &= 0xffff;
-		if (size >= 8 && size <= 29) {
-			size = 1 << size;
-			size *= dmasound.hard.size * (dmasound.hard.stereo + 1);
-			size /= dmasound.soft.size * (dmasound.soft.stereo + 1);
-			if (size > write_sq.bufSize)
-				size = write_sq.bufSize;
-		} else
-			size = write_sq.bufSize;
-		sq_setup(&write_sq, write_sq.numBufs, nbufs, size);
-		return IOCTL_OUT(arg,write_sq.bufSize | write_sq.numBufs << 16);
+		/* we can do this independently for the two queues - with the
+		   proviso that for fds opened O_RDWR we cannot separate the
+		   actions and both queues will be set per the last call.
+		   NOTE: this does *NOT* actually set the queue up - merely
+		   registers our intentions.
+		*/
+		IOCTL_IN(arg, data);
+		result = 0 ;
+		nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */
+		size = data & 0xffff;
+#ifdef HAS_RECORD
+		if ((file->f_mode & FMODE_READ) && dmasound.mach.record) {
+			result = set_queue_frags(&read_sq, nbufs, size) ;
+			if (result)
+				return result ;
+		}
+#endif
+		if (file->f_mode & FMODE_WRITE) {
+			result = set_queue_frags(&write_sq, nbufs, size) ;
+			if (result)
+				return result ;
+		}
+		/* NOTE: this return value is irrelevant - OSS specifically says that
+		   the value is 'random' and that the user _must_ check the actual
+		   frags values using SNDCTL_DSP_GETBLKSIZE or similar */
+		return IOCTL_OUT(arg, data);
+		break ;
 	case SNDCTL_DSP_GETOSPACE:
-		info.fragments = write_sq.max_active - write_sq.count;
-		info.fragstotal = write_sq.max_active;
-		info.fragsize = write_sq.block_size;
-		info.bytes = info.fragments * info.fragsize;
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
+		/*
+		*/
+		if (file->f_mode & FMODE_WRITE) {
+			if ( !write_sq.locked )
+				sq_setup(&write_sq) ;
+			info.fragments = write_sq.max_active - write_sq.count;
+			info.fragstotal = write_sq.max_active;
+			info.fragsize = write_sq.user_frag_size;
+			info.bytes = info.fragments * info.fragsize;
+			if (copy_to_user((void *)arg, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EINVAL ;
+		break ;
 	case SNDCTL_DSP_GETCAPS:
-		val = 1;        /* Revision level of this ioctl() */
+		val = dmasound.mach.capabilities & 0xffffff00;
 		return IOCTL_OUT(arg,val);
 
 	default:
@@ -1029,42 +1328,46 @@
 	owner:		THIS_MODULE,
 	llseek:		no_llseek,
 	write:		sq_write,
+	poll:		sq_poll,
 	ioctl:		sq_ioctl,
 	open:		sq_open,
 	release:	sq_release,
 #ifdef HAS_RECORD
-	read:		sq_read,
+	read:		NULL	/* default to no read for compat mode */
 #endif
 };
 
-static void __init sq_init(void)
+static int __init sq_init(void)
 {
 #ifndef MODULE
 	int sq_unit;
 #endif
+
+#ifdef HAS_RECORD
+	if (dmasound.mach.record)
+		sq_fops.read = sq_read ;
+#endif
 	sq_unit = register_sound_dsp(&sq_fops, -1);
-	if (sq_unit < 0)
-		return;
+	if (sq_unit < 0) {
+		printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;
+		return sq_unit ;
+	}
 
 	write_sq_init_waitqueue();
 	read_sq_init_waitqueue();
 
-	/* whatever you like as startup mode for /dev/dsp,
-	 * (/dev/audio hasn't got a startup mode). note that
-	 * once changed a new open() will *not* restore these!
+	/* These parameters will be restored for every clean open()
+	 * in the case of multiple open()s (e.g. dsp0 & dsp1) they
+	 * will be set so long as the shared resources have no owner.
 	 */
-	dmasound.dsp.format = AFMT_U8;
-	dmasound.dsp.stereo = 0;
-	dmasound.dsp.size = 8;
-
-	/* set minimum rate possible without expanding */
-	dmasound.dsp.speed = dmasound.mach.min_dsp_speed;
-
-	/* before the first open to /dev/dsp this wouldn't be set */
-	dmasound.soft = dmasound.dsp;
-	dmasound.hard = dmasound.dsp;
 
-	sound_silence();
+	if (shared_resource_owner == 0) {
+		dmasound.soft = dmasound.mach.default_soft ;
+		dmasound.hard = dmasound.mach.default_hard ;
+		dmasound.dsp = dmasound.mach.default_soft ;
+		shared_resources_initialised = 0 ;
+	}
+	return 0 ;
 }
 
 
@@ -1072,12 +1375,68 @@
      *  /dev/sndstat
      */
 
+/* we allow more space for record-enabled because there are extra output lines.
+   the number here must include the amount we are prepared to give to the low-level
+   driver.
+*/
+
+#ifdef HAS_RECORD
+#define STAT_BUFF_LEN 1024
+#else
+#define STAT_BUFF_LEN 768
+#endif
+
+/* this is how much space we will allow the low-level driver to use
+   in the stat buffer.  Currently, 2 * (80 character line + <NL>).
+   We do not police this (it is up to the ll driver to be honest).
+*/
+
+#define LOW_LEVEL_STAT_ALLOC 162
+
 static struct {
     int busy;
-    char buf[512];	/* state.buf should not overflow! */
+    char buf[STAT_BUFF_LEN];	/* state.buf should not overflow! */
     int len, ptr;
 } state;
 
+/* publish this function for use by low-level code, if required */
+
+char *get_afmt_string(int afmt)
+{
+        switch(afmt) {
+            case AFMT_MU_LAW:
+                return "mu-law";
+                break;
+            case AFMT_A_LAW:
+                return "A-law";
+                break;
+            case AFMT_U8:
+                return "unsigned 8 bit";
+                break;
+            case AFMT_S8:
+                return "signed 8 bit";
+                break;
+            case AFMT_S16_BE:
+                return "signed 16 bit BE";
+                break;
+            case AFMT_U16_BE:
+                return "unsigned 16 bit BE";
+                break;
+            case AFMT_S16_LE:
+                return "signed 16 bit LE";
+                break;
+            case AFMT_U16_LE:
+                return "unsigned 16 bit LE";
+                break;
+	    case 0:
+		return "format not set" ;
+		break ;
+            default:
+                break ;
+        }
+        return "ERROR: Unsupported AFMT_XXXX code" ;
+}
+
 static int state_open(struct inode *inode, struct file *file)
 {
 	char *buffer = state.buf;
@@ -1090,52 +1449,76 @@
 	state.ptr = 0;
 	state.busy = 1;
 
-	len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name);
+	len += sprintf(buffer+len, "%sDMA sound driver rev %03d :\n",
+		dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
+		((dmasound.mach.version>>8) & 0x0f));
+	len += sprintf(buffer+len,
+		"Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
+		DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
+		(dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
+
+	/* call the low-level module to fill in any stat info. that it has
+	   if present.  Maximum buffer usage is specified.
+	*/
 
-	len += sprintf(buffer+len, "\tsound.format = 0x%x",
-		       dmasound.soft.format);
-	switch (dmasound.soft.format) {
-	    case AFMT_MU_LAW:
-		len += sprintf(buffer+len, " (mu-law)");
-		break;
-	    case AFMT_A_LAW:
-		len += sprintf(buffer+len, " (A-law)");
-		break;
-	    case AFMT_U8:
-		len += sprintf(buffer+len, " (unsigned 8 bit)");
-		break;
-	    case AFMT_S8:
-		len += sprintf(buffer+len, " (signed 8 bit)");
-		break;
-	    case AFMT_S16_BE:
-		len += sprintf(buffer+len, " (signed 16 bit big)");
-		break;
-	    case AFMT_U16_BE:
-		len += sprintf(buffer+len, " (unsigned 16 bit big)");
-		break;
-	    case AFMT_S16_LE:
-		len += sprintf(buffer+len, " (signed 16 bit little)");
-		break;
-	    case AFMT_U16_LE:
-		len += sprintf(buffer+len, " (unsigned 16 bit little)");
-		break;
-	}
-	len += sprintf(buffer+len, "\n");
-	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-		       dmasound.soft.speed, dmasound.hard.speed);
-	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-		       dmasound.soft.stereo,
-		       dmasound.soft.stereo ? "stereo" : "mono");
 	if (dmasound.mach.state_info)
-	    len += dmasound.mach.state_info(buffer);
-	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
-		       " sq.max_active = %d\n",
-		       write_sq.block_size, write_sq.max_count,
-		       write_sq.max_active);
-	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n",
-		       write_sq.count, write_sq.rear_size);
-	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
-		       write_sq.active, write_sq.syncing);
+		len += dmasound.mach.state_info(buffer+len,
+			(size_t) LOW_LEVEL_STAT_ALLOC) ;
+
+	/* make usage of the state buffer as deterministic as poss.
+	   exceptional conditions could cause overrun - and this is flagged as
+	   a kernel error.
+	*/
+
+	/* formats and settings */
+
+	len += sprintf(buffer+len,"\t\t === Formats & settings ===\n") ;
+	len += sprintf(buffer+len,"Parameter %20s%20s\n","soft","hard") ;
+	len += sprintf(buffer+len,"Format   :%20s%20s\n",
+		get_afmt_string(dmasound.soft.format),
+		get_afmt_string(dmasound.hard.format));
+
+	len += sprintf(buffer+len,"Samp Rate:%14d s/sec%14d s/sec\n",
+		       dmasound.soft.speed, dmasound.hard.speed);
+
+	len += sprintf(buffer+len,"Channels :%20s%20s\n",
+		       dmasound.soft.stereo ? "stereo" : "mono",
+		       dmasound.hard.stereo ? "stereo" : "mono" );
+
+	/* sound queue status */
+
+	len += sprintf(buffer+len,"\t\t === Sound Queue status ===\n");
+	len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ;
+	len += sprintf(buffer+len,"%9s:%8d%6d\n",
+		"write", write_sq.numBufs, write_sq.bufSize) ;
+#ifdef HAS_RECORD
+	if (dmasound.mach.record)
+		len += sprintf(buffer+len,"%9s:%8d%6d\n",
+			"read", read_sq.numBufs, read_sq.bufSize) ;
+#endif
+	len += sprintf(buffer+len,
+		"Current  : MaxFrg FragSiz MaxAct Frnt Rear "
+		"Cnt RrSize A B S L  xruns\n") ;
+	len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n",
+		"write", write_sq.max_count, write_sq.block_size,
+		write_sq.max_active, write_sq.front, write_sq.rear,
+		write_sq.count, write_sq.rear_size, write_sq.active,
+		write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ;
+#ifdef HAS_RECORD
+	if (dmasound.mach.record)
+		len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n",
+			"read", read_sq.max_count, read_sq.block_size,
+			read_sq.max_active, read_sq.front, read_sq.rear,
+			read_sq.count, read_sq.rear_size, read_sq.active,
+			read_sq.busy, read_sq.syncing, read_sq.locked, read_sq.xruns) ;
+#endif
+#ifdef DEBUG_DMASOUND
+printk("dmasound: stat buffer used %d bytes\n", len) ;
+#endif
+
+	if (len >= STAT_BUFF_LEN)
+		printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
+
 	state.len = len;
 	return 0;
 }
@@ -1171,15 +1554,16 @@
 	release:	state_release,
 };
 
-static void __init state_init(void)
+static int __init state_init(void)
 {
 #ifndef MODULE
 	int state_unit;
 #endif
 	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
 	if (state_unit < 0)
-		return;
+		return state_unit ;
 	state.busy = 0;
+	return 0 ;
 }
 
 
@@ -1191,6 +1575,7 @@
 
 int __init dmasound_init(void)
 {
+	int res ;
 #ifdef MODULE
 	if (irq_installed)
 		return -EBUSY;
@@ -1199,10 +1584,12 @@
 	/* Set up sound queue, /dev/audio and /dev/dsp. */
 
 	/* Set default settings. */
-	sq_init();
+	if ((res = sq_init()) < 0)
+		return res ;
 
 	/* Set up /dev/sndstat. */
-	state_init();
+	if ((res = state_init()) < 0)
+		return res ;
 
 	/* Set up /dev/mixer. */
 	mixer_init();
@@ -1215,8 +1602,21 @@
 	irq_installed = 1;
 #endif
 
-	printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
-	       numWriteBufs, writeBufSize);
+	printk(KERN_INFO "%s DMA sound driver rev %03d installed\n",
+		dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
+		((dmasound.mach.version>>8) & 0x0f));
+	printk(KERN_INFO
+		"Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
+		DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
+		(dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
+	printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n",
+		numWriteBufs, writeBufSize) ;
+#ifdef HAS_RECORD
+	if (dmasound.mach.record)
+		printk(KERN_INFO
+			"Read  will use %4d fragments of %7d bytes as default\n",
+			numReadBufs, readBufSize) ;
+#endif
 
 	return 0;
 }
@@ -1228,6 +1628,7 @@
 	if (irq_installed) {
 		sound_silence();
 		dmasound.mach.irqcleanup();
+		irq_installed = 0;
 	}
 
 	write_sq_release_buffers();
@@ -1245,29 +1646,60 @@
 
 static int __init dmasound_setup(char *str)
 {
-	int ints[6];
+	int ints[6], size;
 
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 
 	/* check the bootstrap parameter for "dmasound=" */
 
+	/* FIXME: other than in the most naive of cases there is no sense in these
+	 *	  buffers being other than powers of two.  This is not checked yet.
+	 */
+
 	switch (ints[0]) {
+#ifdef HAS_RECORD
+        case 5:
+                if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS))
+                        printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+                else
+                        catchRadius = ints[5];
+                /* fall through */
+        case 4:
+                if (ints[4] < MIN_BUFFERS)
+                        printk("dmasound_setup: illegal number of read buffers, using default = %d\n",
+                                 numReadBufs);
+                else
+                        numReadBufs = ints[4];
+                /* fall through */
+        case 3:
+		if ((size = ints[3]) < 256)  /* check for small buffer specs */
+			size <<= 10 ;
+                if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
+                        printk("dmasound_setup: illegal read buffer size, using default = %d\n", readBufSize);
+                else
+                        readBufSize = size;
+                /* fall through */
+#else
 	case 3:
 		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
 			printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
 		else
 			catchRadius = ints[3];
 		/* fall through */
+#endif
 	case 2:
 		if (ints[1] < MIN_BUFFERS)
 			printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
 		else
 			numWriteBufs = ints[1];
-		if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-			printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize);
-		else
-			writeBufSize = ints[2];
-		break;
+		/* fall through */
+	case 1:
+		if ((size = ints[2]) < 256) /* check for small buffer specs */
+			size <<= 10 ;
+                if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
+                        printk("dmasound_setup: illegal write buffer size, using default = %d\n", writeBufSize);
+                else
+                        writeBufSize = size;
 	case 0:
 		break;
 	default:
@@ -1281,6 +1713,85 @@
 
 #endif /* !MODULE */
 
+    /*
+     *  Conversion tables
+     */
+
+#ifdef HAS_8BIT_TABLES
+/* 8 bit mu-law */
+
+char dmasound_ulaw2dma8[] = {
+	-126,	-122,	-118,	-114,	-110,	-106,	-102,	-98,
+	-94,	-90,	-86,	-82,	-78,	-74,	-70,	-66,
+	-63,	-61,	-59,	-57,	-55,	-53,	-51,	-49,
+	-47,	-45,	-43,	-41,	-39,	-37,	-35,	-33,
+	-31,	-30,	-29,	-28,	-27,	-26,	-25,	-24,
+	-23,	-22,	-21,	-20,	-19,	-18,	-17,	-16,
+	-16,	-15,	-15,	-14,	-14,	-13,	-13,	-12,
+	-12,	-11,	-11,	-10,	-10,	-9,	-9,	-8,
+	-8,	-8,	-7,	-7,	-7,	-7,	-6,	-6,
+	-6,	-6,	-5,	-5,	-5,	-5,	-4,	-4,
+	-4,	-4,	-4,	-4,	-3,	-3,	-3,	-3,
+	-3,	-3,	-3,	-3,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	0,
+	125,	121,	117,	113,	109,	105,	101,	97,
+	93,	89,	85,	81,	77,	73,	69,	65,
+	62,	60,	58,	56,	54,	52,	50,	48,
+	46,	44,	42,	40,	38,	36,	34,	32,
+	30,	29,	28,	27,	26,	25,	24,	23,
+	22,	21,	20,	19,	18,	17,	16,	15,
+	15,	14,	14,	13,	13,	12,	12,	11,
+	11,	10,	10,	9,	9,	8,	8,	7,
+	7,	7,	6,	6,	6,	6,	5,	5,
+	5,	5,	4,	4,	4,	4,	3,	3,
+	3,	3,	3,	3,	2,	2,	2,	2,
+	2,	2,	2,	2,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0
+};
+
+/* 8 bit A-law */
+
+char dmasound_alaw2dma8[] = {
+	-22,	-21,	-24,	-23,	-18,	-17,	-20,	-19,
+	-30,	-29,	-32,	-31,	-26,	-25,	-28,	-27,
+	-11,	-11,	-12,	-12,	-9,	-9,	-10,	-10,
+	-15,	-15,	-16,	-16,	-13,	-13,	-14,	-14,
+	-86,	-82,	-94,	-90,	-70,	-66,	-78,	-74,
+	-118,	-114,	-126,	-122,	-102,	-98,	-110,	-106,
+	-43,	-41,	-47,	-45,	-35,	-33,	-39,	-37,
+	-59,	-57,	-63,	-61,	-51,	-49,	-55,	-53,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-2,	-2,	-2,	-2,	-2,	-2,	-2,	-2,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-1,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
+	-6,	-6,	-6,	-6,	-5,	-5,	-5,	-5,
+	-8,	-8,	-8,	-8,	-7,	-7,	-7,	-7,
+	-3,	-3,	-3,	-3,	-3,	-3,	-3,	-3,
+	-4,	-4,	-4,	-4,	-4,	-4,	-4,	-4,
+	21,	20,	23,	22,	17,	16,	19,	18,
+	29,	28,	31,	30,	25,	24,	27,	26,
+	10,	10,	11,	11,	8,	8,	9,	9,
+	14,	14,	15,	15,	12,	12,	13,	13,
+	86,	82,	94,	90,	70,	66,	78,	74,
+	118,	114,	126,	122,	102,	98,	110,	106,
+	43,	41,	47,	45,	35,	33,	39,	37,
+	59,	57,	63,	61,	51,	49,	55,	53,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	1,	1,	1,	1,	1,	1,	1,	1,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	5,	5,	5,	5,	4,	4,	4,	4,
+	7,	7,	7,	7,	6,	6,	6,	6,
+	2,	2,	2,	2,	2,	2,	2,	2,
+	3,	3,	3,	3,	3,	3,	3,	3
+};
+#endif /* HAS_8BIT_TABLES */
 
     /*
      *  Visible symbols for modules
@@ -1300,14 +1811,4 @@
 EXPORT_SYMBOL(dmasound_ulaw2dma8);
 EXPORT_SYMBOL(dmasound_alaw2dma8);
 #endif
-#ifdef HAS_16BIT_TABLES
-EXPORT_SYMBOL(dmasound_ulaw2dma16);
-EXPORT_SYMBOL(dmasound_alaw2dma16);
-#endif
-#ifdef HAS_14BIT_TABLES
-EXPORT_SYMBOL(dmasound_ulaw2dma14l);
-EXPORT_SYMBOL(dmasound_ulaw2dma14h);
-EXPORT_SYMBOL(dmasound_alaw2dma14l);
-EXPORT_SYMBOL(dmasound_alaw2dma14h);
-#endif
-
+EXPORT_SYMBOL(get_afmt_string) ;
diff -Nru a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
--- a/sound/oss/dmasound/dmasound_paula.c	Thu May  9 15:21:01 2002
+++ b/sound/oss/dmasound/dmasound_paula.c	Thu May  9 15:21:01 2002
@@ -1,11 +1,18 @@
-
 /*
  *  linux/drivers/sound/dmasound/dmasound_paula.c
  *
  *  Amiga `Paula' DMA Sound Driver
  *
  *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
- */
+ *  prior to 28/01/2001
+ *
+ *  28/01/2001 [0.1] Iain Sandoe
+ *		     - added versioning
+ *		     - put in and populated the hardware_afmts field.
+ *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
+ *	       [0.3] - put in constraint on state buffer usage.
+ *	       [0.4] - put in default hard/soft settings
+*/
 
 
 #include <linux/module.h>
@@ -23,6 +30,8 @@
 
 #include "dmasound.h"
 
+#define DMASOUND_PAULA_REVISION 0
+#define DMASOUND_PAULA_EDITION 4
 
    /*
     *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)
@@ -113,8 +122,8 @@
 
 static void AmiMixerInit(void);
 static int AmiMixerIoctl(u_int cmd, u_long arg);
-static void AmiWriteSqSetup(void);
-static int AmiStateInfo(char *buffer);
+static int AmiWriteSqSetup(void);
+static int AmiStateInfo(char *buffer, size_t space);
 
 
 /*** Translations ************************************************************/
@@ -646,26 +655,44 @@
 }
 
 
-static void AmiWriteSqSetup(void)
+static int AmiWriteSqSetup(void)
 {
 	write_sq_block_size_half = write_sq.block_size>>1;
 	write_sq_block_size_quarter = write_sq_block_size_half>>1;
+	return 0;
 }
 
 
-static int AmiStateInfo(char *buffer)
+static int AmiStateInfo(char *buffer, size_t space)
 {
 	int len = 0;
 	len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
 		       dmasound.volume_left);
 	len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
 		       dmasound.volume_right);
+	if (len >= space) {
+		printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ;
+		len = space ;
+	}
 	return len;
 }
 
 
 /*** Machine definitions *****************************************************/
 
+static SETTINGS def_hard = {
+	format: AFMT_S8,
+	stereo: 0,
+	size: 8,
+	speed: 8000
+} ;
+
+static SETTINGS def_soft = {
+	format: AFMT_U8,
+	stereo: 0,
+	size: 8,
+	speed: 8000
+} ;
 
 static MACHINE machAmiga = {
 	name:		"Amiga",
@@ -688,7 +715,10 @@
 	mixer_ioctl:	AmiMixerIoctl,
 	write_sq_setup:	AmiWriteSqSetup,
 	state_info:	AmiStateInfo,
-	min_dsp_speed:	8000
+	min_dsp_speed:	8000,
+	version:	((DMASOUND_PAULA_REVISION<<8) | DMASOUND_PAULA_EDITION),
+	hardware_afmts:	(AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */
+        capabilities:   DSP_CAP_BATCH          /* As per SNDCTL_DSP_GETCAPS */
 };
 
 
@@ -704,6 +734,8 @@
 				    "dmasound [Paula]"))
 		return -EBUSY;
 	    dmasound.mach = machAmiga;
+	    dmasound.mach.default_hard = def_hard ;
+	    dmasound.mach.default_soft = def_soft ;
 	    err = dmasound_init();
 	    if (err)
 		release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
diff -Nru a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
--- a/sound/oss/dmasound/dmasound_q40.c	Thu May  9 15:21:01 2002
+++ b/sound/oss/dmasound/dmasound_q40.c	Thu May  9 15:21:01 2002
@@ -1,10 +1,16 @@
-
 /*
  *  linux/drivers/sound/dmasound/dmasound_q40.c
  *
  *  Q40 DMA Sound Driver
  *
  *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
+ *  prior to 28/01/2001
+ *
+ *  28/01/2001 [0.1] Iain Sandoe
+ *		     - added versioning
+ *		     - put in and populated the hardware_afmts field.
+ *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
+ *	       [0.3] - put in default hard/soft settings.
  */
 
 
@@ -14,10 +20,13 @@
 #include <linux/soundcard.h>
 
 #include <asm/uaccess.h>
+#include <asm/q40ints.h>
 #include <asm/q40_master.h>
 
 #include "dmasound.h"
 
+#define DMASOUND_Q40_REVISION 0
+#define DMASOUND_Q40_EDITION 3
 
 static int expand_bal;	/* Balance factor for expanding (not volume!) */
 static int expand_data;	/* Data for expanding */
@@ -48,7 +57,7 @@
 /*** Mid level stuff *********************************************************/
 
 
-#if 1
+
 /* userCount, frameUsed, frameLeft == byte counts */
 static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
 			   u_char frame[], ssize_t *frameUsed,
@@ -69,42 +78,8 @@
 	*frameUsed += used ;
 	return used;
 }
-#else
-static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
-	ssize_t count, used;
-	u_char *p = (u_char *) &frame[*frameUsed];
-	u_char val;
-	int stereo = sound.soft.stereo;
 
 
-	frameLeft >>= 1;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(size_t, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = table[data]+128;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = table[data]+128;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 2;
-	return stereo? used * 2: used;
-}
-#endif
-
-#if 1
 static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
 			  u_char frame[], ssize_t *frameUsed,
 			  ssize_t frameLeft)
@@ -123,40 +98,7 @@
 	*frameUsed += used;
 	return used;
 }
-#else
-static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_char *p = (u_char *) &frame[*frameUsed];
-	u_char val;
-	int stereo = dmasound.soft.stereo;
-
-	frameLeft >>= 1;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(size_t, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = data + 128;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = data + 128;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 2;
-	return stereo? used * 2: used;
-}
-#endif
 
-#if 1
 static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
 			  u_char frame[], ssize_t *frameUsed,
 			  ssize_t frameLeft)
@@ -170,40 +112,8 @@
 	*frameUsed += used;
 	return used;
 }
-#else
-static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	u_char *p = (u_char *) &frame[*frameUsed];
-	u_char val;
-	int stereo = dmasound.soft.stereo;
 
 
-	frameLeft >>= 1;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min_t(size_t, userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = data;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = data;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 2;
-	return stereo? used * 2: used;
-}
-#endif
-
 /* a bit too complicated to optimise right now ..*/
 static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount,
 			    u_char frame[], ssize_t *frameUsed,
@@ -216,7 +126,7 @@
 	int bal = expand_bal;
 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 	int utotal, ftotal;
- 
+
 	ftotal = frameLeft;
 	utotal = userCount;
 	while (frameLeft) {
@@ -314,6 +224,125 @@
 	return utotal;
 }
 
+/* compressing versions */
+static ssize_t q40_ctc_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
+{
+	unsigned char *table = (unsigned char *)
+		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
+	unsigned int data = expand_data;
+	u_char *p = (u_char *) &frame[*frameUsed];
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+ 
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		while(bal<0) {
+			if (userCount == 0)
+				goto lout;
+			if (!(bal<(-hSpeed))) {
+				if (get_user(c, userPtr))
+					return -EFAULT;
+				data = 0x80 + table[c];
+			}
+			userPtr++;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+ lout:
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft);
+	utotal -= userCount;
+	return utotal;
+}
+
+
+static ssize_t q40_ctc_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	u_char *p = (u_char *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		while (bal < 0) {
+			if (userCount == 0)
+				goto lout;
+			if (!(bal<(-hSpeed))) {
+				if (get_user(c, userPtr))
+					return -EFAULT;
+				data = c + 0x80;
+			}
+			userPtr++;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+ lout:
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft);
+	utotal -= userCount;
+	return utotal;
+}
+
+
+static ssize_t q40_ctc_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	u_char *p = (u_char *) &frame[*frameUsed];
+	unsigned int data = expand_data;
+	int bal = expand_bal;
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	int utotal, ftotal;
+
+	ftotal = frameLeft;
+	utotal = userCount;
+	while (frameLeft) {
+		u_char c;
+		while (bal < 0) {
+			if (userCount == 0)
+				goto lout;
+			if (!(bal<(-hSpeed))) {
+				if (get_user(c, userPtr))
+					return -EFAULT;
+				data = c ;
+			}
+			userPtr++;
+			userCount--;
+			bal += hSpeed;
+		}
+		*p++ = data;
+		frameLeft--;
+		bal -= sSpeed;
+	}
+ lout:
+	expand_bal = bal;
+	expand_data = data;
+	*frameUsed += (ftotal - frameLeft) ;
+	utotal -= userCount;
+	return utotal;
+}
+
 
 static TRANS transQ40Normal = {
 	q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
@@ -323,6 +352,10 @@
 	q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
 };
 
+static TRANS transQ40Compressing = {
+	q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL
+};
+
 
 /*** Low level stuff *********************************************************/
 
@@ -370,7 +403,7 @@
 static void Q40Silence(void)
 {
         master_outb(0,SAMPLE_ENABLE_REG);
-	*DAC_LEFT=*DAC_RIGHT=0;
+	*DAC_LEFT=*DAC_RIGHT=127;
 }
 
 static char *q40_pp=NULL;
@@ -390,7 +423,7 @@
 
 	q40_pp=start;
 	q40_sc=size;
-		
+
 	write_sq.front = (write_sq.front+1) % write_sq.max_count;
 	write_sq.active++;
 
@@ -446,7 +479,7 @@
             *DAC_LEFT=*q40_pp;
 	    *DAC_RIGHT=*q40_pp++;
 	    q40_sc --;
-	    master_outb(1,SAMPLE_CLEAR_REG);	    
+	    master_outb(1,SAMPLE_CLEAR_REG);
 	}else Q40Interrupt();
 }
 static void Q40Interrupt(void)
@@ -465,7 +498,7 @@
 	if (q40_sc<2)
 	      { /* there was nothing to play, disable irq */
 		master_outb(0,SAMPLE_ENABLE_REG);
-		*DAC_LEFT=*DAC_RIGHT=0;
+		*DAC_LEFT=*DAC_RIGHT=127;
 	      }
 	WAKE_UP(write_sq.action_queue);
 
@@ -498,10 +531,10 @@
 
 	Q40Silence();
 
-	if (dmasound.hard.speed > 20000) {
-		/* we would need to squeeze the sound, but we won't do that */
+	if (dmasound.hard.speed > 20200) {
+		/* squeeze the sound, we do that */
 		dmasound.hard.speed = 20000;
-		dmasound.trans_write = &transQ40Normal;
+		dmasound.trans_write = &transQ40Compressing;
 	} else if (dmasound.hard.speed > 10000) {
 		dmasound.hard.speed = 20000;
 	} else {
@@ -546,6 +579,19 @@
 
 /*** Machine definitions *****************************************************/
 
+static SETTINGS def_hard = {
+	format: AFMT_U8,
+	stereo: 0,
+	size: 8,
+	speed: 10000
+} ;
+
+static SETTINGS def_soft = {
+	format: AFMT_U8,
+	stereo: 0,
+	size: 8,
+	speed: 8000
+} ;
 
 static MACHINE machQ40 = {
 	name:		"Q40",
@@ -559,10 +605,14 @@
 	irqcleanup:	Q40IrqCleanUp,
 #endif /* MODULE */
 	init:		Q40Init,
-	silence:	Q40Silence, 
-	setFormat:	Q40SetFormat, 
+	silence:	Q40Silence,
+	setFormat:	Q40SetFormat,
 	setVolume:	Q40SetVolume,
-	play:		Q40Play
+	play:		Q40Play,
+ 	min_dsp_speed:	10000,
+	version:	((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION),
+	hardware_afmts:	AFMT_U8, /* h'ware-supported formats *only* here */
+        capabilities:	DSP_CAP_BATCH  /* As per SNDCTL_DSP_GETCAPS */
 };
 
 
@@ -573,6 +623,8 @@
 {
 	if (MACH_IS_Q40) {
 	    dmasound.mach = machQ40;
+	    dmasound.mach.default_hard = def_hard ;
+	    dmasound.mach.default_soft = def_soft ;
 	    return dmasound_init();
 	} else
 	    return -ENODEV;
@@ -585,4 +637,6 @@
 
 module_init(dmasound_q40_init);
 module_exit(dmasound_q40_cleanup);
+
+MODULE_DESCRIPTION("Q40/Q60 sound driver");
 MODULE_LICENSE("GPL");
