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

diff -urN linux-2.5.6-pre2/COPYING linux-2.5.6-pre3/COPYING
--- linux-2.5.6-pre2/COPYING	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/COPYING	Wed Mar  6 17:17:41 2002
@@ -307,7 +307,7 @@
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
+    Copyright (C) <year>  <name of author>
 
     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
@@ -329,7 +329,7 @@
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
diff -urN linux-2.5.6-pre2/Documentation/networking/arcnet-hardware.txt linux-2.5.6-pre3/Documentation/networking/arcnet-hardware.txt
--- linux-2.5.6-pre2/Documentation/networking/arcnet-hardware.txt	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/Documentation/networking/arcnet-hardware.txt	Wed Mar  6 17:17:42 2002
@@ -2256,7 +2256,7 @@
 When I got my two cards, one of them had this switch set to "enhanced". That
 card didn't work at all, it wasn't even recognized by the driver. The other
 card had this switch set to "compatible" and it behaved absolutely normally. I
-guess that the switch on one of the cards, must have been changed accidently
+guess that the switch on one of the cards, must have been changed accidentally
 when the card was taken out of its former host. The question remains
 unanswered, what is the purpose of the "enhanced" position?
 
diff -urN linux-2.5.6-pre2/Documentation/networking/bonding.txt linux-2.5.6-pre3/Documentation/networking/bonding.txt
--- linux-2.5.6-pre2/Documentation/networking/bonding.txt	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/Documentation/networking/bonding.txt	Wed Mar  6 17:17:43 2002
@@ -503,7 +503,7 @@
 Resources and links
 ===================
 
-Current developement on this driver is posted to:
+Current development on this driver is posted to:
  - http://www.sourceforge.net/projects/bonding/
 
 Donald Becker's Ethernet Drivers and diag programs may be found at :
diff -urN linux-2.5.6-pre2/Documentation/power/pci.txt linux-2.5.6-pre3/Documentation/power/pci.txt
--- linux-2.5.6-pre2/Documentation/power/pci.txt	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/Documentation/power/pci.txt	Wed Mar  6 17:17:43 2002
@@ -63,7 +63,7 @@
 callbacks. This currently takes place only during APM state transitions.
 
 Upon going to sleep, the PCI subsystem walks its device tree twice. Both times, it does
-a depth first walk of the device tree. The first walk saves  each of the device's state 
+a depth first walk of the device tree. The first walk saves each of the device's state 
 and checks for devices that will prevent the system from entering a global power state. 
 The next walk then places the devices in a low power state.
 
@@ -104,7 +104,7 @@
 -----------------
 
 Usage:
-	pci_restore_state(dev,buffer);
+	pci_restore_state(dev, buffer);
 
 Description:
 	Restore previously saved config space. (First 64 bytes only);
@@ -117,7 +117,7 @@
 -------------------
 
 Usage:
-	pci_set_power_state(dev,state);
+	pci_set_power_state(dev, state);
 
 Description:
 	Transition device to low power state using PCI PM Capabilities registers.
@@ -132,7 +132,7 @@
 ---------------
 
 Usage:
-	pci_enable_wake(dev,state,enable);
+	pci_enable_wake(dev, state, enable);
 
 Description:
 	Enable device to generate PME# during low power state using PCI PM 
@@ -155,7 +155,7 @@
 struct pci_driver:
 
         int  (*save_state) (struct pci_dev *dev, u32 state);
-        int  (*suspend)(struct pci_dev *dev, u32 state);
+        int  (*suspend) (struct pci_dev *dev, u32 state);
         int  (*resume) (struct pci_dev *dev);
         int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);
 
@@ -178,7 +178,7 @@
 
 The driver can also interpret this function as a notification that it may be entering
 a sleep state in the near future. If it knows that the device cannot enter the 
-requested state, either because of lack of support for it, or because the devices is 
+requested state, either because of lack of support for it, or because the device is 
 middle of some critical operation, then it should fail.
 
 This function should not be used to set any state in the device or the driver because
diff -urN linux-2.5.6-pre2/Documentation/sound/OPL3-SA2 linux-2.5.6-pre3/Documentation/sound/OPL3-SA2
--- linux-2.5.6-pre2/Documentation/sound/OPL3-SA2	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/Documentation/sound/OPL3-SA2	Wed Mar  6 17:17:43 2002
@@ -65,7 +65,7 @@
 ------------
 
 In previous kernels (2.2.x), some configuration was required to
-get the driver to talk to the card.  Being the new millenium and
+get the driver to talk to the card.  Being the new millennium and
 all, the 2.4.x kernels now support auto-configuration if ISA PnP
 support is configured in.  Theoretically, the driver even supports
 having more than one card in this case.
diff -urN linux-2.5.6-pre2/Documentation/sound/README.OSS linux-2.5.6-pre3/Documentation/sound/README.OSS
--- linux-2.5.6-pre2/Documentation/sound/README.OSS	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/Documentation/sound/README.OSS	Wed Mar  6 17:17:43 2002
@@ -542,7 +542,7 @@
 
 	SoftOSS keeps the samples loaded on the system's RAM so much RAM is
 	required. SoftOSS should never be used on machines with less than 16 MB
-	of RAM since this is potentially dangerous (you may accidently run out
+	of RAM since this is potentially dangerous (you may accidentally run out
 	of memory which probably crashes the machine). 
 
 	SoftOSS implements the wave table API originally designed for GUS. For
diff -urN linux-2.5.6-pre2/Documentation/usb/ov511.txt linux-2.5.6-pre3/Documentation/usb/ov511.txt
--- linux-2.5.6-pre2/Documentation/usb/ov511.txt	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/Documentation/usb/ov511.txt	Wed Mar  6 17:17:43 2002
@@ -182,9 +182,9 @@
   DEFAULT: 1 (Always on)
   DESC: Controls whether the LED (the little light) on the front of the camera
 	is always off (0), always on (1), or only on when driver is open (2).
-	This is only supported with the OV511+ chipset, and even then only on
-	some cameras (ones that actually have the LED wired to the control pin,
-	and not just hardwired to be on all the time).
+	This is not supported with the OV511, and might only work with certain
+	cameras (ones that actually have the LED wired to the control pin, and
+	not just hard-wired to be on all the time).
 
   NAME: dump_bridge
   TYPE: integer (Boolean)
diff -urN linux-2.5.6-pre2/MAINTAINERS linux-2.5.6-pre3/MAINTAINERS
--- linux-2.5.6-pre2/MAINTAINERS	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/MAINTAINERS	Wed Mar  6 17:17:44 2002
@@ -1606,6 +1606,12 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB EHCI DRIVER
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
 USB HID/HIDBP/INPUT DRIVERS
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
@@ -1739,6 +1745,12 @@
 W:	http://usb.in.tum.de
 S:	Maintained
 	
+USB "USBNET" DRIVER
+P:	David Brownell
+M:	dbrownell@users.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
 VFAT FILESYSTEM:
 P:	Gordon Chaffee
 M:	chaffee@cs.berkeley.edu
diff -urN linux-2.5.6-pre2/Makefile linux-2.5.6-pre3/Makefile
--- linux-2.5.6-pre2/Makefile	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/Makefile	Wed Mar  6 17:17:44 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 6
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.6-pre2/arch/alpha/defconfig linux-2.5.6-pre3/arch/alpha/defconfig
--- linux-2.5.6-pre2/arch/alpha/defconfig	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/arch/alpha/defconfig	Wed Mar  6 17:17:44 2002
@@ -237,7 +237,6 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -250,7 +249,6 @@
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
diff -urN linux-2.5.6-pre2/arch/alpha/kernel/entry.S linux-2.5.6-pre3/arch/alpha/kernel/entry.S
--- linux-2.5.6-pre2/arch/alpha/kernel/entry.S	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/alpha/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -495,7 +495,7 @@
 	ret	$31,($26),1
 .end alpha_switch_to
 
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 .globl  ret_from_fork
 .align 3
 .ent ret_from_fork
diff -urN linux-2.5.6-pre2/arch/arm/config.in linux-2.5.6-pre3/arch/arm/config.in
--- linux-2.5.6-pre2/arch/arm/config.in	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/config.in	Wed Mar  6 17:17:44 2002
@@ -682,7 +682,6 @@
 bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER
 bool 'Verbose user fault messages' CONFIG_DEBUG_USER
 bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
-dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
 
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 dep_bool '  Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL
diff -urN linux-2.5.6-pre2/arch/arm/def-configs/shannon linux-2.5.6-pre3/arch/arm/def-configs/shannon
--- linux-2.5.6-pre2/arch/arm/def-configs/shannon	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/arch/arm/def-configs/shannon	Wed Mar  6 17:17:44 2002
@@ -378,7 +378,6 @@
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
diff -urN linux-2.5.6-pre2/arch/arm/kernel/armksyms.c linux-2.5.6-pre3/arch/arm/kernel/armksyms.c
--- linux-2.5.6-pre2/arch/arm/kernel/armksyms.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/kernel/armksyms.c	Wed Mar  6 17:17:44 2002
@@ -169,10 +169,6 @@
 EXPORT_SYMBOL(__bus_to_virt);
 #endif
 
-#ifndef CONFIG_NO_PGT_CACHE
-EXPORT_SYMBOL(quicklists);
-#endif
-
 	/* string / mem functions */
 EXPORT_SYMBOL_NOVERS(strcpy);
 EXPORT_SYMBOL_NOVERS(strncpy);
diff -urN linux-2.5.6-pre2/arch/arm/kernel/process.c linux-2.5.6-pre3/arch/arm/kernel/process.c
--- linux-2.5.6-pre2/arch/arm/kernel/process.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/kernel/process.c	Wed Mar  6 17:17:44 2002
@@ -95,9 +95,6 @@
 			idle();
 		leds_event(led_idle_end);
 		schedule();
-#ifndef CONFIG_NO_PGT_CACHE
-		check_pgt_cache();
-#endif
 	}
 }
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-adifcc/mm.c linux-2.5.6-pre3/arch/arm/mach-adifcc/mm.c
--- linux-2.5.6-pre2/arch/arm/mach-adifcc/mm.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/arch/arm/mach-adifcc/mm.c	Wed Mar  6 17:17:44 2002
@@ -14,7 +14,7 @@
 
 static struct map_desc adifcc_io_desc[] __initdata = {
  /* on-board devices */
- { 0xff400000,   0x00400000,   0x00300000,   DOMAIN_IO, 1, 1, 0, 0},
+ { 0xff400000,   0x00400000,   0x00300000,   DOMAIN_IO, 0, 1, 0, 0},
  LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-anakin/mm.c linux-2.5.6-pre3/arch/arm/mach-anakin/mm.c
--- linux-2.5.6-pre2/arch/arm/mach-anakin/mm.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/arch/arm/mach-anakin/mm.c	Wed Mar  6 17:17:44 2002
@@ -20,7 +20,7 @@
 
 static struct map_desc anakin_io_desc[] __initdata = {
 	{ IO_BASE,    IO_START,    IO_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
-	{ FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 1, 1, 0, 0 },
+	{ FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
 	{ VGA_BASE,   VGA_START,   VGA_SIZE,   DOMAIN_IO, 0, 1, 0, 0 },
 	LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-arc/mm.c linux-2.5.6-pre3/arch/arm/mach-arc/mm.c
--- linux-2.5.6-pre2/arch/arm/mach-arc/mm.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/arch/arm/mach-arc/mm.c	Wed Mar  6 17:17:44 2002
@@ -78,15 +78,16 @@
 	if (!new_pmd)
 		goto no_pmd;
 
-	new_pte = pte_alloc(mm, new_pmd, 0);
+	new_pte = pte_alloc_map(mm, new_pmd, 0);
 	if (!new_pte)
 		goto no_pte;
 
 	init_pgd = pgd_offset_k(0);
 	init_pmd = pmd_offset(init_pgd, 0);
-	init_pte = pte_offset(init_pmd, 0);
-
+	init_pte = pte_offset_map_nested(init_pmd, 0);
 	set_pte(new_pte, *init_pte);
+	pte_unmap_nested(init_pte);
+	pte_unmap(new_pte);
 
 	/*
 	 * most of the page table entries are zeroed
diff -urN linux-2.5.6-pre2/arch/arm/mach-clps711x/autcpu12.c linux-2.5.6-pre3/arch/arm/mach-clps711x/autcpu12.c
--- linux-2.5.6-pre2/arch/arm/mach-clps711x/autcpu12.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/arch/arm/mach-clps711x/autcpu12.c	Wed Mar  6 17:17:44 2002
@@ -51,7 +51,7 @@
  /* virtual, physical, length, domain, r, w, c, b */
  /* memory-mapped extra io and CS8900A Ethernet chip */
  /* ethernet chip */
- 	{ AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 1, 1, 0, 0 },
+ 	{ AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 },
 	
  	LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-clps711x/edb7211-mm.c linux-2.5.6-pre3/arch/arm/mach-clps711x/edb7211-mm.c
--- linux-2.5.6-pre2/arch/arm/mach-clps711x/edb7211-mm.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/arch/arm/mach-clps711x/edb7211-mm.c	Wed Mar  6 17:17:44 2002
@@ -56,12 +56,12 @@
  /* virtual, physical, length, domain, r, w, c, b */
 
  /* memory-mapped extra keyboard row and CS8900A Ethernet chip */
- { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 1, 1, 0, 0 }, 
- { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 1, 1, 0, 0 },
+ { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 0, 1, 0, 0 }, 
+ { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 0, 1, 0, 0 },
 
  /* flash banks */
- { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 },
- { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 },
+ { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 },
+ { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 },
 
  LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/adsbitsy.c linux-2.5.6-pre3/arch/arm/mach-sa1100/adsbitsy.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/adsbitsy.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/adsbitsy.c	Wed Mar  6 17:17:44 2002
@@ -125,7 +125,7 @@
 
 static struct map_desc adsbitsy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/assabet.c linux-2.5.6-pre3/arch/arm/mach-sa1100/assabet.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/assabet.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/assabet.c	Wed Mar  6 17:17:44 2002
@@ -230,8 +230,8 @@
 
 static struct map_desc assabet_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+  { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
   /*  f3000000 - neponset system registers */
   /*  f4000000 - neponset SA1111 registers */
   LAST_DESC
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/cerf.c linux-2.5.6-pre3/arch/arm/mach-sa1100/cerf.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/cerf.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/cerf.c	Wed Mar  6 17:17:44 2002
@@ -64,11 +64,11 @@
 
 static struct map_desc cerf_io_desc[] __initdata = {
   /* virtual	 physical    length	 domain     r  w  c  b */
-  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Ethernet Chip */
+  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Crystal Ethernet Chip */
 #ifdef CONFIG_SA1100_CERF_CPLD
-  { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD Chip */
-  { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Bluetooth */
-  { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CerfPDA Serial */
+  { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Chip */
+  { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Bluetooth */
+  { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Serial */
 #endif
   LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/empeg.c linux-2.5.6-pre3/arch/arm/mach-sa1100/empeg.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/empeg.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/empeg.c	Wed Mar  6 17:17:44 2002
@@ -31,7 +31,7 @@
 
 static struct map_desc empeg_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/flexanet.c linux-2.5.6-pre3/arch/arm/mach-sa1100/flexanet.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/flexanet.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/flexanet.c	Wed Mar  6 17:17:44 2002
@@ -172,10 +172,10 @@
 
 static struct map_desc flexanet_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
-  { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Ethernet controller */
-  { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Instrument boards */
-  { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* External peripherals */
+  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Ethernet controller */
+  { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Instrument boards */
+  { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* External peripherals */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/freebird.c linux-2.5.6-pre3/arch/arm/mach-sa1100/freebird.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/freebird.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/freebird.c	Wed Mar  6 17:17:44 2002
@@ -66,8 +66,8 @@
 
 static struct map_desc freebird_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0},
+  { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
+  { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0},
    LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsclient.c linux-2.5.6-pre3/arch/arm/mach-sa1100/graphicsclient.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsclient.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/graphicsclient.c	Wed Mar  6 17:17:44 2002
@@ -32,67 +32,62 @@
  * Handlers for GraphicsClient's external IRQ logic
  */
 
-static void ADS_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+static void
+gc_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	int i;
+	unsigned int mask;
+
+	while ((mask = ADS_INT_ST1 | (ADS_INT_ST2 << 8))) {
+		/* clear the parent IRQ */
+		GEDR = GPIO_GPIO0;
+
+		irq = ADS_EXT_IRQ(0);
+		desc = irq_desc + irq;
 
-	while( (irq = ADS_INT_ST1 | (ADS_INT_ST2 << 8)) ){
-		for( i = 0; i < 16; i++ )
-			if( irq & (1<<i) )
-				do_IRQ( ADS_EXT_IRQ(i), regs );
+		do {
+			if (mask & 1)
+				desc->handle(irq, desc, regs);
+			mask >>= 1;
+			irq++;
+			desc++;
+		} while (mask);
 	}
 }
 
-static struct irqaction ADS_ext_irq = {
-	name:		"ADS_ext_IRQ",
-	handler:	ADS_IRQ_demux,
-	flags:		SA_INTERRUPT
-};
-
-static void ADS_mask_and_ack_irq0(unsigned int irq)
+static void gc_mask_irq1(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(0)));
 	ADS_INT_EN1 &= ~mask;
 	ADS_INT_ST1 = mask;
 }
 
-static void ADS_mask_irq0(unsigned int irq)
-{
-	ADS_INT_ST1 = (1 << (irq - ADS_EXT_IRQ(0)));
-}
-
-static void ADS_unmask_irq0(unsigned int irq)
+static void gc_unmask_irq1(unsigned int irq)
 {
 	ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
 }
 
-static struct irqchip ADS0_chip = {
-	ack:	ADS_mask_and_ack_irq0,
-	mask:	ADS_mask_irq0,
-	unmask:	ADS_unmask_irq0,
+static struct irqchip gc_irq1_chip = {
+	ack:	gc_mask_irq1,
+	mask:	gc_mask_irq1,
+	unmask:	gc_unmask_irq1,
 };
 
-static void ADS_mask_and_ack_irq1(unsigned int irq)
+static void gc_mask_irq2(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(8)));
 	ADS_INT_EN2 &= ~mask;
 	ADS_INT_ST2 = mask;
 }
 
-static void ADS_mask_irq1(unsigned int irq)
-{
-	ADS_INT_ST2 = (1 << (irq - ADS_EXT_IRQ(8)));
-}
-
-static void ADS_unmask_irq1(unsigned int irq)
+static void gc_unmask_irq2(unsigned int irq)
 {
 	ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
 }
 
-static struct irqchip ADS1_chip = {
-	ack:	ADS_mask_and_ack_irq1,
-	mask:	ADS_mask_irq1,
-	unmask:	ADS_unmask_irq1,
+static struct irqchip gc_irq2_chip = {
+	ack:	gc_mask_irq2,
+	mask:	gc_mask_irq2,
+	unmask:	gc_unmask_irq2,
 };
 
 static void __init graphicsclient_init_irq(void)
@@ -105,22 +100,23 @@
 	/* disable all IRQs */
 	ADS_INT_EN1 = 0;
 	ADS_INT_EN2 = 0;
+
 	/* clear all IRQs */
 	ADS_INT_ST1 = 0xff;
 	ADS_INT_ST2 = 0xff;
 
 	for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
-		set_irq_chip(irq, &ADS0_chip);
+		set_irq_chip(irq, &gc_irq1_chip);
 		set_irq_handler(irq, do_level_IRQ);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 	for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
-		set_irq_chip(irq, &ADS1_chip);
+		set_irq_chip(irq, &gc_irq2_chip);
 		set_irq_handler(irq, do_level_IRQ);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
-	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
-	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
+	set_irq_type(IRQ_GPIO0, IRQT_FALLING);
+	set_irq_chained_handler(IRQ_GPIO0, gc_irq_handler);
 }
 
 
@@ -148,111 +144,6 @@
   LAST_DESC
 };
 
-static struct gc_uart_ctrl_data_t gc_uart_ctrl_data[] = {
-  { GPIO_GC_UART0_CTS, 0, NULL,NULL },
-  { GPIO_GC_UART1_CTS, 0, NULL,NULL },
-  { GPIO_GC_UART2_CTS, 0, NULL,NULL }
-};
-
-#error Old code.  Someone needs to decide what to do with this
-#if 0 
-static void
-graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct gc_uart_ctrl_data_t * uart_data = (struct gc_uart_ctrl_data_t *)dev_id;
-	int cts = !(GPLR & uart_data->cts_gpio);
-
-	/* NOTE: I supose that we will no get any interrupt
-	   if the GPIO is not changed, so maybe
-	   the cts_prev_state can be removed ... */
-	if (cts != uart_data->cts_prev_state) {
-		uart_data->cts_prev_state = cts;
-
-		uart_handle_cts_change(uart_data->info, cts);
-	}
-}
-
-static int
-graphicsclient_register_cts_intr(int gpio, int irq,
-				 struct gc_uart_ctrl_data_t *uart_data)
-{
-	int ret = 0;
-
-	set_GPIO_IRQ_edge(gpio, GPIO_BOTH_EDGES);
-
-	ret = request_irq(irq, graphicsclient_cts_intr,
-			  0, "GC RS232 CTS", uart_data);
-	if (ret) {
-		printk(KERN_ERR "uart_open: failed to register CTS irq (%d)\n",
-		       ret);
-		free_irq(irq, uart_data);
-	}
-
-	return ret;
-}
-
-static int
-graphicsclient_uart_open(struct uart_port *port, struct uart_info *info)
-{
-	int ret = 0;
-
-	if (port->mapbase == _Ser1UTCR0) {
-		Ser1SDCR0 |= SDCR0_UART;
-		/* Set RTS Output */
-		GPSR  = GPIO_GC_UART0_RTS;
-
-		gc_uart_ctrl_data[0].cts_prev_state = 0;
-		gc_uart_ctrl_data[0].info = info;
-		gc_uart_ctrl_data[0].port = port;
-
-		/* register uart0 CTS irq */
-		ret = graphicsclient_register_cts_intr(GPIO_GC_UART0_CTS,
-							IRQ_GC_UART0_CTS,
-							&gc_uart_ctrl_data[0]);
-	} else if (port->mapbase == _Ser2UTCR0) {
-		Ser2UTCR4 = Ser2HSCR0 = 0;
-		/* Set RTS Output */
-		GPSR  = GPIO_GC_UART1_RTS;
-
-		gc_uart_ctrl_data[1].cts_prev_state = 0;
-		gc_uart_ctrl_data[1].info = info;
-		gc_uart_ctrl_data[1].port = port;
-
-		/* register uart1 CTS irq */
-		ret = graphicsclient_register_cts_intr(GPIO_GC_UART1_CTS,
-							IRQ_GC_UART1_CTS,
-							&gc_uart_ctrl_data[1]);
-	} else if (port->mapbase == _Ser3UTCR0) {
-		/* Set RTS Output */
-		GPSR =	GPIO_GC_UART2_RTS;
-
-		gc_uart_ctrl_data[2].cts_prev_state = 0;
-		gc_uart_ctrl_data[2].info = info;
-		gc_uart_ctrl_data[2].port = port;
-
-		/* register uart2 CTS irq */
-		ret = graphicsclient_register_cts_intr(GPIO_GC_UART2_CTS,
-							IRQ_GC_UART2_CTS,
-							&gc_uart_ctrl_data[2]);
-	}
-	return ret;
-}
-
-static int
-graphicsclient_uart_close(struct uart_port *port, struct uart_info *info)
-{
-	if (port->mapbase == _Ser1UTCR0) {
-		free_irq(IRQ_GC_UART0_CTS, &gc_uart_ctrl_data[0]);
-	} else if (port->mapbase == _Ser2UTCR0) {
-		free_irq(IRQ_GC_UART1_CTS, &gc_uart_ctrl_data[1]);
-	} else if (port->mapbase == _Ser3UTCR0) {
-		free_irq(IRQ_GC_UART2_CTS, &gc_uart_ctrl_data[2]);
-	}
-
-	return 0;
-}
-#endif
-
 static u_int graphicsclient_get_mctrl(struct uart_port *port)
 {
 	u_int result = TIOCM_CD | TIOCM_DSR;
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsmaster.c linux-2.5.6-pre3/arch/arm/mach-sa1100/graphicsmaster.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsmaster.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/graphicsmaster.c	Wed Mar  6 17:17:44 2002
@@ -93,68 +93,62 @@
  * Handlers for GraphicsMaster's external IRQ logic
  */
 
-static void ADS_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+static void
+gm_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	int i;
+	unsigned int mask;
 
-	while( (irq = ADS_INT_ST1 | (ADS_INT_ST2 << 8)) ){
-		for( i = 0; i < 16; i++ )
-			if( irq & (1<<i) ) {
-				do_IRQ( ADS_EXT_IRQ(i), regs );
-			}
+	while ((mask = ADS_INT_ST1 | (ADS_INT_ST2 << 8))) {
+		/* clear the parent IRQ */
+		GEDR = GPIO_GPIO0;
+
+		irq = ADS_EXT_IRQ(0);
+		desc = irq_desc + irq;
+
+		do {
+			if (mask & 1)
+				desc->handle(irq, desc, regs);
+			mask >>= 1;
+			irq++;
+			desc++;
+		} while (mask);
 	}
 }
 
-static struct irqaction ADS_ext_irq = {
-	name:		"ADS_ext_IRQ",
-	handler:	ADS_IRQ_demux,
-	flags:		SA_INTERRUPT
-};
-
-static void ADS_mask_and_ack_irq0(unsigned int irq)
+static void gm_mask_irq1(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(0)));
 	ADS_INT_EN1 &= ~mask;
 	ADS_INT_ST1 = mask;
 }
 
-static void ADS_mask_irq0(unsigned int irq)
-{
-	ADS_INT_ST1 = (1 << (irq - ADS_EXT_IRQ(0)));
-}
-
-static void ADS_unmask_irq0(unsigned int irq)
+static void gm_unmask_irq1(unsigned int irq)
 {
 	ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
 }
 
-static struct irqchip ADS0_chip = {
-	ack:	ADS_mask_and_ack_irq0,
-	mask:	ADS_mask_irq0,
-	unmask:	ADS_unmask_irq0,
+static struct irqchip gm_irq1_chip = {
+	ack:	gm_mask_irq1,
+	mask:	gm_mask_irq1,
+	unmask:	gm_unmask_irq1,
 };
 
-static void ADS_mask_and_ack_irq1(unsigned int irq)
+static void gm_mask_irq2(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(8)));
 	ADS_INT_EN2 &= ~mask;
 	ADS_INT_ST2 = mask;
 }
 
-static void ADS_mask_irq1(unsigned int irq)
-{
-	ADS_INT_ST2 = (1 << (irq - ADS_EXT_IRQ(8)));
-}
-
-static void ADS_unmask_irq1(unsigned int irq)
+static void gm_unmask_irq2(unsigned int irq)
 {
 	ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
 }
 
-static struct irqchip ADS1_chip = {
-	ack:	ADS_mask_irq1,
-	mask:	ADS_mask_irq1,
-	unmask:	ADS_mask_irq1,
+static struct irqchip gm_irq2_chip = {
+	ack:	gm_mask_irq2,
+	mask:	gm_mask_irq2,
+	unmask:	gm_unmask_irq2,
 };
 
 static void __init graphicsmaster_init_irq(void)
@@ -167,22 +161,23 @@
 	/* disable all IRQs */
 	ADS_INT_EN1 = 0;
 	ADS_INT_EN2 = 0;
+
 	/* clear all IRQs */
 	ADS_INT_ST1 = 0xff;
 	ADS_INT_ST2 = 0xff;
 
 	for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
-		set_irq_chip(irq, &ADS0_chip);
+		set_irq_chip(irq, &gm_irq1_chip);
 		set_irq_handler(irq, do_level_IRQ);
 		set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
 	}
 	for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
-		set_irq_chip(irq, &ADS1_chip);
+		set_irq_chip(irq, &gm_irq2_chip);
 		set_irq_handler(irq, do_level_IRQ);
 		set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
 	}
-	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
-	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
+	set_irq_type(IRQ_GPIO0, IRQT_FALLING);
+	set_irq_chained_handler(IRQ_GPIO0, gm_irq_handler);
 }
 
 
@@ -206,9 +201,9 @@
 
 static struct map_desc graphicsmaster_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */
-  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
+  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/h3600.c linux-2.5.6-pre3/arch/arm/mach-sa1100/h3600.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/h3600.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/h3600.c	Wed Mar  6 17:17:44 2002
@@ -489,9 +489,9 @@
 
 static struct map_desc h3600_io_desc[] __initdata = {
  /* virtual	       physical    length      domain	  r  w	c  b */
-  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0		 CS#5 */
-  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2  CS#2 */
-  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4  CS#4 */
+  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0		 CS#5 */
+  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2  CS#2 */
+  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4  CS#4 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/huw_webpanel.c linux-2.5.6-pre3/arch/arm/mach-sa1100/huw_webpanel.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/huw_webpanel.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/huw_webpanel.c	Wed Mar  6 17:17:44 2002
@@ -77,7 +77,7 @@
 **/
 static struct map_desc huw_webpanel_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 1, 1, 0, 0 }, /* Parameter */
+  { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 0, 1, 0, 0 }, /* Parameter */
   { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
   LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/itsy.c linux-2.5.6-pre3/arch/arm/mach-sa1100/itsy.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/itsy.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/itsy.c	Wed Mar  6 17:17:44 2002
@@ -31,8 +31,8 @@
    likely wrong. */
 static struct map_desc itsy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/jornada720.c linux-2.5.6-pre3/arch/arm/mach-sa1100/jornada720.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/jornada720.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/jornada720.c	Wed Mar  6 17:17:44 2002
@@ -66,9 +66,9 @@
 
 static struct map_desc jornada720_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson registers */
-  { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson frame buffer */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson registers */
+  { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson frame buffer */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/lart.c linux-2.5.6-pre3/arch/arm/mach-sa1100/lart.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/lart.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/lart.c	Wed Mar  6 17:17:44 2002
@@ -18,8 +18,8 @@
 
 static struct map_desc lart_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
-  { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */
+  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
+  { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/nanoengine.c linux-2.5.6-pre3/arch/arm/mach-sa1100/nanoengine.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/nanoengine.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/nanoengine.c	Wed Mar  6 17:17:44 2002
@@ -34,9 +34,9 @@
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
-  { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Internal PCI Config Space */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/neponset.c linux-2.5.6-pre3/arch/arm/mach-sa1100/neponset.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/neponset.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/neponset.c	Wed Mar  6 17:17:44 2002
@@ -184,8 +184,8 @@
 
 static struct map_desc neponset_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/omnimeter.c linux-2.5.6-pre3/arch/arm/mach-sa1100/omnimeter.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/omnimeter.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/omnimeter.c	Wed Mar  6 17:17:44 2002
@@ -54,7 +54,7 @@
 
 static struct map_desc omnimeter_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* TS */
+  { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* TS */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/pangolin.c linux-2.5.6-pre3/arch/arm/mach-sa1100/pangolin.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/pangolin.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/pangolin.c	Wed Mar  6 17:17:44 2002
@@ -30,7 +30,7 @@
 
 static struct map_desc pangolin_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/pfs168.c linux-2.5.6-pre3/arch/arm/mach-sa1100/pfs168.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/pfs168.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/pfs168.c	Wed Mar  6 17:17:44 2002
@@ -103,20 +103,20 @@
 
 static struct map_desc pfs168_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */
-  { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */
-  { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */
-  { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Status LED control (SYSLED) */
-  { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */
-  { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */
-  { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */
-  { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */
-  { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register A (SYSCTLA) */
-  { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Control register B (SYSCTLB) */
-  { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* SMC91C96 */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */
+  { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */
+  { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */
+  { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Status LED control (SYSLED) */
+  { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */
+  { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */
+  { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */
+  { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */
+  { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register A (SYSCTLA) */
+  { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register B (SYSCTLB) */
+  { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* SMC91C96 */
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
+  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/pleb.c linux-2.5.6-pre3/arch/arm/mach-sa1100/pleb.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/pleb.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/pleb.c	Wed Mar  6 17:17:44 2002
@@ -35,8 +35,8 @@
 
 static struct map_desc pleb_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
-  { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */
+  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
+  { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/simpad.c linux-2.5.6-pre3/arch/arm/mach-sa1100/simpad.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/simpad.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/simpad.c	Wed Mar  6 17:17:44 2002
@@ -58,7 +58,7 @@
 
 static struct map_desc simpad_io_desc[] __initdata = {
   /* virtual	physical    length	domain	   r  w  c  b */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */  
+  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */  
   { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
   LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/stork.c linux-2.5.6-pre3/arch/arm/mach-sa1100/stork.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/stork.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/stork.c	Wed Mar  6 17:17:44 2002
@@ -305,10 +305,10 @@
 
 struct map_desc stork_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
-  { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
-  { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2 */
+  { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/system3.c linux-2.5.6-pre3/arch/arm/mach-sa1100/system3.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/system3.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/system3.c	Wed Mar  6 17:17:44 2002
@@ -58,6 +58,7 @@
 
 #include "generic.h"
 #include "sa1111.h"
+#include <asm/hardware/sa1111.h>
 
 #define DEBUG 1
 
@@ -74,19 +75,17 @@
 /* init funcs */
 static void __init fixup_system3(struct machine_desc *desc,
 		struct param_struct *params, char **cmdline, struct meminfo *mi);
-static void __init get_system3_scr(void);
 static int __init system3_init(void);
 static void __init system3_init_irq(void);
 static void __init system3_map_io(void);
 
-static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs );
-static int system3_get_mctrl(struct uart_port *port);
+static u_int system3_get_mctrl(struct uart_port *port);
 static void system3_set_mctrl(struct uart_port *port, u_int mctrl);
 static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate);
 static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data);
 
-static int system3_lcd_power(int on);
-static int system3_backlight_power(int on);
+static void system3_lcd_power(int on);
+static void system3_backlight_power(int on);
 
 extern void convert_to_tag_list(struct param_struct *params, int mem_init);
 
@@ -101,9 +100,9 @@
 
 static struct map_desc system3_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xe8000000, 0x00000000,		0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf3000000, PT_CPLD_BASE,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
+  { 0xf4000000, PT_SA1111_BASE,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
@@ -113,12 +112,6 @@
 	pm:		system3_uart_pm,
 };
 
-static struct irqaction system3_irq = {
-	name:		"PT Digital Board SA1111 IRQ",
-	handler:	system3_IRQ_demux,
-	flags:		SA_INTERRUPT
-};
-
 static struct notifier_block system3_clkchg_block = {
 	notifier_call:	sdram_notifier,
 };
@@ -145,56 +138,82 @@
 /*********************************************************************
  * Install IRQ handler
  */
-static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+static void
+system3_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
 	u_char irr;
 
-	for(;;){
-		//irr = PTCPLD_REG_IRQSR & (PT_IRQ_LAN | PT_IRQ_USAR | PT_IRQ_SA1111);
-		irr = PT_IRQSR & (PT_IRQ_LAN | PT_IRQ_SA1111);
-
-		irr ^= (PT_IRQ_LAN);
-		if (!irr) break;
-
-		if( irr & PT_IRQ_LAN )
-			do_IRQ(IRQ_SYSTEM3_SMC9196, regs);
-
-#if 0
-		/* Highspeed Serial Bus not yet used */
-		if( irr & PT_IRQ_USAR )
-			do_IRQ(PT_USAR_IRQ, regs);
-#endif
+	//DPRINTK( "irq=%d, desc=%p, regs=%p\n", irq, desc, regs );
 
-		if( irr & PT_IRQ_SA1111 )
-			sa1111_IRQ_demux(irq, dev_id, regs);
-	}
-}
+	while (1) {
+		struct irqdesc *d;
 
+		/*
+		 * Acknowledge the parent IRQ.
+		 */
+		desc->chip->ack(irq);
+
+		/*
+		 * Read the interrupt reason register.  Let's have all
+		 * active IRQ bits high.  Note: there is a typo in the
+		 * Neponset user's guide for the SA1111 IRR level.
+		 */
+		//irr = PT_IRQSR & (PT_IRR_LAN | PT_IRR_SA1111);
+		irr = PT_IRQSR & (PT_IRR_SA1111);
 
-static void __init system3_init_irq(void)
-{
-	int irq;
+		/* SMC IRQ is low-active, so "switch" bit over */
+		//irr ^= (PT_IRR_LAN);
 
-	DPRINTK( "%s\n", "START" );
+		//DPRINTK( "irr=0x%02x\n", irr );
 
-	/* SA1111 IRQ not routed to a GPIO. */
-	sa1111_init_irq(-1);
+		if ((irr & (PT_IRR_LAN | PT_IRR_SA1111)) == 0)
+			break;
 
-	/* setup extra IRQs */
-	irq = IRQ_SYSTEM3_SMC9196;
-	irq_desc[irq].valid	= 1;
-	irq_desc[irq].probe_ok	= 1;
-
-#if 0
-	/* Highspeed Serial Bus not yet used */
-	irq = PT_USAR_IRQ;
-	irq_desc[irq].valid	= 1;
-	irq_desc[irq].probe_ok	= 1;
+		/*
+		 * Since there is no individual mask, we have to
+		 * mask the parent IRQ.  This is safe, since we'll
+		 * recheck the register for any pending IRQs.
+		 */
+		if (irr & (PT_IRR_LAN)) {
+			desc->chip->mask(irq);
+
+			if (irr & PT_IRR_LAN) {
+				//DPRINTK( "SMC9196, irq=%d\n", IRQ_SYSTEM3_SMC9196 );
+				d = irq_desc + IRQ_SYSTEM3_SMC9196;
+				d->handle(IRQ_SYSTEM3_SMC9196, d, regs);
+			}
+
+#if 0 /* no SSP yet on system 4 */
+			if (irr & IRR_USAR) {
+				d = irq_desc + IRQ_NEPONSET_USAR;
+				d->handle(IRQ_NEPONSET_USAR, d, regs);
+			}
 #endif
 
-	/* IRQ by CPLD */
-	set_GPIO_IRQ_edge( GPIO_GPIO(25), GPIO_RISING_EDGE );
-	setup_arm_irq( IRQ_GPIO25, &system3_irq );
+			desc->chip->unmask(irq);
+		}
+
+		if (irr & PT_IRR_SA1111) {
+			//DPRINTK( "SA1111, irq=%d\n", IRQ_SYSTEM3_SA1111 );
+			d = irq_desc + IRQ_SYSTEM3_SA1111;
+			d->handle(IRQ_SYSTEM3_SA1111, d, regs);
+		}
+	}
+}
+
+static void __init system3_init_irq(void)
+{
+	/*
+	 * Install handler for GPIO25.
+	 */
+	set_irq_type(IRQ_GPIO25, IRQT_RISING);
+	set_irq_chained_handler(IRQ_GPIO25, system3_irq_handler);
+
+	/*
+	 * install eth irq
+	 */
+	set_irq_handler(IRQ_SYSTEM3_SMC9196, do_simple_IRQ);
+	set_irq_flags(IRQ_SYSTEM3_SMC9196, IRQF_VALID | IRQF_PROBE);
 }
 
 /**********************************************************************
@@ -270,7 +289,7 @@
 	}
 }
 
-static int system3_get_mctrl(struct uart_port *port)
+static u_int system3_get_mctrl(struct uart_port *port)
 {
 	u_int ret = 0;
 	u_int irqsr = PT_IRQSR;
@@ -358,12 +377,8 @@
 
 static void system3_lcd_power(int on)
 {
-#error why is backlight stuff here???
 	if (on) {
 		system3_lcd_on();
-		system3_lcd_backlight_on();
-		system3_lcd_contrast(0x95);
-		system3_lcd_brightness(240);
 	} else {
 		system3_lcd_off();
 	}
@@ -407,10 +422,12 @@
 	 */
 	sa1110_mb_disable();
 
+	system3_init_irq();
+
 	/*
 	 * Probe for a SA1111.
 	 */
-	ret = sa1111_probe(0x40000000);
+	ret = sa1111_probe(PT_SA1111_BASE);
 	if (ret < 0) {
 		printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
 		goto DONE;
@@ -443,7 +460,11 @@
 	 */
 	sa1110_mb_enable();
 
-	system3_init_irq();
+	/*
+	 * Initialise SA1111 IRQs
+	 */
+	sa1111_init_irq(IRQ_SYSTEM3_SA1111);
+
 
 #if defined( CONFIG_CPU_FREQ )
 	ret = cpufreq_register_notifier(&system3_clkchg_block);
@@ -453,6 +474,7 @@
 	}
 #endif
 
+
 	ret = 0;
 DONE:
 	DPRINTK( "ret=%d\n", ret );
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/victor.c linux-2.5.6-pre3/arch/arm/mach-sa1100/victor.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/victor.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/victor.c	Wed Mar  6 17:17:44 2002
@@ -60,7 +60,7 @@
 
 static struct map_desc victor_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+  { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/xp860.c linux-2.5.6-pre3/arch/arm/mach-sa1100/xp860.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/xp860.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/xp860.c	Wed Mar  6 17:17:44 2002
@@ -67,9 +67,9 @@
 
 static struct map_desc xp860_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */
-  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */
-  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCSI */
+  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN */
+  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
   LAST_DESC
 };
 
diff -urN linux-2.5.6-pre2/arch/arm/mach-sa1100/yopy.c linux-2.5.6-pre3/arch/arm/mach-sa1100/yopy.c
--- linux-2.5.6-pre2/arch/arm/mach-sa1100/yopy.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mach-sa1100/yopy.c	Wed Mar  6 17:17:44 2002
@@ -69,9 +69,9 @@
 
 static struct map_desc yopy_io_desc[] __initdata = {
  /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 0 */
-  { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash 1 */
-  { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0 }, /* LCD */
+  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 0 */
+  { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 1 */
+  { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
   { 0xf1000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO */
   LAST_DESC
 };
diff -urN linux-2.5.6-pre2/arch/arm/mm/fault-armv.c linux-2.5.6-pre3/arch/arm/mm/fault-armv.c
--- linux-2.5.6-pre2/arch/arm/mm/fault-armv.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mm/fault-armv.c	Wed Mar  6 17:17:44 2002
@@ -151,7 +151,7 @@
 	if (pmd_bad(*pmd))
 		goto bad_pmd;
 
-	pte = pte_offset(pmd, address);
+	pte = pte_offset_map(pmd, address);
 	entry = *pte;
 
 	/*
@@ -164,6 +164,7 @@
 		set_pte(pte, entry);
 		flush_tlb_page(vma, address);
 	}
+	pte_unmap(pte);
 	return;
 
 bad_pgd:
diff -urN linux-2.5.6-pre2/arch/arm/mm/fault-common.c linux-2.5.6-pre3/arch/arm/mm/fault-common.c
--- linux-2.5.6-pre2/arch/arm/mm/fault-common.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mm/fault-common.c	Wed Mar  6 17:17:44 2002
@@ -83,11 +83,15 @@
 			break;
 		}
 
-		pte = pte_offset(pmd, addr);
+#ifndef CONFIG_HIGHMEM
+		/* We must not map this if we have highmem enabled */
+		pte = pte_offset_map(pmd, addr);
 		printk(", *pte = %08lx", pte_val(*pte));
 #ifdef CONFIG_CPU_32
 		printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
 #endif
+		pte_unmap(pte);
+#endif
 	} while(0);
 
 	printk("\n");
diff -urN linux-2.5.6-pre2/arch/arm/mm/init.c linux-2.5.6-pre3/arch/arm/mm/init.c
--- linux-2.5.6-pre2/arch/arm/mm/init.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/arch/arm/mm/init.c	Wed Mar  6 17:17:44 2002
@@ -64,38 +64,6 @@
  */
 struct page *empty_zero_page;
 
-#ifndef CONFIG_NO_PGT_CACHE
-struct pgtable_cache_struct quicklists;
-
-int do_check_pgt_cache(int low, int high)
-{
-	int freed = 0;
-
-	if(pgtable_cache_size > high) {
-		do {
-			if(pgd_quicklist) {
-				free_pgd_slow(get_pgd_fast());
-				freed++;
-			}
-			if(pmd_quicklist) {
-				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-			if(pte_quicklist) {
-				pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-		} while(pgtable_cache_size > low);
-	}
-	return freed;
-}
-#else
-int do_check_pgt_cache(int low, int high)
-{
-	return 0;
-}
-#endif
-
 /* This is currently broken
  * PG_skip is used on sparc/sparc64 architectures to "skip" certain
  * parts of the address space.
@@ -145,9 +113,6 @@
 	printk("%d slab pages\n", slab);
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
-#ifndef CONFIG_NO_PGT_CACHE
-	printk("%ld page tables cached\n", pgtable_cache_size);
-#endif
 	show_buffers();
 }
 
diff -urN linux-2.5.6-pre2/arch/arm/mm/minicache.c linux-2.5.6-pre3/arch/arm/mm/minicache.c
--- linux-2.5.6-pre2/arch/arm/mm/minicache.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mm/minicache.c	Wed Mar  6 17:17:44 2002
@@ -58,7 +58,7 @@
 	pmd = pmd_alloc(&init_mm, pgd, minicache_address);
 	if (!pmd)
 		BUG();
-	minicache_pte = pte_alloc(&init_mm, pmd, minicache_address);
+	minicache_pte = pte_alloc_kernel(&init_mm, pmd, minicache_address);
 	if (!minicache_pte)
 		BUG();
 
diff -urN linux-2.5.6-pre2/arch/arm/mm/mm-armv.c linux-2.5.6-pre3/arch/arm/mm/mm-armv.c
--- linux-2.5.6-pre2/arch/arm/mm/mm-armv.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/arch/arm/mm/mm-armv.c	Wed Mar  6 17:17:44 2002
@@ -98,11 +98,15 @@
 		if (!new_pmd)
 			goto no_pmd;
 
-		new_pte = pte_alloc(mm, new_pmd, 0);
+		new_pte = pte_alloc_map(mm, new_pmd, 0);
 		if (!new_pte)
 			goto no_pte;
 
+		init_pmd = pmd_offset(init_pgd, 0);
+		init_pte = pte_offset_map_nested(init_pmd, 0);
 		set_pte(new_pte, *init_pte);
+		pte_unmap_nested(init_pte);
+		pte_unmap(new_pte);
 
 		spin_unlock(&mm->page_table_lock);
 	}
@@ -138,7 +142,7 @@
 void free_pgd_slow(pgd_t *pgd)
 {
 	pmd_t *pmd;
-	pte_t *pte;
+	struct page *pte;
 
 	if (!pgd)
 		return;
@@ -153,7 +157,7 @@
 		goto free;
 	}
 
-	pte = pte_offset(pmd, 0);
+	pte = pmd_page(*pmd);
 	pmd_clear(pmd);
 	pte_free(pte);
 	pmd_free(pmd);
@@ -198,7 +202,7 @@
 
 		set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
 	}
-	ptep = pte_offset(pmdp, virt);
+	ptep = pte_offset_kernel(pmdp, virt);
 
 	set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
 }
@@ -225,6 +229,20 @@
 	int prot_sect, prot_pte;
 	long off;
 
+	if (md->prot_read && md->prot_write &&
+	    !md->cacheable && !md->bufferable) {
+		printk(KERN_WARNING "Security risk: creating user "
+		       "accessible mapping for 0x%08lx at 0x%08lx\n",
+		       md->physical, md->virtual);
+	}
+
+	if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) {
+		printk(KERN_WARNING "MM: not creating mapping for "
+		       "0x%08lx at 0x%08lx in user region\n",
+		       md->physical, md->virtual);
+		return;
+	}
+
 	prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
 		   (md->prot_read  ? L_PTE_USER       : 0) |
 		   (md->prot_write ? L_PTE_WRITE      : 0) |
diff -urN linux-2.5.6-pre2/arch/arm/mm/proc-xscale.S linux-2.5.6-pre3/arch/arm/mm/proc-xscale.S
--- linux-2.5.6-pre2/arch/arm/mm/proc-xscale.S	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/arm/mm/proc-xscale.S	Wed Mar  6 17:17:44 2002
@@ -663,8 +663,8 @@
 cpu_80200_name:
 	.asciz	"XScale-80200"
 
-cpu_cotulla_name:
-	.asciz	"XScale-Cotulla"
+cpu_pxa250_name:
+	.asciz	"XScale-PXA250"
 
 	.align
 
@@ -734,11 +734,11 @@
 	.long	cpu_80200_name
 	.size	cpu_80200_info, . - cpu_80200_info
 
-	.type	cpu_cotulla_info, #object
-cpu_cotulla_info:
+	.type	cpu_pxa250_info, #object
+cpu_pxa250_info:
 	.long	cpu_manu_name
-	.long	cpu_cotulla_name
-	.size	cpu_cotulla_info, . - cpu_cotulla_info
+	.long	cpu_pxa250_name
+	.size	cpu_pxa250_info, . - cpu_pxa250_info
 
 	.type	cpu_arch_name, #object
 cpu_arch_name:
@@ -767,8 +767,8 @@
 	.long	v4wbi_tlb_fns
 	.size	__80200_proc_info, . - __80200_proc_info
 
-	.type	__cotulla_proc_info,#object
-__cotulla_proc_info:
+	.type	__pxa250_proc_info,#object
+__pxa250_proc_info:
 	.long	0x69052100
 	.long	0xfffffff0
 	.long	0x00000c0e
@@ -776,8 +776,9 @@
 	.long	cpu_arch_name
 	.long	cpu_elf_name
 	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
-	.long	cpu_cotulla_info
+	.long	cpu_pxa250_info
 	.long	xscale_processor_functions
 	.long	v4wbi_tlb_fns
 	.size	__cotulla_proc_info, . - __cotulla_proc_info
+	.size	__pxa250_proc_info, . - __pxa250_proc_info
 
diff -urN linux-2.5.6-pre2/arch/cris/drivers/ide.c linux-2.5.6-pre3/arch/cris/drivers/ide.c
--- linux-2.5.6-pre2/arch/cris/drivers/ide.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/cris/drivers/ide.c	Wed Mar  6 17:17:44 2002
@@ -94,8 +94,6 @@
  * device can't do DMA handshaking for some stupid reason. We don't need to do that.
  */ 
 
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -urN linux-2.5.6-pre2/arch/i386/defconfig linux-2.5.6-pre3/arch/i386/defconfig
--- linux-2.5.6-pre2/arch/i386/defconfig	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/i386/defconfig	Wed Mar  6 17:17:44 2002
@@ -98,6 +98,7 @@
 # CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
+# CONFIG_PCMCIA_SA1100 is not set
 
 #
 # PCI Hotplug Support
@@ -239,10 +240,9 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-CONFIG_IDE_TASK_IOCTL=y
 
 #
-# IDE chipset support/bugfixes
+# IDE chipset support
 #
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
@@ -252,7 +252,6 @@
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
@@ -656,6 +655,9 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
diff -urN linux-2.5.6-pre2/arch/i386/kernel/entry.S linux-2.5.6-pre3/arch/i386/kernel/entry.S
--- linux-2.5.6-pre2/arch/i386/kernel/entry.S	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/arch/i386/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -195,7 +195,7 @@
 
 
 ENTRY(ret_from_fork)
-#if CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 	call SYMBOL_NAME(schedule_tail)
 #endif
 	GET_THREAD_INFO(%ebx)
@@ -716,6 +716,7 @@
 	.long SYMBOL_NAME(sys_lremovexattr)
 	.long SYMBOL_NAME(sys_fremovexattr)
 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_sendfile64)
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.5.6-pre2/arch/i386/kernel/io_apic.c linux-2.5.6-pre3/arch/i386/kernel/io_apic.c
--- linux-2.5.6-pre2/arch/i386/kernel/io_apic.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/i386/kernel/io_apic.c	Wed Mar  6 17:17:44 2002
@@ -67,7 +67,7 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int apic, int pin)
+static void __init add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
 	static int first_free_entry = NR_IRQS;
 	struct irq_pin_list *entry = irq_2_pin + irq;
@@ -85,6 +85,26 @@
 	entry->pin = pin;
 }
 
+/*
+ * Reroute an IRQ to a different pin.
+ */
+static void __init replace_pin_at_irq(unsigned int irq,
+				      int oldapic, int oldpin,
+				      int newapic, int newpin)
+{
+	struct irq_pin_list *entry = irq_2_pin + irq;
+
+	while (1) {
+		if (entry->apic == oldapic && entry->pin == oldpin) {
+			entry->apic = newapic;
+			entry->pin = newpin;
+		}
+		if (!entry->next)
+			break;
+		entry = irq_2_pin + entry->next;
+	}
+}
+
 #define __DO_ACTION(R, ACTION, FINAL)					\
 									\
 {									\
@@ -1533,6 +1553,10 @@
 		setup_ExtINT_IRQ0_pin(pin2, vector);
 		if (timer_irq_works()) {
 			printk("works.\n");
+			if (pin1 != -1)
+				replace_pin_at_irq(0, 0, pin1, 0, pin2);
+			else
+				add_pin_to_irq(0, 0, pin2);
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
 				check_nmi_watchdog();
diff -urN linux-2.5.6-pre2/arch/i386/kernel/smpboot.c linux-2.5.6-pre3/arch/i386/kernel/smpboot.c
--- linux-2.5.6-pre2/arch/i386/kernel/smpboot.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/arch/i386/kernel/smpboot.c	Wed Mar  6 17:17:44 2002
@@ -240,7 +240,7 @@
  *		    ^---- (this multiplication can overflow)
  */
 
-static unsigned long long div64 (unsigned long long a, unsigned long b0)
+static unsigned long long __init div64 (unsigned long long a, unsigned long b0)
 {
 	unsigned int a1, a2;
 	unsigned long long res;
diff -urN linux-2.5.6-pre2/arch/i386/vmlinux.lds linux-2.5.6-pre3/arch/i386/vmlinux.lds
--- linux-2.5.6-pre2/arch/i386/vmlinux.lds	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/i386/vmlinux.lds	Wed Mar  6 17:17:44 2002
@@ -57,6 +57,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -urN linux-2.5.6-pre2/arch/ia64/sn/io/pci_bus_cvlink.c linux-2.5.6-pre3/arch/ia64/sn/io/pci_bus_cvlink.c
--- linux-2.5.6-pre2/arch/ia64/sn/io/pci_bus_cvlink.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/arch/ia64/sn/io/pci_bus_cvlink.c	Wed Mar  6 17:17:44 2002
@@ -112,9 +112,9 @@
 	pci_bus = pci_bus_to_vertex(busnum);
 	if (!pci_bus) {
 		/*
-		 * During probing, the Linux pci code invents non existant
+		 * During probing, the Linux pci code invents non-existent
 		 * bus numbers and pci_dev structures and tries to access
-		 * them to determine existance. Don't crib during probing.
+		 * them to determine existence. Don't crib during probing.
 		 */
 		if (done_probing)
 			printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum);
diff -urN linux-2.5.6-pre2/arch/ppc/boot/ld.script linux-2.5.6-pre3/arch/ppc/boot/ld.script
--- linux-2.5.6-pre2/arch/ppc/boot/ld.script	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/arch/ppc/boot/ld.script	Wed Mar  6 17:17:44 2002
@@ -44,6 +44,7 @@
   {
     *(.data)
     *(.data1)
+    *(.data.boot)
     *(.sdata)
     *(.sdata2)
     *(.got.plt) *(.got)
diff -urN linux-2.5.6-pre2/arch/ppc/boot/simple/misc-embedded.c linux-2.5.6-pre3/arch/ppc/boot/simple/misc-embedded.c
--- linux-2.5.6-pre2/arch/ppc/boot/simple/misc-embedded.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/arch/ppc/boot/simple/misc-embedded.c	Wed Mar  6 17:17:44 2002
@@ -59,7 +59,9 @@
 /* Serial port to use. */
 unsigned long com_port;
 
-bd_t hold_resid_buf;
+/* We need to make sure that this is before the images to ensure
+ * that it's in a mapped location. - Tom */
+bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
 bd_t *hold_residual = &hold_resid_buf;
 
 extern unsigned long serial_init(int chan, bd_t *bp);
diff -urN linux-2.5.6-pre2/arch/ppc/config.in linux-2.5.6-pre3/arch/ppc/config.in
--- linux-2.5.6-pre2/arch/ppc/config.in	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/arch/ppc/config.in	Wed Mar  6 17:17:44 2002
@@ -258,8 +258,9 @@
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS
 bool 'High memory support' CONFIG_HIGHMEM
+dep_bool '  Support for PTEs in high memory' CONFIG_HIGHPTE $CONFIG_HIGHMEM
+bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS
 if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then
   if [ "$CONFIG_HIGHMEM" = "y" ]; then
     bool "  Set high memory pool address" CONFIG_HIGHMEM_START_BOOL
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/entry.S linux-2.5.6-pre3/arch/ppc/kernel/entry.S
--- linux-2.5.6-pre2/arch/ppc/kernel/entry.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -288,15 +288,12 @@
  */	
 _GLOBAL(_switch)
 	stwu	r1,-INT_FRAME_SIZE(r1)
-	stw	r0,GPR0(r1)
-	lwz	r0,0(r1)
-	stw	r0,GPR1(r1)
+	mflr	r0
+	stw	r0,INT_FRAME_SIZE+4(r1)
 	/* r3-r13 are caller saved -- Cort */
-	SAVE_GPR(2, r1)
 	SAVE_8GPRS(14, r1)
 	SAVE_10GPRS(22, r1)
-	mflr	r20		/* Return to switch caller */
-	stw	r20,INT_FRAME_SIZE+4(r1)
+	stw	r0,_NIP(r1)	/* Return to switch caller */
 	mfmsr	r22
 	li	r0,MSR_FP	/* Disable floating-point */
 #ifdef CONFIG_ALTIVEC
@@ -309,17 +306,9 @@
 	andc	r22,r22,r0
 	mtmsr	r22
 	isync
-1:	stw	r20,_NIP(r1)
-	stw	r22,_MSR(r1)
-	stw	r20,_LINK(r1)
+1:	stw	r22,_MSR(r1)
 	mfcr	r20
-	mfctr	r22
-	mfspr	r23,XER
 	stw	r20,_CCR(r1)
-	stw	r22,_CTR(r1)
-	stw	r23,_XER(r1)
-	li	r0,0x0ff0
-	stw	r0,TRAP(r1)
 	stw	r1,KSP(r3)	/* Set old stack pointer */
 
 	tophys(r0,r4)
@@ -343,7 +332,7 @@
 
 	.globl	ret_from_fork
 ret_from_fork:
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 	bl	schedule_tail
 #endif
 	rlwinm	r3,r1,0,0,18
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/iSeries_head.S linux-2.5.6-pre3/arch/ppc/kernel/iSeries_head.S
--- linux-2.5.6-pre2/arch/ppc/kernel/iSeries_head.S	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/iSeries_head.S	Wed Mar  6 17:17:44 2002
@@ -839,7 +839,7 @@
 
 	/* 
 	 * We hard enable here (but first soft disable) so that the hash_page
-	 * code can spin on the hash_table_lock without problem on a shared
+	 * code can spin on the mmu_hash_lock without problem on a shared
 	 * processor
 	 */
 	li	r0,0
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/iSeries_misc.S linux-2.5.6-pre3/arch/ppc/kernel/iSeries_misc.S
--- linux-2.5.6-pre2/arch/ppc/kernel/iSeries_misc.S	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/iSeries_misc.S	Wed Mar  6 17:17:44 2002
@@ -29,7 +29,7 @@
 	.align	5
 
 #ifdef CONFIG_SMP
-	.comm	hash_table_lock,4
+	.comm	mmu_hash_lock,4
 #endif /* CONFIG_SMP */
 
 _GLOBAL(is_msr_enabled)
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/idle.c linux-2.5.6-pre3/arch/ppc/kernel/idle.c
--- linux-2.5.6-pre2/arch/ppc/kernel/idle.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/idle.c	Wed Mar  6 17:17:44 2002
@@ -47,17 +47,10 @@
 #define run_light_on(x)         do { } while (0)
 #endif /* CONFIG_PPC_ISERIES */
 
-void zero_paged(void);
 void power_save(void);
 
-unsigned long zero_paged_on = 0;
-unsigned long powersave_nap = 0;
-
-unsigned long *zero_cache;    /* head linked list of pre-zero'd pages */
-atomic_t zerototal;      /* # pages zero'd over time */
-atomic_t zeropage_hits;  /* # zero'd pages request that we've done */
-atomic_t zero_sz;	      /* # currently pre-zero'd pages */
-atomic_t zeropage_calls; /* # zero'd pages request that've been made */
+unsigned long zero_paged_on;
+unsigned long powersave_nap;
 
 int idled(void)
 {
@@ -92,7 +85,6 @@
 		if (need_resched()) {
 			run_light_on(1);
 			schedule();
-			check_pgt_cache();
 		}
 #ifdef CONFIG_PPC_ISERIES
 		else {
@@ -115,141 +107,6 @@
 	return 0; 
 }
 
-#if 0
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_zero_page_fast(void)
-{
-	unsigned long page = 0;
-
-	atomic_inc(&zero_cache_calls);
-	if ( zero_quicklist )
-	{
-		/* atomically remove this page from the list */
-		register unsigned long tmp;
-		asm (	"101:lwarx  %1,0,%3\n"  /* reserve zero_cache */
-			"    lwz    %0,0(%1)\n" /* get next -- new zero_cache */
-			PPC405_ERR77(0,%3)
-			"    stwcx. %0,0,%3\n"  /* update zero_cache */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
-			: "r" (&zero_quicklist)
-			: "cc" );
-#ifdef CONFIG_SMP
-		/* if another cpu beat us above this can happen -- Cort */
-		if ( page == 0 ) 
-			return 0;
-#endif /* CONFIG_SMP */		
-		/* we can update zerocount after the fact since it is not
-		 * used for anything but control of a loop which doesn't
-		 * matter since it won't affect anything if it zeros one
-		 * less page -- Cort
-		 */
-		atomic_inc((atomic_t *)&zero_cache_hits);
-		atomic_dec((atomic_t *)&zero_cache_sz);
-		
-		/* zero out the pointer to next in the page */
-		*(unsigned long *)page = 0;
-		return page;
-	}
-	return 0;
-}
-
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages(). Zero's out pages until
- * we've reached the limit of zero'd pages.  We handle
- * reschedule()'s in here so when we return we know we've
- * zero'd all we need to for now.
- */
-int zero_cache_water[2] = { 25, 96 }; /* high and low water marks for zero cache */
-void zero_paged(void)
-{
-	unsigned long pageptr = 0;	/* current page being zero'd */
-	unsigned long bytecount = 0;  
-        register unsigned long tmp;
-	pte_t *pte;
-
-	if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
-		return;
-	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
-	{
-		/*
-		 * Mark a page as reserved so we can mess with it
-		 * If we're interrupted we keep this page and our place in it
-		 * since we validly hold it and it's reserved for us.
-		 */
-		pageptr = __get_free_pages(GFP_ATOMIC, 0);
-		if ( !pageptr )
-			return;
-		
-		cond_resched();
-		
-		/*
-		 * Make the page no cache so we don't blow our cache with 0's
-		 */
-		pte = find_pte(&init_mm, pageptr);
-		if ( !pte )
-		{
-			printk("pte NULL in zero_paged()\n");
-			return;
-		}
-		
-		pte_uncache(*pte);
-		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
-		/*
-		 * Important here to not take time away from real processes.
-		 */
-		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
-		{
-			cond_resched();
-			*(unsigned long *)(bytecount + pageptr) = 0;
-		}
-		
-		/*
-		 * If we finished zero-ing out a page add this page to
-		 * the zero_cache atomically -- we can't use
-		 * down/up since we can't sleep in idle.
-		 * Disabling interrupts is also a bad idea since we would
-		 * steal time away from real processes.
-		 * We can also have several zero_paged's running
-		 * on different processors so we can't interfere with them.
-		 * So we update the list atomically without locking it.
-		 * -- Cort
-		 */
-		
-		/* turn cache on for this page */
-		pte_cache(*pte);
-		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
-		/* atomically add this page to the list */
-		asm (	"101:lwarx  %0,0,%2\n"  /* reserve zero_cache */
-			"    stw    %0,0(%3)\n" /* update *pageptr */
-#ifdef CONFIG_SMP
-			"    sync\n"            /* let store settle */
-#endif			
- 			PPC405_ERR77(0,%2)
-			"    stwcx. %3,0,%2\n"  /* update zero_cache in mem */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (tmp), "+m" (zero_quicklist)
-			: "r" (&zero_quicklist), "r" (pageptr)
-			: "cc" );
-		/*
-		 * This variable is used in the above loop and nowhere
-		 * else so the worst that could happen is we would
-		 * zero out one more or one less page than we want
-		 * per processor on the machine.  This is because
-		 * we could add our page to the list but not have
-		 * zerocount updated yet when another processor
-		 * reads it.  -- Cort
-		 */
-		atomic_inc((atomic_t *)&zero_cache_sz);
-		atomic_inc((atomic_t *)&zero_cache_total);
-	}
-}
-#endif /* 0 */
-
 void power_save(void)
 {
 	unsigned long hid0;
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/misc.S linux-2.5.6-pre3/arch/ppc/kernel/misc.S
--- linux-2.5.6-pre2/arch/ppc/kernel/misc.S	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/misc.S	Wed Mar  6 17:17:44 2002
@@ -369,34 +369,39 @@
 	isync
 #else
 #if defined(CONFIG_SMP)
+	rlwinm	r8,r1,0,0,18
+	lwz	r8,TI_CPU(r8)
+	oris	r8,r8,10
 	mfmsr	r10
 	SYNC
 	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear DR */
 	mtmsr	r0
-	SYNC
-	lis	r9,hash_table_lock@h
-	ori	r9,r9,hash_table_lock@l
-	rlwinm	r8,r1,0,0,18
-	lwz	r8,TI_CPU(r8)
-	oris	r8,r8,10
+	SYNC_601
+	isync
+	lis	r9,mmu_hash_lock@h
+	ori	r9,r9,mmu_hash_lock@l
+	tophys(r9,r9)
 10:	lwarx	r7,0,r9
 	cmpi	0,r7,0
 	bne-	10b
-	/* No 405 Erratum 77 fix needed here, because 4xx can't do SMP */
 	stwcx.	r8,0,r9
 	bne-	10b
-#endif /* CONFIG_SMP */
 	sync
 	tlbia
 	sync
-#ifdef CONFIG_SMP
 	TLBSYNC
 	li	r0,0
-	stw	r0,0(r9)		/* clear hash_table_lock */
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
 	mtmsr	r10
-	SYNC
-#endif
-#endif
+	SYNC_601
+	isync
+#else /* CONFIG_SMP */
+	sync
+	tlbia
+	sync
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_4xx */
 	blr	
 
 /*
@@ -415,33 +420,37 @@
 10:
 #else
 #if defined(CONFIG_SMP)
+	rlwinm	r8,r1,0,0,18
+	lwz	r8,TI_CPU(r8)
+	oris	r8,r8,11
 	mfmsr	r10
 	SYNC
 	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear DR */
 	mtmsr	r0
-	SYNC
-	lis	r9,hash_table_lock@h
-	ori	r9,r9,hash_table_lock@l
-	rlwinm	r8,r1,0,0,18
-	lwz	r8,TI_CPU(r8)
-	oris	r8,r8,11
+	SYNC_601
+	isync
+	lis	r9,mmu_hash_lock@h
+	ori	r9,r9,mmu_hash_lock@l
+	tophys(r9,r9)
 10:	lwarx	r7,0,r9
 	cmpi	0,r7,0
 	bne-	10b
-	PPC405_ERR77(0,r9)
 	stwcx.	r8,0,r9
 	bne-	10b
 	eieio
-#endif /* CONFIG_SMP */
 	tlbie	r3
 	sync
-#ifdef CONFIG_SMP
 	TLBSYNC
 	li	r0,0
-	stw	r0,0(r9)		/* clear hash_table_lock */
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
 	mtmsr	r10
-	SYNC
-#endif
+	SYNC_601
+	isync
+#else /* CONFIG_SMP */
+	tlbie	r3
+	sync
+#endif /* CONFIG_SMP */
 #endif /* CONFIG_4xx */
 	blr
 
@@ -629,6 +638,40 @@
 	sync
 	isync
 	blr
+
+/*
+ * Flush a particular page from the data cache to RAM, identified
+ * by its physical address.  We turn off the MMU so we can just use
+ * the physical address (this may be a highmem page without a kernel
+ * mapping).
+ *
+ *	void __flush_dcache_icache_phys(unsigned long physaddr)
+ */
+_GLOBAL(__flush_dcache_icache_phys)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr					/* for 601, do nothing */
+	mfmsr	r10
+	rlwinm	r0,r10,0,28,26			/* clear DR */
+	mtmsr	r0
+	isync
+	rlwinm	r3,r3,0,0,19			/* Get page base address */
+	li	r4,4096/L1_CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+	mr	r6,r3
+0:	dcbst	0,r3				/* Write line to ram */
+	addi	r3,r3,L1_CACHE_LINE_SIZE
+	bdnz	0b
+	sync
+	mtctr	r4
+1:	icbi	0,r6
+	addi	r6,r6,L1_CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	mtmsr	r10				/* restore DR */
+	isync
+	blr
 	
 /*
  * Clear a page using the dcbz instruction, which doesn't cause any
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/ppc_ksyms.c linux-2.5.6-pre3/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.5.6-pre2/arch/ppc/kernel/ppc_ksyms.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/ppc_ksyms.c	Wed Mar  6 17:17:44 2002
@@ -218,13 +218,13 @@
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 #ifdef SPINLOCK_DEBUG
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
-EXPORT_SYMBOL(spin_trylock);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
+EXPORT_SYMBOL(_raw_spin_lock);
+EXPORT_SYMBOL(_raw_spin_unlock);
+EXPORT_SYMBOL(_raw_spin_trylock);
+EXPORT_SYMBOL(_raw_read_lock);
+EXPORT_SYMBOL(_raw_read_unlock);
+EXPORT_SYMBOL(_raw_write_lock);
+EXPORT_SYMBOL(_raw_write_unlock);
 #endif
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_hw_index);
@@ -361,7 +361,7 @@
 EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
 EXPORT_SYMBOL_NOVERS(disarm_decr);
 #ifdef CONFIG_PPC_STD_MMU
-EXPORT_SYMBOL(flush_hash_page); /* For MOL */
+EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
 #endif
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/qspan_pci.c linux-2.5.6-pre3/arch/ppc/kernel/qspan_pci.c
--- linux-2.5.6-pre2/arch/ppc/kernel/qspan_pci.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/qspan_pci.c	Wed Mar  6 17:17:44 2002
@@ -14,7 +14,7 @@
  * PCI access and QSpan control register addresses.  The selection is
  * further selected by a bit setting in a board control register.
  * Although it should happen, we disable interrupts during this operation
- * to make sure some driver doesn't accidently access the PCI while
+ * to make sure some driver doesn't accidentally access the PCI while
  * we have switched the chip select.
  */
 
diff -urN linux-2.5.6-pre2/arch/ppc/kernel/smp.c linux-2.5.6-pre3/arch/ppc/kernel/smp.c
--- linux-2.5.6-pre2/arch/ppc/kernel/smp.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/arch/ppc/kernel/smp.c	Wed Mar  6 17:17:44 2002
@@ -291,26 +291,6 @@
 		atomic_inc(&call_data->finished);
 }
 
-/*
- * Task migration callback.
- */
-void smp_task_migration_interrupt(void *new_task)
-{
-	task_t *p;
-
-	p = new_task;
-	sched_task_migrated(p);
-}
-
-/*
- * This function sends a 'task migration' IPI to another CPU.
- * Must be called from syscall contexts, with interrupts *enabled*.
- */
-void smp_migrate_task(int cpu, task_t *p)
-{
-	__smp_call_function(smp_task_migration_interrupt, p, 0, cpu);
-}
-
 void __init smp_boot_cpus(void)
 {
 	int i, cpu_nr;
diff -urN linux-2.5.6-pre2/arch/ppc/lib/locks.c linux-2.5.6-pre3/arch/ppc/lib/locks.c
--- linux-2.5.6-pre2/arch/ppc/lib/locks.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/ppc/lib/locks.c	Wed Mar  6 17:17:44 2002
@@ -28,7 +28,7 @@
  * since they may inhibit forward progress by other CPUs in getting
  * a lock.
  */
-static unsigned long __spin_trylock(volatile unsigned long *lock)
+unsigned long __spin_trylock(volatile unsigned long *lock)
 {
 	unsigned long ret;
 
diff -urN linux-2.5.6-pre2/arch/ppc/mm/cachemap.c linux-2.5.6-pre3/arch/ppc/mm/cachemap.c
--- linux-2.5.6-pre2/arch/ppc/mm/cachemap.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/cachemap.c	Wed Mar  6 17:17:44 2002
@@ -50,8 +50,6 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 
-extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
-
 /* This function will allocate the requested contiguous pages and
  * map them into the kernel's vmalloc() space.  This is done so we
  * get unique mapping for these pages, outside of the kernel's 1:1
@@ -157,6 +155,6 @@
 {
 	unsigned long start;
 
-	start = (unsigned long)(page->virtual) + offset; 
+	start = page_address(page) + offset;
 	consistent_sync(start, size, direction);
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/fault.c linux-2.5.6-pre3/arch/ppc/mm/fault.c
--- linux-2.5.6-pre2/arch/ppc/mm/fault.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/fault.c	Wed Mar  6 17:17:44 2002
@@ -154,6 +154,7 @@
 
 		/* Since 4xx supports per-page execute permission,
 		 * we lazily flush dcache to icache. */
+		ptep = NULL;
 		if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) {
 			struct page *page = pte_page(*ptep);
 
@@ -164,9 +165,12 @@
 			}
 			pte_update(ptep, 0, _PAGE_HWEXEC);
 			_tlbie(address);
+			pte_unmap(ptep);
 			up_read(&mm->mmap_sem);
 			return;
 		}
+		if (ptep != NULL)
+			pte_unmap(ptep);
 #endif
 	/* a read */
 	} else {
@@ -289,27 +293,18 @@
 	struct mm_struct *mm;
 
 	if (address < TASK_SIZE)
-		mm = current->mm;
-	else
-		mm = &init_mm;
+		return NULL;
 
-	dir = pgd_offset(mm, address & PAGE_MASK);
+	dir = pgd_offset(&init_mm, address);
 	if (dir) {
 		pmd = pmd_offset(dir, address & PAGE_MASK);
 		if (pmd && pmd_present(*pmd)) {
-			pte = pte_offset(pmd, address & PAGE_MASK);
-			if (pte && pte_present(*pte)) {
+			pte = pte_offset_kernel(pmd, address & PAGE_MASK);
+			if (pte && pte_present(*pte))
 				return(pte);
-			}
-		}
-		else {
-			return (0);
 		}
 	}
-	else {
-		return (0);
-	}
-	return (0);
+	return NULL;
 }
 
 unsigned long va_to_phys(unsigned long address)
@@ -334,7 +329,7 @@
         if (pgd) {
                 pmd = pmd_offset(pgd, addr & PAGE_MASK);
                 if (pmd && pmd_present(*pmd)) {
-                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
                         if (pte) {
                                 printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
                                         (long)pgd, (long)pte, (long)pte_val(*pte));
@@ -375,9 +370,9 @@
         if (pgd) {
                 pmd = pmd_offset(pgd, addr & PAGE_MASK);
                 if (pmd && pmd_present(*pmd)) {
-                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
                         if (pte) {
-                                        retval = (int)pte_val(*pte);
+				retval = (int)pte_val(*pte);
                         }
                 }
         }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/hashtable.S linux-2.5.6-pre3/arch/ppc/mm/hashtable.S
--- linux-2.5.6-pre2/arch/ppc/mm/hashtable.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/hashtable.S	Wed Mar  6 17:17:44 2002
@@ -36,7 +36,7 @@
 #include <kernel/ppc_defs.h>
 
 #ifdef CONFIG_SMP
-	.comm	hash_table_lock,4
+	.comm	mmu_hash_lock,4
 #endif /* CONFIG_SMP */
 
 /*
@@ -62,8 +62,8 @@
 #endif
 	tophys(r7,0)			/* gets -KERNELBASE into r7 */
 #ifdef CONFIG_SMP
-	addis	r2,r7,hash_table_lock@h
-	ori	r2,r2,hash_table_lock@l
+	addis	r2,r7,mmu_hash_lock@h
+	ori	r2,r2,mmu_hash_lock@l
 	lis	r0,0x0fff
 	b	10f
 11:	lwz	r6,0(r2)
@@ -88,8 +88,8 @@
 	rlwimi	r3,r23,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	r5,0(r5)		/* get pmd entry */
-	rlwinm.	r5,r5,0,0,19		/* extract address of pte page */
+	lwz	r2,0(r5)		/* get pmd entry */
+	rlwinm.	r2,r2,0,0,19		/* extract address of pte page */
 #ifdef CONFIG_SMP
 	beq-	hash_page_out		/* return if no mapping */
 #else
@@ -99,7 +99,6 @@
 	   to the address following the rfi. */
 	beqlr-
 #endif
-	add	r2,r5,r7		/* convert to phys addr */
 	rlwimi	r2,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
@@ -142,9 +141,9 @@
 
 #ifdef CONFIG_SMP
 	eieio
-	addis	r2,r7,hash_table_lock@ha
+	addis	r2,r7,mmu_hash_lock@ha
 	li	r0,0
-	stw	r0,hash_table_lock@l(r2)
+	stw	r0,mmu_hash_lock@l(r2)
 #endif
 
 	/* Return from the exception */
@@ -174,16 +173,16 @@
 #ifdef CONFIG_SMP
 hash_page_out:
 	eieio
-	addis	r2,r7,hash_table_lock@ha
+	addis	r2,r7,mmu_hash_lock@ha
 	li	r0,0
-	stw	r0,hash_table_lock@l(r2)
+	stw	r0,mmu_hash_lock@l(r2)
 	blr
 #endif /* CONFIG_SMP */
 
 /*
  * Add an entry for a particular page to the hash table.
  *
- * add_hash_page(unsigned context, unsigned long va, pte_t pte)
+ * add_hash_page(unsigned context, unsigned long va, unsigned long pmdval)
  *
  * We assume any necessary modifications to the pte (e.g. setting
  * the accessed bit) have already been done and that there is actually
@@ -199,31 +198,41 @@
 	mulli	r0,r0,0x111		/* multiply by ESID skew */
 	add	r3,r3,r0		/* note create_hpte trims to 24 bits */
 
+#ifdef CONFIG_SMP
+	rlwinm	r8,r1,0,0,18		/* use cpu number to make tag */
+	lwz	r8,TI_CPU(r8)		/* to go in mmu_hash_lock */
+	oris	r8,r8,12
+#endif /* CONFIG_SMP */
+
 	/*
 	 * We disable interrupts here, even on UP, because we don't
 	 * want to race with hash_page, and because we want the
 	 * _PAGE_HASHPTE bit to be a reliable indication of whether
-	 * the HPTE exists (or at least whether one did once).  -- paulus
+	 * the HPTE exists (or at least whether one did once).
+	 * We also turn off the MMU for data accesses so that we
+	 * we can't take a hash table miss (assuming the code is
+	 * covered by a BAT).  -- paulus
 	 */
 	mfmsr	r10
 	SYNC
 	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear MSR_DR */
 	mtmsr	r0
-	SYNC
+	SYNC_601
+	isync
+
+	tophys(r7,0)
 
 #ifdef CONFIG_SMP
-	lis	r9,hash_table_lock@h
-	ori	r9,r9,hash_table_lock@l
-	rlwinm	r8,r1,0,0,18
-	lwz	r8,TI_CPU(r8)
-	oris	r8,r8,12
-10:	lwarx	r7,0,r9
-	cmpi	0,r7,0
+	addis	r9,r7,mmu_hash_lock@ha
+	addi	r9,r9,mmu_hash_lock@l
+10:	lwarx	r0,0,r9			/* take the mmu_hash_lock */
+	cmpi	0,r0,0
 	bne-	11f
 	stwcx.	r8,0,r9
 	beq+	12f
-11:	lwz	r7,0(r9)
-	cmpi	0,r7,0
+11:	lwz	r0,0(r9)
+	cmpi	0,r0,0
 	beq	10b
 	b	11b
 12:	isync
@@ -234,18 +243,18 @@
 	 * If _PAGE_HASHPTE was already set, we don't replace the existing
 	 * HPTE, so we just unlock and return.
 	 */
-	mr	r7,r5
-1:	lwarx	r6,0,r7
+	mr	r8,r5
+	rlwimi	r8,r4,22,20,29
+1:	lwarx	r6,0,r8
 	andi.	r0,r6,_PAGE_HASHPTE
 	bne	9f			/* if HASHPTE already set, done */
-	ori	r5,r6,_PAGE_ACCESSED|_PAGE_HASHPTE
-	stwcx.	r5,0,r7
+	ori	r5,r6,_PAGE_HASHPTE
+	stwcx.	r5,0,r8
 	bne-	1b
 
-	li	r7,0			/* no address offset needed */
 	bl	create_hpte
 
-	lis	r8,htab_preloads@ha
+	addis	r8,r7,htab_preloads@ha
 	lwz	r3,htab_preloads@l(r8)
 	addi	r3,r3,1
 	stw	r3,htab_preloads@l(r8)
@@ -254,15 +263,16 @@
 #ifdef CONFIG_SMP
 	eieio
 	li	r0,0
-	stw	r0,0(r9)		/* clear hash_table_lock */
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
 #endif
 
+	/* reenable interrupts and DR */
+	mtmsr	r10
+	SYNC_601
+	isync
+
 	lwz	r0,4(r1)
 	mtlr	r0
-
-	/* reenable interrupts */
-	mtmsr	r10
-	SYNC
 	blr
 
 /*
@@ -273,7 +283,7 @@
  * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
  * offset to be added to addresses (0 if the MMU is on,
  * -KERNELBASE if it is off).
- * On SMP, the caller should have the hash_table_lock held.
+ * On SMP, the caller should have the mmu_hash_lock held.
  * We assume that the caller has (or will) set the _PAGE_HASHPTE
  * bit in the linux PTE in memory.  The value passed in r6 should
  * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set
@@ -486,41 +496,73 @@
 /*
  * Flush the entry for a particular page from the hash table.
  *
- * flush_hash_page(unsigned context, unsigned long va, pte_t *ptep)
+ * flush_hash_pages(unsigned context, unsigned long va, unsigned long pmdval,
+ *		    int count)
  *
  * We assume that there is a hash table in use (Hash != 0).
  */
-_GLOBAL(flush_hash_page)
-	/* Convert context and va to VSID */
-	mulli	r3,r3,897*16		/* multiply context by context skew */
-	rlwinm	r0,r4,4,28,31		/* get ESID (top 4 bits of va) */
-	mulli	r0,r0,0x111		/* multiply by ESID skew */
-	add	r3,r3,r0		/* note code below trims to 24 bits */
+_GLOBAL(flush_hash_pages)
+	tophys(r7,0)
 
 	/*
 	 * We disable interrupts here, even on UP, because we want
 	 * the _PAGE_HASHPTE bit to be a reliable indication of
-	 * whether the HPTE exists.  -- paulus
+	 * whether the HPTE exists (or at least whether one did once).
+	 * We also turn off the MMU for data accesses so that we
+	 * we can't take a hash table miss (assuming the code is
+	 * covered by a BAT).  -- paulus
 	 */
 	mfmsr	r10
-	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
 	SYNC
+	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear MSR_DR */
 	mtmsr	r0
-	SYNC
+	SYNC_601
+	isync
+
+	/* First find a PTE in the range that has _PAGE_HASHPTE set */
+	rlwimi	r5,r4,22,20,29
+1:	lwz	r0,0(r5)
+	cmpwi	cr1,r6,1
+	andi.	r0,r0,_PAGE_HASHPTE
+	bne	2f
+	ble	cr1,19f
+	addi	r4,r4,0x1000
+	addi	r5,r5,4
+	addi	r6,r6,-1
+	b	1b
+
+	/* Convert context and va to VSID */
+2:	mulli	r3,r3,897*16		/* multiply context by context skew */
+	rlwinm	r0,r4,4,28,31		/* get ESID (top 4 bits of va) */
+	mulli	r0,r0,0x111		/* multiply by ESID skew */
+	add	r3,r3,r0		/* note code below trims to 24 bits */
+
+	/* Construct the high word of the PPC-style PTE (r11) */
+#ifndef CONFIG_PPC64BRIDGE
+	rlwinm	r11,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
+	rlwimi	r11,r4,10,26,31		/* put in API (abbrev page index) */
+#else /* CONFIG_PPC64BRIDGE */
+	clrlwi	r3,r3,8			/* reduce vsid to 24 bits */
+	sldi	r11,r3,12		/* shift vsid into position */
+	rlwimi	r11,r4,16,20,24		/* put in API (abbrev page index) */
+#endif /* CONFIG_PPC64BRIDGE */
+	SET_V(r11)			/* set V (valid) bit */
 
 #ifdef CONFIG_SMP
-	lis	r9,hash_table_lock@h
-	ori	r9,r9,hash_table_lock@l
+	addis	r9,r7,mmu_hash_lock@ha
+	addi	r9,r9,mmu_hash_lock@l
 	rlwinm	r8,r1,0,0,18
+	add	r8,r8,r7
 	lwz	r8,TI_CPU(r8)
 	oris	r8,r8,9
-10:	lwarx	r7,0,r9
-	cmpi	0,r7,0
+10:	lwarx	r0,0,r9
+	cmpi	0,r0,0
 	bne-	11f
 	stwcx.	r8,0,r9
 	beq+	12f
-11:	lwz	r7,0(r9)
-	cmpi	0,r7,0
+11:	lwz	r0,0(r9)
+	cmpi	0,r0,0
 	beq	10b
 	b	11b
 12:	isync
@@ -528,69 +570,72 @@
 
 	/*
 	 * Check the _PAGE_HASHPTE bit in the linux PTE.  If it is
-	 * already clear, we're done.  If not, clear it (atomically)
-	 * and proceed.  -- paulus.
+	 * already clear, we're done (for this pte).  If not,
+	 * clear it (atomically) and proceed.  -- paulus.
 	 */
-1:	lwarx	r6,0,r5			/* fetch the pte */
-	andi.	r0,r6,_PAGE_HASHPTE
-	beq	9f			/* done if HASHPTE is already clear */
-	rlwinm	r6,r6,0,31,29		/* clear HASHPTE bit */
-	stwcx.	r6,0,r5			/* update the pte */
-	bne-	1b
-
-	/* Construct the high word of the PPC-style PTE (r5) */
-#ifndef CONFIG_PPC64BRIDGE
-	rlwinm	r5,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
-	rlwimi	r5,r4,10,26,31		/* put in API (abbrev page index) */
-#else /* CONFIG_PPC64BRIDGE */
-	clrlwi	r3,r3,8			/* reduce vsid to 24 bits */
-	sldi	r5,r3,12		/* shift vsid into position */
-	rlwimi	r5,r4,16,20,24		/* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64BRIDGE */
-	SET_V(r5)			/* set V (valid) bit */
+33:	lwarx	r8,0,r5			/* fetch the pte */
+	andi.	r0,r8,_PAGE_HASHPTE
+	beq	8f			/* done if HASHPTE is already clear */
+	rlwinm	r8,r8,0,31,29		/* clear HASHPTE bit */
+	stwcx.	r8,0,r5			/* update the pte */
+	bne-	33b
 
 	/* Get the address of the primary PTE group in the hash table (r3) */
 	.globl	flush_hash_patch_A
 flush_hash_patch_A:
-	lis	r8,Hash_base@h		/* base address of hash table */
+	addis	r8,r7,Hash_base@h	/* base address of hash table */
 	rlwimi	r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT    /* VSID -> hash */
-	rlwinm	r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
-	xor	r3,r3,r8		/* make primary hash */
-	li	r8,8			/* PTEs/group */
+	rlwinm	r0,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */
+	xor	r8,r0,r8		/* make primary hash */
 
 	/* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
-	mtctr	r8
-	addi	r7,r3,-PTE_SIZE
-1:	LDPTEu	r0,PTE_SIZE(r7)		/* get next PTE */
-	CMPPTE	0,r0,r5
+	li	r0,8			/* PTEs/group */
+	mtctr	r0
+	addi	r12,r8,-PTE_SIZE
+1:	LDPTEu	r0,PTE_SIZE(r12)	/* get next PTE */
+	CMPPTE	0,r0,r11
 	bdnzf	2,1b			/* loop while ctr != 0 && !cr0.eq */
 	beq+	3f
 
 	/* Search the secondary PTEG for a matching PTE */
-	ori	r5,r5,PTE_H		/* set H (secondary hash) bit */
+	ori	r11,r11,PTE_H		/* set H (secondary hash) bit */
+	li	r0,8			/* PTEs/group */
 	.globl	flush_hash_patch_B
 flush_hash_patch_B:
-	xoris	r7,r3,Hash_msk>>16	/* compute secondary hash */
-	xori	r7,r7,(-PTEG_SIZE & 0xffff)
-	addi	r7,r7,-PTE_SIZE
-	mtctr	r8
-2:	LDPTEu	r0,PTE_SIZE(r7)
-	CMPPTE	0,r0,r5
+	xoris	r12,r8,Hash_msk>>16	/* compute secondary hash */
+	xori	r12,r12,(-PTEG_SIZE & 0xffff)
+	addi	r12,r12,-PTE_SIZE
+	mtctr	r0
+2:	LDPTEu	r0,PTE_SIZE(r12)
+	CMPPTE	0,r0,r11
 	bdnzf	2,2b
-	bne-	4f			/* should never fail to find it */
+	xori	r11,r11,PTE_H		/* clear H again */
+	bne-	4f			/* should rarely fail to find it */
 
 3:	li	r0,0
-	STPTE	r0,0(r7)		/* invalidate entry */
+	STPTE	r0,0(r12)		/* invalidate entry */
 4:	sync
 	tlbie	r4			/* in hw tlb too */
 	sync
 
+8:	ble	cr1,9f			/* if all ptes checked */
+81:	addi	r6,r6,-1
+	addi	r5,r5,4			/* advance to next pte */
+	addi	r4,r4,0x1000
+	lwz	r0,0(r5)		/* check next pte */
+	cmpwi	cr1,r6,1
+	andi.	r0,r0,_PAGE_HASHPTE
+	bne	33b
+	bgt	cr1,81b
+
+9:
 #ifdef CONFIG_SMP
 	TLBSYNC
-9:	li	r0,0
-	stw	r0,0(r9)		/* clear hash_table_lock */
+	li	r0,0
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
 #endif
 
-9:	mtmsr	r10
-	SYNC
+19:	mtmsr	r10
+	SYNC_601
+	isync
 	blr
diff -urN linux-2.5.6-pre2/arch/ppc/mm/iSeries_hashtable.c linux-2.5.6-pre3/arch/ppc/mm/iSeries_hashtable.c
--- linux-2.5.6-pre2/arch/ppc/mm/iSeries_hashtable.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/iSeries_hashtable.c	Wed Mar  6 17:17:44 2002
@@ -39,7 +39,7 @@
 
 int iSeries_hpt_loaded;
 
-static spinlock_t hash_table_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t mmu_hash_lock = SPIN_LOCK_UNLOCKED;
 
 extern unsigned long htab_reloads;	// Defined in ppc/kernel/ppc_htab.c
 extern unsigned long htab_evicts;
@@ -159,10 +159,10 @@
 	
 	access |= _PAGE_PRESENT;		// _PAGE_PRESENT also needed
 
-	spin_lock( &hash_table_lock );
+	spin_lock( &mmu_hash_lock );
 	// check if pte is in the required state
 	if ( ( access & ~(pte_val(*pt)) ) ) {
-		spin_unlock( &hash_table_lock );
+		spin_unlock( &mmu_hash_lock );
 		return 1;
 	}
 
@@ -177,18 +177,18 @@
 		      va, 
 		      pte_val(*pt));
 
-	spin_unlock( &hash_table_lock );
+	spin_unlock( &mmu_hash_lock );
 	return 0;
 }
 
 void add_hash_page(unsigned context, unsigned long va, pte_t *ptep)
 {
-	spin_lock( &hash_table_lock );
+	spin_lock( &mmu_hash_lock );
 	pte_update(ptep,0,_PAGE_HASHPTE);
 	__create_hpte(CTX_TO_VSID(context, va), 
 		      va, 
 		      pte_val(*ptep));
-	spin_unlock( &hash_table_lock );
+	spin_unlock( &mmu_hash_lock );
 }
 
 int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep)
@@ -208,7 +208,7 @@
 	hpte1Ptr = hpte0Ptr + 1;
 	*hpte0Ptr = *hpte1Ptr = 0;
   
-	spin_lock( &hash_table_lock );
+	spin_lock( &mmu_hash_lock );
 	rtnIndex = HvCallHpt_findValid( &hpte, vpn );
   
 	if ( hpte.v ) {
@@ -217,7 +217,7 @@
 		rc = 0;
 	} else
 		rc = 1;
-	spin_unlock( &hash_table_lock );
+	spin_unlock( &mmu_hash_lock );
 	return rc;
 }
 
diff -urN linux-2.5.6-pre2/arch/ppc/mm/iSeries_mmu.c linux-2.5.6-pre3/arch/ppc/mm/iSeries_mmu.c
--- linux-2.5.6-pre2/arch/ppc/mm/iSeries_mmu.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/iSeries_mmu.c	Wed Mar  6 17:17:44 2002
@@ -175,12 +175,13 @@
 	pte_t *ptep;
 	static int nopreload;
 
-	if (nopreload)
+	if (nopreload || address >= TASK_SIZE)
 		return;
-	mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
+	mm = vma->vm_mm;
 	pmd = pmd_offset(pgd_offset(mm, address), address);
 	if (!pmd_none(*pmd)) {
-		ptep = pte_offset(pmd, address);
+		ptep = pte_offset_map(pmd, address);
 		add_hash_page(mm->context, address, ptep);
+		pte_unmap(ptep);
 	}
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/init.c linux-2.5.6-pre3/arch/ppc/mm/init.c
--- linux-2.5.6-pre2/arch/ppc/mm/init.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/init.c	Wed Mar  6 17:17:44 2002
@@ -113,24 +113,6 @@
 /* max amount of low RAM to map in */
 unsigned long __max_low_memory = MAX_LOW_MEM;
 
-int do_check_pgt_cache(int low, int high)
-{
-	int freed = 0;
-	if (pgtable_cache_size > high) {
-		do {
-                        if (pgd_quicklist) {
-				free_pgd_slow(get_pgd_fast());
-				freed++;
-			}
-			if (pte_quicklist) {
-				pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-		} while (pgtable_cache_size > low);
-	}
-	return freed;
-}
-
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
@@ -160,7 +142,6 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	printk("%d pages in page table cache\n",(int)pgtable_cache_size);
 	show_buffers();
 }
 
@@ -396,9 +377,11 @@
 
 #ifdef CONFIG_HIGHMEM
 	map_page(PKMAP_BASE, 0, 0);	/* XXX gross */
-	pkmap_page_table = pte_offset(pmd_offset(pgd_offset_k(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE);
+	pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k
+			(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE);
 	map_page(KMAP_FIX_BEGIN, 0, 0);	/* XXX gross */
-	kmap_pte = pte_offset(pmd_offset(pgd_offset_k(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN);
+	kmap_pte = pte_offset_kernel(pmd_offset(pgd_offset_k
+			(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN);
 	kmap_prot = PAGE_KERNEL;
 #endif /* CONFIG_HIGHMEM */
 
@@ -588,10 +571,12 @@
 
 void flush_icache_page(struct vm_area_struct *vma, struct page *page)
 {
+	unsigned long phys;
+
 	if (page->mapping && !PageReserved(page)
 	    && !test_bit(PG_arch_1, &page->flags)) {
-		__flush_dcache_icache(kmap(page));
-		kunmap(page);
+		phys = ((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART;
+		__flush_dcache_icache_phys(phys);
 		set_bit(PG_arch_1, &page->flags);
 	}
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/mmu_decl.h linux-2.5.6-pre3/arch/ppc/mm/mmu_decl.h
--- linux-2.5.6-pre2/arch/ppc/mm/mmu_decl.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/mmu_decl.h	Wed Mar  6 17:17:44 2002
@@ -61,11 +61,12 @@
  * which includes all new 82xx processors.  We need tlbie/tlbsync here
  * in that case (I think). -- Dan.
  */
-static inline void flush_HPTE(unsigned context, unsigned long va, pte_t *pg)
+static inline void flush_HPTE(unsigned context, unsigned long va,
+			      unsigned long pdval)
 {
 	if ((Hash != 0) &&
 	    (cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE))
-		flush_hash_page(0, va, pg);
+		flush_hash_pages(0, va, pdval, 1);
 	else
 		_tlbie(va);
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/pgtable.c linux-2.5.6-pre3/arch/ppc/mm/pgtable.c
--- linux-2.5.6-pre2/arch/ppc/mm/pgtable.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/pgtable.c	Wed Mar  6 17:17:44 2002
@@ -39,10 +39,6 @@
 unsigned long ioremap_bot;
 int io_bat_index;
 
-#ifndef CONFIG_SMP
-struct pgtable_cache_struct quicklists;
-#endif
-
 #if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
 #define HAVE_BATS	1
 #endif
@@ -173,12 +169,12 @@
 	/* Use upper 10 bits of VA to index the first level map */
 	pd = pmd_offset(pgd_offset_k(va), va);
 	/* Use middle 10 bits of VA to index the second-level map */
-	pg = pte_alloc(&init_mm, pd, va);
+	pg = pte_alloc_kernel(&init_mm, pd, va);
 	if (pg != 0) {
 		err = 0;
 		set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
 		if (mem_init_done)
-			flush_HPTE(0, va, pg);
+			flush_HPTE(0, va, pmd_val(*pd));
 	}
 	spin_unlock(&init_mm.page_table_lock);
 	return err;
@@ -272,10 +268,11 @@
         if (pgd) {
                 pmd = pmd_offset(pgd, addr & PAGE_MASK);
                 if (pmd_present(*pmd)) {
-                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        pte = pte_offset_map(pmd, addr & PAGE_MASK);
                         if (pte) {
 				retval = 1;
 				*ptep = pte;
+				/* XXX caller needs to do pte_unmap, yuck */
                         }
                 }
         }
@@ -312,8 +309,10 @@
 		mm = &init_mm;
 	
 	pa = 0;
-	if (get_pteptr(mm, addr, &pte))
+	if (get_pteptr(mm, addr, &pte)) {
 		pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
+		pte_unmap(pte);
+	}
 
 	return(pa);
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/ppc_mmu.c linux-2.5.6-pre3/arch/ppc/mm/ppc_mmu.c
--- linux-2.5.6-pre2/arch/ppc/mm/ppc_mmu.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/ppc_mmu.c	Wed Mar  6 17:17:44 2002
@@ -33,6 +33,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 
 #include <asm/prom.h>
 #include <asm/mmu.h>
@@ -289,7 +290,6 @@
 {
 	struct mm_struct *mm;
 	pmd_t *pmd;
-	pte_t *ptep;
 	static int nopreload;
 
 	if (Hash == 0 || nopreload)
@@ -299,8 +299,6 @@
 		return;
 	mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
 	pmd = pmd_offset(pgd_offset(mm, address), address);
-	if (!pmd_none(*pmd)) {
-		ptep = pte_offset(pmd, address);
-		add_hash_page(mm->context, address, ptep);
-	}
+	if (!pmd_none(*pmd))
+		add_hash_page(mm->context, address, pmd_val(*pmd));
 }
diff -urN linux-2.5.6-pre2/arch/ppc/mm/tlb.c linux-2.5.6-pre3/arch/ppc/mm/tlb.c
--- linux-2.5.6-pre2/arch/ppc/mm/tlb.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/arch/ppc/mm/tlb.c	Wed Mar  6 17:17:44 2002
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 
 #include "mmu_decl.h"
 
@@ -104,7 +105,6 @@
 {
 	struct mm_struct *mm;
 	pmd_t *pmd;
-	pte_t *pte;
 
 	if (Hash == 0) {
 		_tlbie(vmaddr);
@@ -112,11 +112,8 @@
 	}
 	mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
 	pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
-	if (!pmd_none(*pmd)) {
-		pte = pte_offset(pmd, vmaddr);
-		if (pte_val(*pte) & _PAGE_HASHPTE)
-			flush_hash_page(mm->context, vmaddr, pte);
-	}
+	if (!pmd_none(*pmd))
+		flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1);
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif	
@@ -133,8 +130,8 @@
 {
 	struct mm_struct *mm = vma->vm_mm;
 	pmd_t *pmd;
-	pte_t *pte;
 	unsigned long pmd_end;
+	int count;
 	unsigned int ctx = mm->context;
 
 	if (Hash == 0) {
@@ -144,24 +141,21 @@
 	start &= PAGE_MASK;
 	if (start >= end)
 		return;
+	end = (end - 1) | ~PAGE_MASK;
 	pmd = pmd_offset(pgd_offset(mm, start), start);
-	do {
-		pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
+	for (;;) {
+		pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
+		if (pmd_end > end)
+			pmd_end = end;
 		if (!pmd_none(*pmd)) {
-			if (!pmd_end || pmd_end > end)
-				pmd_end = end;
-			pte = pte_offset(pmd, start);
-			do {
-				if ((pte_val(*pte) & _PAGE_HASHPTE) != 0)
-					flush_hash_page(ctx, start, pte);
-				start += PAGE_SIZE;
-				++pte;
-			} while (start && start < pmd_end);
-		} else {
-			start = pmd_end;
+			count = ((pmd_end - start) >> PAGE_SHIFT) + 1;
+			flush_hash_pages(ctx, start, pmd_val(*pmd), count);
 		}
+		if (pmd_end == end)
+			break;
+		start = pmd_end + 1;
 		++pmd;
-	} while (start && start < end);
+	}
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
diff -urN linux-2.5.6-pre2/arch/ppc/vmlinux.lds linux-2.5.6-pre3/arch/ppc/vmlinux.lds
--- linux-2.5.6-pre2/arch/ppc/vmlinux.lds	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/arch/ppc/vmlinux.lds	Wed Mar  6 17:17:44 2002
@@ -111,6 +111,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -urN linux-2.5.6-pre2/arch/ppc64/kernel/entry.S linux-2.5.6-pre3/arch/ppc64/kernel/entry.S
--- linux-2.5.6-pre2/arch/ppc64/kernel/entry.S	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/arch/ppc64/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -311,7 +311,7 @@
 	blr
 
 _GLOBAL(ret_from_fork)
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 	bl	.schedule_tail
 #endif
 	clrrdi	r4,r1,THREAD_SHIFT
diff -urN linux-2.5.6-pre2/arch/s390/kernel/entry.S linux-2.5.6-pre3/arch/s390/kernel/entry.S
--- linux-2.5.6-pre2/arch/s390/kernel/entry.S	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/arch/s390/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -295,7 +295,7 @@
         stosm   24(%r15),0x03     # reenable interrupts
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
         l       %r1,BASED(.Lschedtail)
 	la      %r14,BASED(sysc_return)
         br      %r1               # call schedule_tail, return to sysc_return
@@ -896,7 +896,7 @@
 #error .Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
 
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 .Lschedtail:   .long  schedule_tail
 #endif
 
diff -urN linux-2.5.6-pre2/arch/s390x/kernel/entry.S linux-2.5.6-pre3/arch/s390x/kernel/entry.S
--- linux-2.5.6-pre2/arch/s390x/kernel/entry.S	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/arch/s390x/kernel/entry.S	Wed Mar  6 17:17:44 2002
@@ -280,7 +280,7 @@
         GET_CURRENT               # load pointer to task_struct to R9
         stosm   48(%r15),0x03     # reenable interrupts
 	xc      SP_R2(8,%r15),SP_R2(%r15) # child returns 0
-#ifdef CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 	larl    %r14,sysc_return
         jg      schedule_tail     # return to sysc_return
 #else
diff -urN linux-2.5.6-pre2/arch/sparc64/defconfig linux-2.5.6-pre3/arch/sparc64/defconfig
--- linux-2.5.6-pre2/arch/sparc64/defconfig	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/arch/sparc64/defconfig	Wed Mar  6 17:17:44 2002
@@ -273,7 +273,6 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -286,7 +285,6 @@
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
diff -urN linux-2.5.6-pre2/arch/x86_64/defconfig linux-2.5.6-pre3/arch/x86_64/defconfig
--- linux-2.5.6-pre2/arch/x86_64/defconfig	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/arch/x86_64/defconfig	Wed Mar  6 17:17:44 2002
@@ -188,7 +188,6 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
diff -urN linux-2.5.6-pre2/drivers/acorn/block/mfmhd.c linux-2.5.6-pre3/drivers/acorn/block/mfmhd.c
--- linux-2.5.6-pre2/drivers/acorn/block/mfmhd.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/acorn/block/mfmhd.c	Wed Mar  6 17:17:44 2002
@@ -1222,7 +1222,7 @@
 	case BLKROSET:
 	case BLKROGET:
 	case BLKPG:
-		return blk_ioctl(dev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 
 	default:
 		return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/acpi/executer/exresnte.c linux-2.5.6-pre3/drivers/acpi/executer/exresnte.c
--- linux-2.5.6-pre2/drivers/acpi/executer/exresnte.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/drivers/acpi/executer/exresnte.c	Wed Mar  6 17:17:44 2002
@@ -44,7 +44,7 @@
  * FUNCTION:    Acpi_ex_resolve_node_to_value
  *
  * PARAMETERS:  Object_ptr      - Pointer to a location that contains
- *                                a pointer to a NS node, and will recieve a
+ *                                a pointer to a NS node, and will receive a
  *                                pointer to the resolved object.
  *              Walk_state      - Current state.  Valid only if executing AML
  *                                code.  NULL if simply resolving an object
diff -urN linux-2.5.6-pre2/drivers/block/DAC960.c linux-2.5.6-pre3/drivers/block/DAC960.c
--- linux-2.5.6-pre2/drivers/block/DAC960.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/drivers/block/DAC960.c	Wed Mar  6 17:17:44 2002
@@ -5398,7 +5398,7 @@
     case BLKFLSBUF:
     case BLKBSZGET:
     case BLKBSZSET:
-      return blk_ioctl(Inode->i_rdev, Request, Argument);
+      return blk_ioctl(Inode->i_bdev, Request, Argument);
 
     case BLKRRPART:
       /* Re-Read Partition Table. */
diff -urN linux-2.5.6-pre2/drivers/block/acsi.c linux-2.5.6-pre3/drivers/block/acsi.c
--- linux-2.5.6-pre2/drivers/block/acsi.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/block/acsi.c	Wed Mar  6 17:17:44 2002
@@ -1141,7 +1141,7 @@
 	  case BLKROGET:
 	  case BLKFLSBUF:
 	  case BLKPG:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 
 	  case BLKRRPART: /* Re-read partition tables */
 	        if (!capable(CAP_SYS_ADMIN)) 
diff -urN linux-2.5.6-pre2/drivers/block/ataflop.c linux-2.5.6-pre3/drivers/block/ataflop.c
--- linux-2.5.6-pre2/drivers/block/ataflop.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/block/ataflop.c	Wed Mar  6 17:17:44 2002
@@ -1574,7 +1574,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKFLSBUF:
-			return blk_ioctl(device, cmd, param);
+			return blk_ioctl(inode->i_bdev, cmd, param);
 	}
 	drive = minor (device);
 	type  = drive >> 2;
diff -urN linux-2.5.6-pre2/drivers/block/blkpg.c linux-2.5.6-pre3/drivers/block/blkpg.c
--- linux-2.5.6-pre2/drivers/block/blkpg.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/block/blkpg.c	Wed Mar  6 17:17:44 2002
@@ -34,7 +34,6 @@
 #include <linux/blk.h>			/* for set_device_ro() */
 #include <linux/blkpg.h>
 #include <linux/genhd.h>
-#include <linux/swap.h>			/* for is_swap_partition() */
 #include <linux/module.h>               /* for EXPORT_SYMBOL */
 
 #include <asm/uaccess.h>
@@ -63,12 +62,13 @@
  *                 or has the same number as an existing one
  *          0: all OK.
  */
-int add_partition(kdev_t dev, struct blkpg_partition *p)
+int add_partition(struct block_device *bdev, struct blkpg_partition *p)
 {
 	struct gendisk *g;
 	long long ppstart, pplength;
 	long pstart, plength;
 	int i, drive, first_minor, end_minor, minor;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 
 	/* convert bytes to sectors, check for fit in a hd_struct */
 	ppstart = (p->start >> 9);
@@ -126,11 +126,14 @@
  *
  * Note that the dev argument refers to the entire disk, not the partition.
  */
-int del_partition(kdev_t dev, struct blkpg_partition *p)
+int del_partition(struct block_device *bdev, struct blkpg_partition *p)
 {
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct gendisk *g;
 	kdev_t devp;
+	struct block_device *bdevp;
 	int drive, first_minor, minor;
+	int holder;
 
 	/* find the drive major */
 	g = get_gendisk(dev);
@@ -153,22 +156,29 @@
 
 	/* partition in use? Incomplete check for now. */
 	devp = mk_kdev(major(dev), minor);
-	if (is_mounted(devp) || is_swap_partition(devp))
+	bdevp = bdget(kdev_t_to_nr(devp));
+	if (!bdevp)
+		return -ENOMEM;
+	if (bd_claim(bdevp, &holder) < 0) {
+		bdput(bdevp);
 		return -EBUSY;
+	}
 
 	/* all seems OK */
-	fsync_dev(devp);
-	invalidate_buffers(devp);
+	fsync_bdev(bdevp);
+	invalidate_bdev(bdevp, 0);
 
 	g->part[minor].start_sect = 0;
 	g->part[minor].nr_sects = 0;
 	if (g->sizes)
 		g->sizes[minor] = 0;
+	bd_release(bdevp);
+	bdput(bdevp);
 
 	return 0;
 }
 
-int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
+int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
 {
 	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
@@ -188,9 +198,9 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (a.op == BLKPG_ADD_PARTITION)
-				return add_partition(dev, &p);
+				return add_partition(bdev, &p);
 			else
-				return del_partition(dev, &p);
+				return del_partition(bdev, &p);
 		default:
 			return -EINVAL;
 	}
@@ -200,16 +210,15 @@
  * Common ioctl's for block devices
  */
 extern int block_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg);
-int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
+int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
 {
 	request_queue_t *q;
 	struct gendisk *g;
 	u64 ullval = 0;
 	int intval;
 	unsigned short usval;
-
-	if (kdev_none(dev))
-		return -EINVAL;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	int holder;
 
 	intval = block_ioctl(dev, cmd, arg);
 	if (intval != -ENOTTY)
@@ -265,7 +274,7 @@
 #endif
 
 		case BLKPG:
-			return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
+			return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
 			
 		/*
 		 * deprecated, use the /proc/iosched interface instead
@@ -290,9 +299,10 @@
 			if (intval > PAGE_SIZE || intval < 512 ||
 			    (intval & (intval - 1)))
 				return -EINVAL;
-			if (is_mounted(dev) || is_swap_partition(dev))
+			if (bd_claim(bdev, &holder) < 0)
 				return -EBUSY;
 			set_blocksize(dev, intval);
+			bd_release(bdev);
 			return 0;
 
 		default:
diff -urN linux-2.5.6-pre2/drivers/block/cciss.c linux-2.5.6-pre3/drivers/block/cciss.c
--- linux-2.5.6-pre2/drivers/block/cciss.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/block/cciss.c	Wed Mar  6 17:17:44 2002
@@ -469,7 +469,7 @@
 	case BLKROSET:
 	case BLKROGET:
 	case BLKPG:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 	case CCISS_GETPCIINFO:
 	{
 		cciss_pci_info_struct pciinfo;
diff -urN linux-2.5.6-pre2/drivers/block/cpqarray.c linux-2.5.6-pre3/drivers/block/cpqarray.c
--- linux-2.5.6-pre2/drivers/block/cpqarray.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/block/cpqarray.c	Wed Mar  6 17:17:44 2002
@@ -1179,7 +1179,7 @@
 	case BLKROSET:
 	case BLKROGET:
 	case BLKPG:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 
 	default:
 		return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/block/floppy.c linux-2.5.6-pre3/drivers/block/floppy.c
--- linux-2.5.6-pre2/drivers/block/floppy.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/block/floppy.c	Wed Mar  6 17:17:44 2002
@@ -3449,7 +3449,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKFLSBUF:
-			return blk_ioctl(device, cmd, param);
+			return blk_ioctl(inode->i_bdev, cmd, param);
 	}
 	type = TYPE(device);
 	drive = DRIVE(device);
diff -urN linux-2.5.6-pre2/drivers/block/loop.c linux-2.5.6-pre3/drivers/block/loop.c
--- linux-2.5.6-pre2/drivers/block/loop.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/block/loop.c	Wed Mar  6 17:17:45 2002
@@ -852,7 +852,7 @@
 		break;
 	case BLKBSZGET:
 	case BLKBSZSET:
-		err = blk_ioctl(inode->i_rdev, cmd, arg);
+		err = blk_ioctl(inode->i_bdev, cmd, arg);
 		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/block/paride/pd.c linux-2.5.6-pre3/drivers/block/paride/pd.c
--- linux-2.5.6-pre2/drivers/block/paride/pd.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/block/paride/pd.c	Wed Mar  6 17:17:45 2002
@@ -481,7 +481,7 @@
 	    case BLKROGET:
 	    case BLKFLSBUF:
 	    case BLKPG:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 	    default:
 		return -EINVAL;
 	}
diff -urN linux-2.5.6-pre2/drivers/block/paride/pf.c linux-2.5.6-pre3/drivers/block/paride/pf.c
--- linux-2.5.6-pre2/drivers/block/paride/pf.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/block/paride/pf.c	Wed Mar  6 17:17:45 2002
@@ -433,7 +433,7 @@
 	    case BLKROSET:
 	    case BLKROGET:
 	    case BLKFLSBUF:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
             default:
                 return -EINVAL;
         }
diff -urN linux-2.5.6-pre2/drivers/block/ps2esdi.c linux-2.5.6-pre3/drivers/block/ps2esdi.c
--- linux-2.5.6-pre2/drivers/block/ps2esdi.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/drivers/block/ps2esdi.c	Wed Mar  6 17:17:45 2002
@@ -1111,7 +1111,7 @@
 		case BLKBSZGET:
 		case BLKBSZSET:
 		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 		}
 	return (-EINVAL);
 }
diff -urN linux-2.5.6-pre2/drivers/block/rd.c linux-2.5.6-pre3/drivers/block/rd.c
--- linux-2.5.6-pre2/drivers/block/rd.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/block/rd.c	Wed Mar  6 17:17:45 2002
@@ -311,7 +311,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
-			error = blk_ioctl(inode->i_rdev, cmd, arg);
+			error = blk_ioctl(inode->i_bdev, cmd, arg);
 	};
 out:
 	return error;
diff -urN linux-2.5.6-pre2/drivers/block/xd.c linux-2.5.6-pre3/drivers/block/xd.c
--- linux-2.5.6-pre2/drivers/block/xd.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/block/xd.c	Wed Mar  6 17:17:45 2002
@@ -355,7 +355,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		default:
 			return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/cdrom/cdrom.c linux-2.5.6-pre3/drivers/cdrom/cdrom.c
--- linux-2.5.6-pre2/drivers/cdrom/cdrom.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/cdrom/cdrom.c	Wed Mar  6 17:17:45 2002
@@ -263,6 +263,7 @@
 #include <linux/cdrom.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
+#include <linux/blkpg.h>
 #include <linux/init.h>
 
 #include <asm/fcntl.h>
@@ -1724,6 +1725,11 @@
 	   because they fill up the sys log when CD players poll
 	   the drive. */
 	switch (cmd) {
+	case BLKROSET:
+	case BLKROGET:
+	case BLKFLSBUF:
+	case BLKSSZGET:
+		return blk_ioctl(ip->i_bdev, cmd, arg);
 	case CDROMSUBCHNL: {
 		struct cdrom_subchnl q;
 		u_char requested, back;
diff -urN linux-2.5.6-pre2/drivers/char/agp/agpgart_be.c linux-2.5.6-pre3/drivers/char/agp/agpgart_be.c
--- linux-2.5.6-pre2/drivers/char/agp/agpgart_be.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/char/agp/agpgart_be.c	Wed Mar  6 17:17:45 2002
@@ -622,7 +622,7 @@
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
-		set_bit(PG_reserved, &page->flags);
+		SetPageReserved(page);
 
 	agp_bridge.gatt_table_real = (unsigned long *) table;
 	CACHE_FLUSH();
@@ -632,7 +632,7 @@
 
 	if (agp_bridge.gatt_table == NULL) {
 		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
-			clear_bit(PG_reserved, &page->flags);
+			ClearPageReserved(page);
 
 		free_pages((unsigned long) table, page_order);
 
@@ -699,7 +699,7 @@
 	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
-		clear_bit(PG_reserved, &page->flags);
+		ClearPageReserved(page);
 
 	free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
 	return 0;
@@ -812,8 +812,8 @@
 	if (page == NULL) {
 		return 0;
 	}
-	atomic_inc(&page->count);
-	set_bit(PG_locked, &page->flags);
+	get_page(page);
+	LockPage(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
 	return (unsigned long)page_address(page);
 }
@@ -828,9 +828,8 @@
 	}
 	
 	page = virt_to_page(pt);
-	atomic_dec(&page->count);
-	clear_bit(PG_locked, &page->flags);
-	wake_up_page(page);
+	put_page(page);
+	UnlockPage(page);
 	free_page((unsigned long) pt);
 	atomic_dec(&agp_bridge.current_memory_agp);
 }
@@ -2278,13 +2277,12 @@
 	if (page_map->real == NULL) {
 		return -ENOMEM;
 	}
-	set_bit(PG_reserved, &virt_to_page(page_map->real)->flags);
+	SetPageReserved(virt_to_page(page_map->real));
 	CACHE_FLUSH();
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
-		clear_bit(PG_reserved, 
-			  &virt_to_page(page_map->real)->flags);
+		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
 		return -ENOMEM;
@@ -2301,8 +2299,7 @@
 static void amd_free_page_map(amd_page_map *page_map)
 {
 	iounmap(page_map->remapped);
-	clear_bit(PG_reserved, 
-		  &virt_to_page(page_map->real)->flags);
+	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
 }
 
@@ -2790,8 +2787,8 @@
 	if (page == NULL)
 		return 0;
 
-	atomic_inc(&page->count);
-	set_bit(PG_locked, &page->flags);
+	get_page(page);
+	LockPage(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
 
 	global_cache_flush();
@@ -2826,9 +2823,8 @@
 	}
 
 	page = virt_to_page(pt);
-	atomic_dec(&page->count);
-	clear_bit(PG_locked, &page->flags);
-	wake_up_page(page);
+	put_page(page);
+	UnlockPage(page);
 	free_page((unsigned long) pt);
 	atomic_dec(&agp_bridge.current_memory_agp);
 }
@@ -2910,13 +2906,12 @@
 	if (page_map->real == NULL) {
 		return -ENOMEM;
 	}
-	set_bit(PG_reserved, &virt_to_page(page_map->real)->flags);
+	SetPageReserved(virt_to_page(page_map->real));
 	CACHE_FLUSH();
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
-		clear_bit(PG_reserved, 
-			  &virt_to_page(page_map->real)->flags);
+		ClearPageReserved(virt_to_page(page_map->real));
 		free_page((unsigned long) page_map->real);
 		page_map->real = NULL;
 		return -ENOMEM;
@@ -2933,8 +2928,7 @@
 static void serverworks_free_page_map(serverworks_page_map *page_map)
 {
 	iounmap(page_map->remapped);
-	clear_bit(PG_reserved, 
-		  &virt_to_page(page_map->real)->flags);
+	ClearPageReserved(virt_to_page(page_map->real));
 	free_page((unsigned long) page_map->real);
 }
 
diff -urN linux-2.5.6-pre2/drivers/char/drm/i810_dma.c linux-2.5.6-pre3/drivers/char/drm/i810_dma.c
--- linux-2.5.6-pre2/drivers/char/drm/i810_dma.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/char/drm/i810_dma.c	Wed Mar  6 17:17:45 2002
@@ -286,8 +286,8 @@
 	if(address == 0UL)
 		return 0;
 
-	atomic_inc(&virt_to_page(address)->count);
-	set_bit(PG_locked, &virt_to_page(address)->flags);
+	get_page(virt_to_page(address));
+	LockPage(virt_to_page(address));
 
 	return address;
 }
@@ -296,9 +296,8 @@
 {
 	if (page) {
 		struct page *p = virt_to_page(page);
-		atomic_dec(p);
-		clear_bit(PG_locked, &p->flags);
-		wake_up_page(p);
+		put_page(p);
+		UnlockPage(p);
 		free_page(page);
 	}
 }
diff -urN linux-2.5.6-pre2/drivers/char/synclink.c linux-2.5.6-pre3/drivers/char/synclink.c
--- linux-2.5.6-pre2/drivers/char/synclink.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/char/synclink.c	Wed Mar  6 17:17:45 2002
@@ -1812,7 +1812,7 @@
 	/* Allocate and claim adapter resources */
 	retval = mgsl_claim_resources(info);
 	
-	/* perform existance check and diagnostics */
+	/* perform existence check and diagnostics */
 	if ( !retval )
 		retval = mgsl_adapter_test(info);
 		
diff -urN linux-2.5.6-pre2/drivers/ide/Config.help linux-2.5.6-pre3/drivers/ide/Config.help
--- linux-2.5.6-pre2/drivers/ide/Config.help	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/drivers/ide/Config.help	Wed Mar  6 17:17:46 2002
@@ -581,13 +581,6 @@
 
   People with SCSI-only systems can say N here.
 
-CONFIG_BLK_DEV_4DRIVES
-  Certain older chipsets, including the Tekram 690CD, use a single set
-  of I/O ports at 0x1f0 to control up to four drives, instead of the
-  customary two drives per port. Support for this can be enabled at
-  runtime using the "ide0=four" kernel boot parameter if you say Y
-  here.
-
 CONFIG_BLK_DEV_ALI14XX
   This driver is enabled at runtime using the "ide0=ali14xx" kernel
   boot parameter.  It enables support for the secondary IDE interface
@@ -807,19 +800,6 @@
 
   If you are unsure, say N here.
 
-CONFIG_IDE_TASK_IOCTL
-  This is a direct raw access to the media.  It is a complex but
-  elegant solution to test and validate the domain of the hardware and
-  perform below the driver data recovery if needed.  This is the most
-  basic form of media-forensics.
-
-  If you are unsure, say N here.
-
-CONFIG_BLK_DEV_IDEDMA_FORCED
-  This is an old piece of lost code from Linux 2.0 Kernels.
-
-  Generally say N here.
-
 CONFIG_IDEDMA_ONLYDISK
   This is used if you know your ATAPI Devices are going to fail DMA
   Transfers.
diff -urN linux-2.5.6-pre2/drivers/ide/Config.in linux-2.5.6-pre3/drivers/ide/Config.in
--- linux-2.5.6-pre2/drivers/ide/Config.in	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/drivers/ide/Config.in	Wed Mar  6 17:17:46 2002
@@ -33,9 +33,7 @@
    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
 
-   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
-
-   comment 'IDE chipset support/bugfixes'
+   comment 'IDE chipset support'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
       dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
       dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
@@ -47,7 +45,6 @@
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
-	    dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $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
@@ -143,7 +140,6 @@
       bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
-	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
 	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
 	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
 	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
diff -urN linux-2.5.6-pre2/drivers/ide/ali14xx.c linux-2.5.6-pre3/drivers/ide/ali14xx.c
--- linux-2.5.6-pre2/drivers/ide/ali14xx.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ali14xx.c	Wed Mar  6 17:17:46 2002
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
- *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
@@ -37,8 +35,6 @@
  * mode 4 for a while now with no trouble.)  -Derek
  */
 
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff -urN linux-2.5.6-pre2/drivers/ide/cmd640.c linux-2.5.6-pre3/drivers/ide/cmd640.c
--- linux-2.5.6-pre2/drivers/ide/cmd640.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/cmd640.c	Wed Mar  6 17:17:46 2002
@@ -1,12 +1,10 @@
 /*
- *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
- *
  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
  */
 
 /*
  *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *  			mlord@pobox.com (Mark Lord)
+ *			mlord@pobox.com (Mark Lord)
  *
  *  See linux/MAINTAINERS for address of current maintainer.
  *
@@ -98,7 +96,6 @@
  *			 (patch courtesy of Zoltan Hidvegi)
  */
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
 #define CMD640_PREFETCH_MASKS 1
 
 #include <linux/config.h>
diff -urN linux-2.5.6-pre2/drivers/ide/cmd64x.c linux-2.5.6-pre3/drivers/ide/cmd64x.c
--- linux-2.5.6-pre2/drivers/ide/cmd64x.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/cmd64x.c	Wed Mar  6 17:17:46 2002
@@ -238,7 +238,7 @@
 	 */
 	if (channel) {
 		drive->drive_data = setup_count;
-		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
+		setup_count = max(drives[0].drive_data, drives[1].drive_data);
 		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
 	}
 
diff -urN linux-2.5.6-pre2/drivers/ide/dtc2278.c linux-2.5.6-pre3/drivers/ide/dtc2278.c
--- linux-2.5.6-pre2/drivers/ide/dtc2278.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/ide/dtc2278.c	Wed Mar  6 17:17:46 2002
@@ -1,11 +1,7 @@
 /*
- *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
- *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff -urN linux-2.5.6-pre2/drivers/ide/hd.c linux-2.5.6-pre3/drivers/ide/hd.c
--- linux-2.5.6-pre2/drivers/ide/hd.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/hd.c	Wed Mar  6 17:17:46 2002
@@ -654,7 +654,7 @@
 		case BLKROGET:
 		case BLKFLSBUF:
 		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		default:
 			return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/ide/hpt366.c linux-2.5.6-pre3/drivers/ide/hpt366.c
--- linux-2.5.6-pre2/drivers/ide/hpt366.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/hpt366.c	Wed Mar  6 17:17:46 2002
@@ -374,7 +374,8 @@
 		class_rev &= 0xff;
 
 		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "Chipset: HPT%s\n",
+			class_rev < sizeof(chipset_nums) / sizeof(char *) ? chipset_nums[class_rev] : "???");
 		p += sprintf(p, "--------------- Primary Channel "
 				"--------------- Secondary Channel "
 				"--------------\n");
@@ -1119,12 +1120,11 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-	if (pci_rev_check_hpt3xx(dev)) {
+	if (pci_rev_check_hpt3xx(dev))
 		init_hpt370(dev);
+
+	if (n_hpt_devs < HPT366_MAX_DEVS)
 		hpt_devs[n_hpt_devs++] = dev;
-	} else {
-		hpt_devs[n_hpt_devs++] = dev;
-	}
 	
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
diff -urN linux-2.5.6-pre2/drivers/ide/hptraid.c linux-2.5.6-pre3/drivers/ide/hptraid.c
--- linux-2.5.6-pre2/drivers/ide/hptraid.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/hptraid.c	Wed Mar  6 17:17:46 2002
@@ -126,7 +126,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		default:
 			return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/ide/ht6560b.c linux-2.5.6-pre3/drivers/ide/ht6560b.c
--- linux-2.5.6-pre2/drivers/ide/ht6560b.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ht6560b.c	Wed Mar  6 17:17:46 2002
@@ -1,10 +1,5 @@
 /*
- *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
- *
  *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
  *
  *  Version 0.01        Initial version hacked out of ide.c
  *
@@ -36,8 +31,6 @@
 
 #define HT6560B_VERSION "v0.07"
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff -urN linux-2.5.6-pre2/drivers/ide/ide-cd.c linux-2.5.6-pre3/drivers/ide/ide-cd.c
--- linux-2.5.6-pre2/drivers/ide/ide-cd.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-cd.c	Wed Mar  6 17:17:46 2002
@@ -1633,6 +1633,7 @@
 	return startstop;
 }
 
+#define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 
 /****************************************************************************
  * cdrom driver request routine.
@@ -2906,69 +2907,29 @@
 	return 0;
 }
 
-static int ide_cdrom_reinit (ide_drive_t *drive);
-
 static struct ata_operations ide_cdrom_driver = {
 	owner:			THIS_MODULE,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
-	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
 	end_request:		NULL,
 	ioctl:			ide_cdrom_ioctl,
 	open:			ide_cdrom_open,
 	release:		ide_cdrom_release,
-	media_change:		ide_cdrom_check_media_change,
+	check_media_change:	ide_cdrom_check_media_change,
 	revalidate:		ide_cdrom_revalidate,
 	pre_reset:		NULL,
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
-	proc:			NULL,
-	driver_reinit:		ide_cdrom_reinit,
+	proc:			NULL
 };
 
 /* options */
-char *ignore = NULL;
+static char *ignore = NULL;
 
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cdrom_reinit (ide_drive_t *drive)
-{
-	struct cdrom_info *info;
-	int failed = 0;
-
-	MOD_INC_USE_COUNT;
-	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
-	if (info == NULL) {
-		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
-		return 1;
-	}
-	if (ide_register_subdriver (drive, &ide_cdrom_driver)) {
-		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (info);
-		return 1;
-	}
-	memset (info, 0, sizeof (struct cdrom_info));
-	drive->driver_data = info;
-
-	/* ATA-PATTERN */
-	ata_ops(drive)->busy++;
-	if (ide_cdrom_setup (drive)) {
-		ata_ops(drive)->busy--;
-		if (ide_cdrom_cleanup (drive))
-			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
-		return 1;
-	}
-	ata_ops(drive)->busy--;
-
-	failed--;
-
-	revalidate_drives();
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
 static void __exit ide_cdrom_exit(void)
 {
 	ide_drive_t *drive;
@@ -2980,7 +2941,7 @@
 			failed++;
 		}
 }
- 
+
 int ide_cdrom_init(void)
 {
 	ide_drive_t *drive;
diff -urN linux-2.5.6-pre2/drivers/ide/ide-disk.c linux-2.5.6-pre3/drivers/ide/ide-disk.c
--- linux-2.5.6-pre2/drivers/ide/ide-disk.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-disk.c	Wed Mar  6 17:17:46 2002
@@ -1,10 +1,6 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.13	Nov 28, 2001
- *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- */
-
-/*
+ *
  *  Mostly written by Mark Lord <mlord@pobox.com>
  *                and Gadi Oxman <gadio@netvision.net.il>
  *                and Andre Hedrick <andre@linux-ide.org>
@@ -34,8 +30,6 @@
 
 #define IDEDISK_VERSION	"1.13"
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -351,7 +345,19 @@
 	return 0;
 }
 
-static int do_idedisk_flushcache(ide_drive_t *drive);
+static int idedisk_flushcache(ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	if (drive->id->cfs_enable_2 & 0x2400) {
+		taskfile.command	= WIN_FLUSH_CACHE_EXT;
+	} else {
+		taskfile.command	= WIN_FLUSH_CACHE;
+	}
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
 
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
@@ -367,15 +373,16 @@
 			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
-		if (do_idedisk_flushcache(drive))
+		if (idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
 				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
-static int idedisk_media_change (ide_drive_t *drive)
+static int idedisk_check_media_change (ide_drive_t *drive)
 {
-	return drive->removable;	/* if removable, always assume it was changed */
+	/* if removable, always assume it was changed */
+	return drive->removable;
 }
 
 /*
@@ -707,7 +714,7 @@
 	taskfile.low_cylinder	= SMART_LCYL_PASS;
 	taskfile.high_cylinder	= SMART_HCYL_PASS;
 	taskfile.command	= WIN_SMART;
-	(void) smart_enable(drive);
+	smart_enable(drive);
 	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
@@ -722,7 +729,7 @@
 	taskfile.low_cylinder	= SMART_LCYL_PASS;
 	taskfile.high_cylinder	= SMART_HCYL_PASS;
 	taskfile.command	= WIN_SMART;
-	(void) smart_enable(drive);
+	smart_enable(drive);
 	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
@@ -831,12 +838,12 @@
 	if (!(drive->id->cfs_enable_2 & 0x3000))
 		return 1;
 
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 	drive->wcache = arg;
 	return 0;
 }
 
-static int do_idedisk_standby (ide_drive_t *drive)
+static int idedisk_standby (ide_drive_t *drive)
 {
 	struct hd_drive_task_hdr taskfile;
 	struct hd_drive_hob_hdr hobfile;
@@ -846,20 +853,6 @@
 	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
-static int do_idedisk_flushcache (ide_drive_t *drive)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	if (drive->id->cfs_enable_2 & 0x2400) {
-		taskfile.command	= WIN_FLUSH_CACHE_EXT;
-	} else {
-		taskfile.command	= WIN_FLUSH_CACHE;
-	}
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-}
-
 static int set_acoustic (ide_drive_t *drive, int arg)
 {
 	struct hd_drive_task_hdr taskfile;
@@ -871,7 +864,7 @@
 	taskfile.sector_count	= arg;
 
 	taskfile.command	= WIN_SETFEATURES;
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -1040,72 +1033,36 @@
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
-
-	/* FIXME: we will have to think twice whatever this is the proper place
-	 * to do it.
-	 */
-
 	put_device(&drive->device);
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
-		if (do_idedisk_flushcache(drive))
+		if (idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
 				drive->name);
 	return ide_unregister_subdriver(drive);
 }
 
-static int idedisk_reinit(ide_drive_t *drive);
-
 /*
  *      IDE subdriver functions, registered with ide.c
  */
 static struct ata_operations idedisk_driver = {
 	owner:			THIS_MODULE,
 	cleanup:		idedisk_cleanup,
-	standby:		do_idedisk_standby,
-	flushcache:		do_idedisk_flushcache,
+	standby:		idedisk_standby,
 	do_request:		do_rw_disk,
 	end_request:		NULL,
 	ioctl:			NULL,
 	open:			idedisk_open,
 	release:		idedisk_release,
-	media_change:		idedisk_media_change,
-	revalidate:		ide_revalidate_drive,
+	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,
-	driver_reinit:		idedisk_reinit,
+	proc:			idedisk_proc
 };
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-static int idedisk_reinit(ide_drive_t *drive)
-{
-	int failed = 0;
-
-	MOD_INC_USE_COUNT;
-
-	if (ide_register_subdriver (drive, &idedisk_driver)) {
-		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
-		return 1;
-	}
-
-	ata_ops(drive)->busy++;
-	idedisk_setup(drive);
-	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
-		idedisk_cleanup(drive);
-		ata_ops(drive)->busy--;
-		return 1;
-	}
-	ata_ops(drive)->busy--;
-	failed--;
-
-	revalidate_drives();
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
 static void __exit idedisk_exit (void)
 {
 	ide_drive_t *drive;
@@ -1136,15 +1093,12 @@
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
-		ata_ops(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
 			idedisk_cleanup(drive);
-			ata_ops(drive)->busy--;
 			continue;
 		}
-		ata_ops(drive)->busy--;
 		failed--;
 	}
 	revalidate_drives();
diff -urN linux-2.5.6-pre2/drivers/ide/ide-dma.c linux-2.5.6-pre3/drivers/ide/ide-dma.c
--- linux-2.5.6-pre2/drivers/ide/ide-dma.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-dma.c	Wed Mar  6 17:17:46 2002
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ide-dma.c		Version 4.10	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
  */
@@ -15,7 +13,7 @@
 /*
  * This module provides support for the bus-master IDE DMA functions
  * of various PCI chipsets, including the Intel PIIX (i82371FB for
- * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and 
+ * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and
  * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
  * ("PIIX" stands for "PCI ISA IDE Xcellerator").
  *
@@ -73,8 +71,6 @@
  * check_drive_lists(ide_drive_t *drive, int good_bad)
  *
  * ATA-66/100 and recovery functions, I forgot the rest......
- * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
- *
  */
 
 #include <linux/config.h>
@@ -426,7 +422,7 @@
 	return 0;
 }
 
-int report_drive_dmaing (ide_drive_t *drive)
+static int report_drive_dmaing (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 
@@ -606,7 +602,10 @@
 		case ide_dma_read:
 			reading = 1 << 3;
 		case ide_dma_write:
-			SELECT_READ_WRITE(hwif,drive,func);
+			/* active tuning based on IO direction */
+			if (hwif->rwproc)
+				hwif->rwproc(drive, func);
+
 			if (!(count = ide_build_dmatable(drive, func)))
 				return 1;	/* try PIO instead of DMA */
 			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
@@ -617,9 +616,9 @@
 				return 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
 			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
-#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+#else
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
+#endif
 			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
 			    (drive->addressing == 1)) {
 				ide_task_t *args = HWGROUP(drive)->rq->special;
@@ -728,9 +727,8 @@
 }
 
 /*
- *	This can be called for a dynamically installed interface. Don't __init it
+ * This can be called for a dynamically installed interface. Don't __init it
  */
- 
 void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
 {
 	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
@@ -768,81 +766,3 @@
 dma_alloc_failure:
 	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
 }
-
-/*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
- */
-unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
-{
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (hwif->mate && hwif->mate->dma_base) {
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-	} else {
-		dma_base = pci_resource_start(dev, 4);
-		if (!dma_base) {
-			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
-			dma_base = 0;
-		}
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	if ((!dma_base) && (!second_chance)) {
-		unsigned long set_bmiba = 0;
-		second_chance++;
-		switch(dev->vendor) {
-			case PCI_VENDOR_ID_AL:
-				set_bmiba = DEFAULT_BMALIBA; break;
-			case PCI_VENDOR_ID_VIA:
-				set_bmiba = DEFAULT_BMCRBA; break;
-			case PCI_VENDOR_ID_INTEL:
-				set_bmiba = DEFAULT_BMIBA; break;
-			default:
-				return dma_base;
-		}
-		pci_write_config_dword(dev, 0x20, set_bmiba|1);
-		goto second_chance_to_dma;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (dma_base) {
-		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
-			request_region(dma_base+16, extra, name);
-		dma_base += hwif->channel ? 8 : 0;
-		hwif->dma_extra = extra;
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AMD_VIPER_7409:
-			case PCI_DEVICE_ID_CMD_643:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
-				if (inb(dma_base+2) & 0x80) {
-					printk("%s: simplex device: DMA forced\n", name);
-				}
-				break;
-			default:
-				/*
-				 * If the device claims "simplex" DMA,
-				 * this means only one of the two interfaces
-				 * can be trusted with DMA at any point in time.
-				 * So we should enable DMA only on one of the
-				 * two interfaces.
-				 */
-				if ((inb(dma_base+2) & 0x80)) {	/* simplex device? */
-					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					    (hwif->mate && hwif->mate->dma_base)) {
-						printk("%s: simplex device:  DMA disabled\n", name);
-						dma_base = 0;
-					}
-				}
-		}
-	}
-	return dma_base;
-}
diff -urN linux-2.5.6-pre2/drivers/ide/ide-floppy.c linux-2.5.6-pre3/drivers/ide/ide-floppy.c
--- linux-2.5.6-pre2/drivers/ide/ide-floppy.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-floppy.c	Wed Mar  6 17:17:46 2002
@@ -1113,7 +1113,7 @@
 	pc->retries++;
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+	bcount.all = min(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
@@ -1819,10 +1819,10 @@
 /*
  *	Check media change. Use a simple algorithm for now.
  */
-static int idefloppy_media_change (ide_drive_t *drive)
+static int idefloppy_check_media_change (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	
+
 	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
@@ -2038,8 +2038,6 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_reinit(ide_drive_t *drive);
-
 /*
  *	IDE subdriver functions, registered with ide.c
  */
@@ -2047,58 +2045,19 @@
 	owner:			THIS_MODULE,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
-	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
 	end_request:		idefloppy_end_request,
 	ioctl:			idefloppy_ioctl,
 	open:			idefloppy_open,
 	release:		idefloppy_release,
-	media_change:		idefloppy_media_change,
-	revalidate:		ide_revalidate_drive,
+	check_media_change:	idefloppy_check_media_change,
+	revalidate:		NULL, /* use default method */
 	pre_reset:		NULL,
 	capacity:		idefloppy_capacity,
 	special:		NULL,
-	proc:			idefloppy_proc,
-	driver_reinit:		idefloppy_reinit,
+	proc:			idefloppy_proc
 };
 
-static int idefloppy_reinit (ide_drive_t *drive)
-{
-	idefloppy_floppy_t *floppy;
-	int failed = 0;
-
-	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices(ATA_FLOPPY, "ide-floppy", NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idefloppy_driver)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
-			continue;
-		}
-
-		/* ATA-PATTERN */
-		ata_ops(drive)->busy++;
-		idefloppy_setup (drive, floppy);
-		ata_ops(drive)->busy--;
-
-		failed--;
-	}
-	revalidate_drives();
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
 static void __exit idefloppy_exit (void)
diff -urN linux-2.5.6-pre2/drivers/ide/ide-geometry.c linux-2.5.6-pre3/drivers/ide/ide-geometry.c
--- linux-2.5.6-pre2/drivers/ide/ide-geometry.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-geometry.c	Wed Mar  6 17:17:46 2002
@@ -14,14 +14,14 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
-extern unsigned long current_capacity (ide_drive_t *);
 
 /*
  * If heads is nonzero: find a translation with this many heads and S=63.
  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  */
 static void
-ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
+ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s)
+{
 	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
 	const byte *headp = dm_head_vals;
 	unsigned long total;
@@ -34,7 +34,7 @@
 	 * computes a geometry different from what OnTrack uses.]
 	 */
 
-	total = ata_ops(drive)->capacity(drive);
+	total = ata_capacity(drive);
 
 	*s = 63;
 
@@ -136,7 +136,7 @@
 		ret = 1;
 	}
 
-	drive->part[0].nr_sects = current_capacity(drive);
+	drive->part[0].nr_sects = ata_capacity(drive);
 
 	if (ret)
 		printk("%s%s [%d/%d/%d]", msg, msg1,
diff -urN linux-2.5.6-pre2/drivers/ide/ide-pci.c linux-2.5.6-pre3/drivers/ide/ide-pci.c
--- linux-2.5.6-pre2/drivers/ide/ide-pci.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-pci.c	Wed Mar  6 17:17:46 2002
@@ -1,9 +1,7 @@
 /*
- *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
- *
  *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
  *  Copyright (c) 1995-1998  Mark Lord
+ *
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
@@ -168,9 +166,9 @@
 #endif
 
 typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
+	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.
@@ -230,9 +228,10 @@
 	{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 ident 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.. */
+	/* 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 },
@@ -303,7 +302,9 @@
 #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. */
+	/* 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, IDE_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 },
@@ -313,10 +314,11 @@
 	{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 }};
 
 /*
- * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
+ * This allows off board ide-pci cards the enable a BIOS, verify interrupt
  * settings of split-mirror pci-config space, place chipset into init-mode,
  * and/or preserve an interrupt if the card is not native ide support.
  */
@@ -332,7 +334,7 @@
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-static ide_hwif_t __init *lookup_hwif (unsigned long io_base, byte bootable, const char *name)
+static ide_hwif_t __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
 {
 	int h;
 	ide_hwif_t *hwif;
@@ -396,7 +398,8 @@
 
 static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name)
 {
-	byte reg, progif = 0;
+	u8 reg;
+	u8 progif = 0;
 
 	/*
 	 * Place both IDE interfaces into PCI "native" mode:
@@ -428,10 +431,111 @@
 	return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+/*
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ */
+static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char *name)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+	/*
+	 * If we are on the second channel, the dma base address will be one
+	 * entry away from the primary interface.
+	 */
+
+	if (hwif->mate && hwif->mate->dma_base)
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	else
+		dma_base = pci_resource_start(dev, 4);
+
+	if (!dma_base)
+		return 0;
+
+	if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
+		request_region(dma_base + 16, extra, name);
+
+	dma_base += hwif->channel ? 8 : 0;
+	hwif->dma_extra = extra;
+
+	if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
+			(dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) ||
+			(dev->vendor == PCI_VENDOR_ID_CMD && dev->device == PCI_DEVICE_ID_CMD_643)) {
+		outb(inb(dma_base + 2) & 0x60, dma_base+2);
+		if (inb(dma_base + 2) & 0x80)
+			printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
+	} else {
+
+		/*
+		 * If the device claims "simplex" DMA, this means only one of
+		 * the two interfaces can be trusted with DMA at any point in
+		 * time.  So we should enable DMA only on one of the two
+		 * interfaces.
+		 */
+
+		if ((inb(dma_base + 2) & 0x80)) {
+			if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
+					(hwif->mate && hwif->mate->dma_base)) {
+				printk("%s: simplex device:  DMA disabled\n", name);
+				dma_base = 0;
+			}
+		}
+	}
+
+	return dma_base;
+}
+
+/*
+ * Setup DMA transfers on a channel.
+ */
+static void __init setup_channel_dma(ide_hwif_t *hwif, struct pci_dev *dev,
+		ide_pci_device_t *d,
+		int port,
+		u8 class_rev,
+		int pciirq, ide_hwif_t **mate,
+		int autodma, unsigned short *pcicmd)
+{
+	unsigned long dma_base;
+
+	if (d->flags & ATA_F_NOADMA)
+		autodma = 0;
+
+	if (autodma)
+		hwif->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, (!*mate && d->extra) ? d->extra : 0, dev->name);
+	if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) {
+
+		/*
+		 * 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 */
+		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);
+			dma_base = 0;
+		}
+	}
+	if (dma_base) {
+		if (d->dma_init)
+			d->dma_init(hwif, dma_base);
+		else
+			ide_setup_dma(hwif, dma_base, 8);
+	} else
+		printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+}
+#endif
+
 /*
  * Setup a particular port on an ATA host controller.
  *
- * This get's called once for the master and for the slave interface.
+ * This gets called once for the master and for the slave interface.
  */
 static int __init setup_host_channel(struct pci_dev *dev,
 		ide_pci_device_t *d,
@@ -525,9 +629,9 @@
 		}
 	}
 
-	/* Hard wired IRQ lines on UMC chips and no DMA transfers.*/
+	/* Cross wired IRQ lines on UMC chips and no DMA transfers.*/
 	if (d->flags & ATA_F_FIXIRQ) {
-		hwif->irq = hwif->channel ? 15 : 14;
+		hwif->irq = port ? 15 : 14;
 		goto no_dma;
 	}
 	if (d->flags & ATA_F_NODMA)
@@ -540,53 +644,22 @@
 		if (d->ata66_check)
 			hwif->udma_four = d->ata66_check(hwif);
 	}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (d->flags & ATA_F_NOADMA)
-		autodma = 0;
-
-	if (autodma)
-		hwif->autodma = 1;
-
-	if ((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
-		unsigned long dma_base;
-
-		dma_base = ide_get_or_set_dma_base(hwif, (!*mate && d->extra) ? d->extra : 0, dev->name);
-		if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) {
 
-			/*
-			 * 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 */
-			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);
-				dma_base = 0;
-			}
-		}
-		if (dma_base) {
-			if (d->dma_init)
-				d->dma_init(hwif, dma_base);
-			else	/* FIXME: use a generic device descriptor instead */
-				ide_setup_dma(hwif, dma_base, 8);
-		} else {
-			printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
-		}
-	}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	setup_channel_dma(hwif, dev, d, port, class_rev, pciirq,  mate, autodma, pcicmd);
 #endif
+
 no_dma:
 	if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
 		d->init_hwif(hwif);
 
 	*mate = hwif;
 
-	/* we are done */
-
 	return 0;
 }
 
 /*
- * Looks at the primary/secondary chanells on a PCI IDE device and, if they
+ * Looks at the primary/secondary channels on a PCI IDE device and, if they
  * are enabled, prepares the IDE driver for use with them.  This generic code
  * works for most PCI chipsets.
  *
@@ -628,10 +701,11 @@
 	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
 		/*
 		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
-		 *  (or possibly the device is using a "legacy header" for IRQs).
-		 * Maybe the user deliberately *disabled* the device,
-		 * but we'll eventually ignore it again if no drives respond.
+		 * but we can do it ourselves, so long as the BIOS has assigned
+		 * an IRQ (or possibly the device is using a "legacy header"
+		 * for IRQs).  Maybe the user deliberately *disabled* the
+		 * device, but we'll eventually ignore it again if no drives
+		 * respond.
 		 */
 		if (tried_config++
 		 || setup_pci_baseregs(dev, dev->name)
@@ -663,7 +737,7 @@
 	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) {
 		/* By rights we want to ignore these, but the Promise Fastrak
 		   people have some strange ideas about proprietary so we have
-		   to act otherwise on those. The supertrak however we need
+		   to act otherwise on those. The Supertrak however we need
 		   to skip */
 		if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20265) {
 			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
@@ -680,7 +754,7 @@
 	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
 		printk("%s: not 100%% native mode: will probe irqs later\n", dev->name);
 		/*
-		 * This allows offboard ide-pci cards the enable a BIOS,
+		 * This allows off board ide-pci cards the enable a BIOS,
 		 * verify interrupt settings of split-mirror pci-config
 		 * space, place chipset into init-mode, and/or preserve
 		 * an interrupt if the card is not native ide support.
@@ -690,10 +764,10 @@
 		else
 			pciirq = trust_pci_irq(d, dev);
 	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", dev->name);
+		printk("%s: will probe IRQs later\n", dev->name);
 		pciirq = 0;
 	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", dev->name, pciirq);
+		printk("%s: bad IRQ (%d): will probe later\n", dev->name, pciirq);
 		pciirq = 0;
 	} else {
 		if (d->init_chipset)
@@ -729,7 +803,8 @@
 			if ((findev->vendor == dev->vendor) &&
 			    (findev->device == dev->device) &&
 			    (PCI_SLOT(findev->devfn) & 2)) {
-				byte irq = 0, irq2 = 0;
+				u8 irq = 0;
+				u8 irq2 = 0;
 				dev2 = findev;
 				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
 				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
@@ -805,7 +880,7 @@
 }
 
 /*
- * This finds all PCI IDE controllers and calls appriopriate initialization
+ * This finds all PCI IDE controllers and calls appropriate initialization
  * functions for them.
  */
 static void __init ide_scan_pcidev(struct pci_dev *dev)
diff -urN linux-2.5.6-pre2/drivers/ide/ide-probe.c linux-2.5.6-pre3/drivers/ide/ide-probe.c
--- linux-2.5.6-pre2/drivers/ide/ide-probe.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-probe.c	Wed Mar  6 17:17:46 2002
@@ -1,10 +1,6 @@
 /*
- *  linux/drivers/ide/ide-probe.c	Version 1.07	March 18, 2001
- *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- */
-
-/*
+ *
  *  Mostly written by Mark Lord <mlord@pobox.com>
  *                and Gadi Oxman <gadio@netvision.net.il>
  *                and Andre Hedrick <andre@linux-ide.org>
@@ -26,11 +22,9 @@
  *			 with new flag : drive->ata_flash : 1;
  * Version 1.06		stream line request queue and prep for cascade project.
  * Version 1.07		max_sect <= 255; slower disks would get behind and
- * 			then fall over when they get to 256.	Paul G.
+ *			then fall over when they get to 256.	Paul G.
  */
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -94,7 +88,7 @@
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
 		goto err_misc;
 	}
-#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
+#endif
 
 	/*
 	 *  WIN_IDENTIFY returns little-endian info,
@@ -128,7 +122,7 @@
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+#endif
 		switch (type) {
 			case ATA_FLOPPY:
 				if (!strstr(id->model, "CD-ROM")) {
@@ -186,7 +180,11 @@
 	}
 	drive->type = ATA_DISK;
 	printk("ATA DISK drive\n");
-	QUIRK_LIST(HWIF(drive),drive);
+
+	/* Initialize our quirk list. */
+	if (HWIF(drive)->quirkproc)
+		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+
 	return;
 
 err_misc:
@@ -282,24 +280,15 @@
 
 	if (autoprobe) {
 		int irq;
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
-		(void) GET_STAT();			/* clear drive IRQ */
+		OUT_BYTE(drive->ctl | 0x02, IDE_CONTROL_REG);	/* mask device irq */
+		GET_STAT();			/* clear drive IRQ */
 		udelay(5);
 		irq = probe_irq_off(cookie);
 		if (!HWIF(drive)->irq) {
-			if (irq > 0) {
+			if (irq > 0)
 				HWIF(drive)->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
+			else	/* Mmmm.. multiple IRQs.. don't know which was ours */
 				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
-#ifdef CONFIG_BLK_DEV_CMD640
-#ifdef CMD640_DUMP_REGS
-				if (HWIF(drive)->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
-					CMD640_DUMP_REGS;
-				}
-#endif /* CMD640_DUMP_REGS */
-#endif /* CONFIG_BLK_DEV_CMD640 */
-			}
 		}
 	}
 	return retval;
@@ -471,9 +460,11 @@
 	sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
 	sprintf(hwif->device.name, "ide");
 	hwif->device.driver_data = hwif;
+#ifdef CONFIG_BLK_DEV_IDEPCI
 	if (hwif->pci_dev)
 		hwif->device.parent = &hwif->pci_dev->dev;
 	else
+#endif
 		hwif->device.parent = NULL; /* Would like to do = &device_legacy */
 	device_register(&hwif->device);
 
@@ -520,11 +511,11 @@
 	if (hwif->noprobe)
 		return;
 
-	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
+	if (
 #if CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	    (hwif_check_regions(hwif))) {
+#endif
+	    hwif_check_regions(hwif)) {
 		int msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
@@ -550,9 +541,7 @@
 		probe_for_drive (drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
-			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
-				hwif_register(hwif);
-			}
+			hwif_register(hwif);
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
@@ -580,32 +569,6 @@
 	}
 }
 
-#if MAX_HWIFS > 1
-/*
- * save_match() is used to simplify logic in init_irq() below.
- *
- * A loophole here is that we may not know about a particular
- * hwif's irq until after that hwif is actually probed/initialized..
- * This could be a problem for the case where an hwif is on a
- * dual interface that requires serialization (eg. cmd640) and another
- * hwif using one of the same irqs is initialized beforehand.
- *
- * This routine detects and reports such situations, but does not fix them.
- */
-static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
-{
-	ide_hwif_t *m = *match;
-
-	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
-		if (!new->hwgroup)
-			return;
-		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
-	}
-	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
-		*match = new;
-}
-#endif /* MAX_HWIFS > 1 */
-
 /*
  * init request queue
  */
@@ -634,6 +597,33 @@
 	blk_queue_max_phys_segments(q, PRD_ENTRIES);
 }
 
+#if MAX_HWIFS > 1
+
+/*
+ * This is used to simplify logic in init_irq() below.
+ *
+ * A loophole here is that we may not know about a particular hwif's irq until
+ * after that hwif is actually probed/initialized..  This could be a problem
+ * for the case where an hwif is on a dual interface that requires
+ * serialization (eg. cmd640) and another hwif using one of the same irqs is
+ * initialized beforehand.
+ *
+ * This routine detects and reports such situations, but does not fix them.
+ */
+static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+{
+	ide_hwif_t *m = *match;
+
+	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
+		if (!new->hwgroup)
+			return;
+		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+	}
+	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
+		*match = new;
+}
+#endif
+
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -654,15 +644,14 @@
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
-	
+
 	/* Allocate the buffer and potentially sleep first */
-	
+
 	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
-	
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
 
+	spin_lock_irqsave(&ide_lock, flags);
 	hwif->hwgroup = NULL;
+
 #if MAX_HWIFS > 1
 	/*
 	 * Group up with any other hwifs that share our irq(s).
@@ -672,9 +661,8 @@
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
-				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+				if (hwif->chipset != ide_pci || h->chipset != ide_pci)
 					save_match(hwif, h, &match);
-				}
 			}
 			if (hwif->serialized) {
 				if (hwif->mate && hwif->mate->irq == h->irq)
@@ -686,7 +674,7 @@
 			}
 		}
 	}
-#endif /* MAX_HWIFS > 1 */
+#endif
 	/*
 	 * If we are still without a hwgroup, then form a new one
 	 */
@@ -697,7 +685,7 @@
 	} else {
 		hwgroup = new_hwgroup;
 		if (!hwgroup) {
-			restore_flags(flags);	/* all CPUs */
+			spin_unlock_irqrestore(&ide_lock, flags);
 			return 1;
 		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
@@ -717,9 +705,9 @@
 	if (!match || match->irq != hwif->irq) {
 #ifdef CONFIG_IDEPCI_SHARE_IRQ
 		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else /* !CONFIG_IDEPCI_SHARE_IRQ */
+#else
 		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+#endif
 
 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
 			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
@@ -727,13 +715,13 @@
 		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
-			restore_flags(flags);	/* all CPUs */
+			spin_unlock_irqrestore(&ide_lock, flags);
 			return 1;
 		}
 	}
 
 	/*
-	 * Everything is okay, so link us into the hwgroup
+	 * Everything is okay, so link us into the hwgroup.
 	 */
 	hwif->hwgroup = hwgroup;
 	hwif->next = hwgroup->hwif->next;
@@ -755,7 +743,7 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
-	restore_flags(flags);	/* all CPUs; safe now that hwif->hwgroup is set up */
+	spin_unlock_irqrestore(&ide_lock, flags);
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
 	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
diff -urN linux-2.5.6-pre2/drivers/ide/ide-proc.c linux-2.5.6-pre3/drivers/ide/ide-proc.c
--- linux-2.5.6-pre2/drivers/ide/ide-proc.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-proc.c	Wed Mar  6 17:17:46 2002
@@ -161,7 +161,6 @@
 		case ide_trm290:	name = "trm290";	break;
 		case ide_cmd646:	name = "cmd646";	break;
 		case ide_cy82c693:	name = "cy82c693";	break;
-		case ide_4drives:	name = "4drives";	break;
 		case ide_pmac:		name = "mac-io";	break;
 		default:		name = "(unknown)";	break;
 	}
@@ -298,8 +297,8 @@
 			}
 			if (*p != ':')
 				goto parse_error;
-			len = IDE_MIN(p - start, MAX_LEN);
-			strncpy(name, start, IDE_MIN(len, MAX_LEN));
+			len = min(p - start, MAX_LEN);
+			strncpy(name, start, min(len, MAX_LEN));
 			name[len] = 0;
 
 			if (n > 0) {
@@ -307,7 +306,7 @@
 				p++;
 			} else
 				goto parse_error;
-			
+
 			digits = 0;
 			while (n > 0 && (d = ide_getdigit(*p)) >= 0) {
 				val = (val * 10) + d;
@@ -353,7 +352,7 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%llu\n", (unsigned long long) drive->driver->capacity(drive));
+		len = sprintf(page,"%llu\n", (unsigned long long) ata_capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
diff -urN linux-2.5.6-pre2/drivers/ide/ide-tape.c linux-2.5.6-pre3/drivers/ide/ide-tape.c
--- linux-2.5.6-pre2/drivers/ide/ide-tape.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-tape.c	Wed Mar  6 17:17:46 2002
@@ -1504,7 +1504,7 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+		count = min(bio->bi_size - pc->b_count, bcount);
 		atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
 		pc->b_count += bio->bi_size;
@@ -1529,7 +1529,7 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (pc->b_count, bcount);
+		count = min(pc->b_count, bcount);
 		atapi_output_bytes (drive, bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
@@ -1559,7 +1559,7 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bio->bi_size, bcount);
+		count = min(bio->bi_size, bcount);
 		pc->b_count = count;
 		if (pc->b_count == bio->bi_size)
 			bio = bio->bi_next;
@@ -1759,8 +1759,8 @@
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->max_stages += increase;
-	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
-	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
+	tape->max_stages = max(tape->max_stages, tape->min_pipeline);
+	tape->max_stages = min(tape->max_stages, tape->max_pipeline);
 }
 
 /*
@@ -2084,7 +2084,7 @@
 
 	if (!status.b.drq) {						/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
-		tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
+		tape->max_cmd_time = max(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
 			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
@@ -2442,7 +2442,7 @@
 			tape->uncontrolled_pipeline_head_time = jiffies;
 		}
 	}
-	tape->pipeline_head_speed = IDE_MAX(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
+	tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
 	if (tape->speed_control == 0) {
 		tape->max_insert_speed = 5000;
 	} else if (tape->speed_control == 1) {
@@ -2459,7 +2459,7 @@
 			(tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages;
 	} else
 		tape->max_insert_speed = tape->speed_control;
-	tape->max_insert_speed = IDE_MAX(tape->max_insert_speed, 500);
+	tape->max_insert_speed = max(tape->max_insert_speed, 500);
 }
 
 static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
@@ -2920,7 +2920,7 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bio->bi_size - tape->b_count, n);
+		count = min(bio->bi_size - tape->b_count, n);
 		copy_from_user (bio_data(bio) + tape->b_count, buf, count);
 		n -= count;
 		bio->bi_size += count;
@@ -2946,7 +2946,7 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (tape->b_count, n);
+		count = min(tape->b_count, n);
 		copy_to_user (buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
@@ -3878,7 +3878,7 @@
 					printk(KERN_INFO "ide-tape: bug, bio NULL\n");
 					break;
 				}
-				min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+				min = min(i, bio->bi_size - atomic_read(&bio->bi_cnt));
 				memset(bio_data(bio) + bio->bi_size, 0, min);
 				atomic_add(min, &bio->bi_cnt);
 				i -= min;
@@ -4149,11 +4149,11 @@
 	
 	while (bcount) {
 		bio = tape->merge_stage->bio;
-		count = IDE_MIN (tape->stage_size, bcount);
+		count = min(tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
-			atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+			atomic_set(&bio->bi_cnt, min(count, bio->bi_size));
 			memset (bio_data(bio), 0, bio->bi_size);
 			count -= atomic_read(&bio->bi_cnt);
 			bio = bio->bi_next;
@@ -4596,7 +4596,7 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = IDE_MIN (tape->merge_stage_size, count);
+		actually_read = min(tape->merge_stage_size, count);
 		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
@@ -4615,7 +4615,7 @@
 		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = IDE_MIN (count, bytes_read);
+		temp = min(count, bytes_read);
 		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
@@ -4890,7 +4890,7 @@
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
+		actually_written = min(tape->stage_size - tape->merge_stage_size, count);
 		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
@@ -6049,7 +6049,7 @@
 	 *	Select the "best" DSC read/write polling frequency
 	 *	and pipeline size.
 	 */
-	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
+	speed = max(tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
@@ -6075,7 +6075,7 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	tape->best_dsc_rw_frequency = max(min(t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
 	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
 		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
 		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
@@ -6140,7 +6140,12 @@
 
 #endif
 
-static int idetape_reinit(ide_drive_t *drive);
+static void idetape_revalidate(ide_drive_t *_dummy)
+{
+	/* We don't have to handle any partition information here, which is the
+	 * default behaviour of this method.
+	 */
+}
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6149,18 +6154,16 @@
 	owner:			THIS_MODULE,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
-	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
 	ioctl:			idetape_blkdev_ioctl,
 	open:			idetape_blkdev_open,
 	release:		idetape_blkdev_release,
-	media_change:		NULL,
-	revalidate:		NULL,
+	check_media_change:	NULL,
+	revalidate:		idetape_revalidate,
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
-	proc:			idetape_proc,
-	driver_reinit:		idetape_reinit,
+	proc:			idetape_proc
 };
 
 /*
@@ -6175,12 +6178,6 @@
 	release:	idetape_chrdev_release,
 };
 
-/* This will propably just go entierly away... */
-static int idetape_reinit (ide_drive_t *drive)
-{
-	return 1;
-}
-
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
 MODULE_LICENSE("GPL");
 
diff -urN linux-2.5.6-pre2/drivers/ide/ide-taskfile.c linux-2.5.6-pre3/drivers/ide/ide-taskfile.c
--- linux-2.5.6-pre2/drivers/ide/ide-taskfile.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide-taskfile.c	Wed Mar  6 17:17:46 2002
@@ -1,12 +1,8 @@
 /*
- * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
- *
  *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
  *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
  *
  *  May be copied or modified under the terms of the GNU General Public License
- *
- * IDE_DEBUG(__LINE__);
  */
 
 #include <linux/config.h>
@@ -48,7 +44,7 @@
 static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
 {
 	if (rq->bio)
-		return  bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
 	else
 		return rq->buffer + task_rq_offset(rq);
 }
@@ -60,13 +56,6 @@
 	    bio_kunmap_irq(to, flags);
 }
 
-inline u32 task_read_24 (ide_drive_t *drive)
-{
-	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
-}
-
 static void ata_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -85,12 +74,13 @@
  * of the sector count register location, with interrupts disabled
  * to ensure that the reads all happen together.
  */
-static inline void task_vlb_sync (ide_ioreg_t port) {
-	(void) IN_BYTE (port);
-	(void) IN_BYTE (port);
-	(void) IN_BYTE (port);
+static inline void task_vlb_sync(ide_ioreg_t port)
+{
+	IN_BYTE (port);
+	IN_BYTE (port);
+	IN_BYTE (port);
 }
-#endif /* SUPPORT_VLB_SYNC */
+#endif
 
 /*
  * This is used for most PIO data transfers *from* the IDE interface
@@ -121,7 +111,7 @@
 			insl(IDE_DATA_REG, buffer, wcount);
 			__restore_flags(flags);	/* local CPU only */
 		} else
-#endif /* SUPPORT_VLB_SYNC */
+#endif
 			insl(IDE_DATA_REG, buffer, wcount);
 	} else {
 #if SUPPORT_SLOW_DATA_PORTS
@@ -132,7 +122,7 @@
 				*ptr++ = inw_p(IDE_DATA_REG);
 			}
 		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
+#endif
 			insw(IDE_DATA_REG, buffer, wcount<<1);
 	}
 }
@@ -161,7 +151,7 @@
 			outsl(IDE_DATA_REG, buffer, wcount);
 			__restore_flags(flags);	/* local CPU only */
 		} else
-#endif /* SUPPORT_VLB_SYNC */
+#endif
 			outsl(IDE_DATA_REG, buffer, wcount);
 	} else {
 #if SUPPORT_SLOW_DATA_PORTS
@@ -172,7 +162,7 @@
 				outw_p(*ptr++, IDE_DATA_REG);
 			}
 		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
+#endif
 			outsw(IDE_DATA_REG, buffer, wcount<<1);
 	}
 }
@@ -273,7 +263,90 @@
 	return 1;		/* drive ready: *might* be interrupting */
 }
 
-ide_startstop_t bio_mulout_intr (ide_drive_t *drive);
+/*
+ * Polling wait until the drive is ready.
+ *
+ * Stuff the first sector(s) by implicitly calling the handler driectly
+ * therafter.
+ */
+void ata_poll_drive_ready(ide_drive_t *drive)
+{
+	int i;
+
+
+	if (drive_is_ready(drive))
+		return;
+
+	/* FIXME: Replace hard-coded 100, what about error handling?
+	 */
+	for (i = 0; i < 100; ++i) {
+		if (drive_is_ready(drive))
+			break;
+	}
+}
+static ide_startstop_t bio_mulout_intr(ide_drive_t *drive);
+
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+	if (rq->current_nr_sectors == 0) {
+		if (stat & (ERR_STAT|DRQ_STAT))
+			return ide_error(drive, "task_mulout_intr", stat);
+
+		/*
+		 * there may be more, ide_do_request will restart it if
+		 * necessary
+		 */
+		ide_end_request(drive, 1);
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulout_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (hwgroup->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): See task_mulin_intr */
+	msect = drive->mult_count;
+	nsect = rq->current_nr_sectors;
+	if (nsect > msect)
+		nsect = msect;
+
+	pBuf = ide_map_rq(rq, &flags);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+		pBuf, nsect, rq->current_nr_sectors);
+	drive->io_32bit = 0;
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	rq->current_nr_sectors -= nsect;
+	if (hwgroup->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
 ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 {
 	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
@@ -311,7 +384,7 @@
 		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
 		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
 		/*
-		 * warning check for race between handler and prehandler for
+		 * Warning check for race between handler and prehandler for
 		 * writing first block of data.  however since we are well
 		 * inside the boundaries of the seek, we should be okay.
 		 */
@@ -366,310 +439,12 @@
 	}
 }
 
-#if 0
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-
-	/*
-	 * (KS) Check taskfile in/out flags.
-	 * If set, then execute as it is defined.
-	 * If not set, then define default settings.
-	 * The default values are:
-	 *	write and read all taskfile registers (except data) 
-	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
-	 */
-	if (task->tf_out_flags.all == 0) {
-		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
-		}
-        }
-
-	if (task->tf_in_flags.all == 0) {
-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
-		}
-        }
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	if (task->tf_out_flags.b.data) {
-		unsigned short data =  taskfile->data + (hobfile->data << 8);
-		OUT_WORD (data, IDE_DATA_REG);
-	}
-
-	/* (KS) send hob registers first */
-	if (task->tf_out_flags.b.nsector_hob)
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-	if (task->tf_out_flags.b.sector_hob)
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl_hob)
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl_hob)
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-
-
-	/* (KS) Send now the standard registers */
-	if (task->tf_out_flags.b.error_feature)
-		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	/* refers to number of sectors to transfer */
-	if (task->tf_out_flags.b.nsector)
-		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to sector offset or start sector */
-	if (task->tf_out_flags.b.sector)
-		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl)
-		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl)
-		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-        /*
-	 * (KS) Do not modify the specified taskfile. We want to have a
-	 * universal pass through, so we must execute ALL specified values.
-	 *
-	 * (KS) The drive head register is mandatory.
-	 * Don't care about the out flags !
-	 */
-	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
-	if (task->handler != NULL) {
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
-			return task->prehandler(drive, task->rq);
-		}
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
-
-	return ide_started;
-}
-#endif
-
-#if 0
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
-{
-	unsigned long flags;
-	byte err = 0;
-
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
-	printk(" { ");
-	if (stat & BUSY_STAT)
-		printk("Busy ");
-	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
-	}
-	printk("}");
-#endif  /* FANCY_STATUS_DUMPS */
-	printk("\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
-		printk("%s: %s: error=0x%02x", drive->name, msg, err);
-#if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = task_read_24(drive);
-					OUT_BYTE(0x80, IDE_CONTROL_REG);
-					high = task_read_24(drive);
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld", sectors);
-				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
-					} else {
-						printk(", CHS=%d/%d/%d",
-						  (IN_BYTE(IDE_HCYL_REG)<<8) +
-						   IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
-				}
-				if (HWGROUP(drive)->rq)
-					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
-			}
-		}
-#endif  /* FANCY_STATUS_DUMPS */
-		printk("\n");
-	}
-	__restore_flags (flags);	/* local CPU only */
-	return err;
-}
-
-/*
- * Clean up after success/failure of an explicit taskfile operation.
- */
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
-{
-	unsigned long flags;
-	struct request *rq;
-	ide_task_t *args;
-	task_ioreg_t command;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	args = (ide_task_t *) rq->special;
-
-	command = args->tfRegister[IDE_COMMAND_OFFSET];
-
-	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-	args->tfRegister[IDE_ERROR_OFFSET]   = err;
-	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
-	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
-	if ((drive->id->command_set_2 & 0x0400) &&
-	    (drive->id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
-	}
-
-/*	taskfile_settings_update(drive, args, command); */
-
-	spin_lock_irqsave(&ide_lock, flags);
-	blkdev_dequeue_request(rq);
-	HWGROUP(drive)->rq = NULL;
-	end_that_request_last(rq);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * try_to_flush_leftover_data() is invoked in response to a drive
- * unexpectedly having its DRQ_STAT bit set.  As an alternative to
- * resetting the drive, this routine tries to clear the condition
- * by read a sector's worth of data from the drive.  Of course,
- * this may not help if the drive is *waiting* for data from *us*.
- */
-void task_try_to_flush_leftover_data (ide_drive_t *drive)
-{
-	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
-
-	if (drive->media != ide_disk)
-		return;
-	while (i > 0) {
-		u32 buffer[16];
-		unsigned int wcount = (i > 16) ? 16 : i;
-		i -= wcount;
-		taskfile_input_data (drive, buffer, wcount);
-	}
-}
-
-/*
- * taskfile_error() takes action based on the error returned by the drive.
- */
-ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
-{
-	struct request *rq;
-	byte err;
-
-        err = taskfile_dump_status(drive, msg, stat);
-	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return ide_stopped;
-	/* retry only "normal" I/O: */
-	if (rq->flags & REQ_DRIVE_TASKFILE) {
-		rq->errors = 1;
-		ide_end_taskfile(drive, stat, err);
-		return ide_stopped;
-	}
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
-		rq->errors |= ERROR_RESET;
-	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
-			/* err has different meaning on cdrom and tape */
-			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
-				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-				rq->errors |= ERROR_RECAL;
-		}
-		/* pre bio (rq->cmd != WRITE) */
-		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
-			task_try_to_flush_leftover_data(drive);
-	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
-	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			ata_ops(drive)->end_request(0, HWGROUP(drive));
-		else
-			ide_end_request(drive, 0);
-	} else {
-		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-			++rq->errors;
-			return ide_do_reset(drive);
-		}
-		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-			drive->special.b.recalibrate = 1;
-		++rq->errors;
-	}
-	return ide_stopped;
-}
-#endif
-
 /*
  * Handler for special commands without a data phase from ide-disk
  */
 
 /*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ * This is invoked on completion of a WIN_SETMULT cmd.
  */
 ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
@@ -680,15 +455,15 @@
 	} else {
 		drive->mult_req = drive->mult_count = 0;
 		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
+		ide_dump_status(drive, "set_multmode", stat);
 	}
 	return ide_stopped;
 }
 
 /*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ * This is invoked on completion of a WIN_SPECIFY cmd.
  */
-ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
 	byte stat;
 
@@ -703,9 +478,9 @@
 }
 
 /*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ * This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-ide_startstop_t recal_intr (ide_drive_t *drive)
+static ide_startstop_t recal_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
@@ -736,7 +511,7 @@
 /*
  * Handler for command with PIO data-in phase
  */
-ide_startstop_t task_in_intr (ide_drive_t *drive)
+static ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
 	byte stat		= GET_STAT();
 	byte io_32bit		= drive->io_32bit;
@@ -751,7 +526,7 @@
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
 			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
-			return ide_started;  
+			return ide_started;
 		}
 	}
 	DTF("stat: %02x\n", stat);
@@ -777,134 +552,7 @@
 	return ide_stopped;
 }
 
-#undef ALTSTAT_SCREW_UP
-
-#ifdef ALTSTAT_SCREW_UP
-/*
- * (ks/hs): Poll Alternate Status Register to ensure
- * that drive is not busy.
- */
-byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
-{
-	int i;
-
-	DTF("multi%s: ASR = %x\n", msg, stat);
-	if (stat & BUSY_STAT) {
-		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
-		for (i=0; i<100; i++) {
-			stat = GET_ALTSTAT();
-			if ((stat & BUSY_STAT) == 0)
-				break;
-		}
-	}
-	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
-	 */
-	return(GET_STAT());
-}
-
-/*
- * (ks/hs): Poll Alternate status register to wait for drive
- * to become ready for next transfer
- */
-byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
-{
-	/* (ks/hs): FIXME: Error handling, time-out? */
-	while (stat & BUSY_STAT)
-		stat = GET_ALTSTAT();
-	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
-	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
-}
-#endif /* ALTSTAT_SCREW_UP */
-
-/*
- * Handler for command with Read Multiple
- */
-ide_startstop_t task_mulin_intr (ide_drive_t *drive)
-{
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
-	unsigned long flags;
-
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulin_intr", stat);
-		}
-		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
-		 */
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = ide_map_rq(rq, &flags);
-			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-			ide_unmap_rq(rq, pBuf, &flags);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
-		}
-		ide_end_request(drive, 1);
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	do {
-		nsect = rq->current_nr_sectors;
-		if (nsect > msect)
-			nsect = msect;
-
-		pBuf = ide_map_rq(rq, &flags);
-
-		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-			pBuf, nsect, rq->current_nr_sectors);
-		drive->io_32bit = 0;
-		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-		ide_unmap_rq(rq, pBuf, &flags);
-		drive->io_32bit = io_32bit;
-		rq->errors = 0;
-		rq->current_nr_sectors -= nsect;
-		msect -= nsect;
-		if (!rq->current_nr_sectors) {
-			if (!ide_end_request(drive, 1))
-				return ide_stopped;
-		}
-	} while (msect);
-
-
-	/*
-	 * more data left
-	 */
-	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
-	return ide_started;
-}
-
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
 	ide_task_t *args = rq->special;
 	ide_startstop_t startstop;
@@ -924,21 +572,7 @@
 		rq->current_nr_sectors--;
 		ide_unmap_rq(rq, buf, &flags);
 	} else {
-		/*
-		 * (ks/hs): Stuff the first sector(s)
-		 * by implicitly calling the handler
-		 */
-		if (!(drive_is_ready(drive))) {
-			int i;
-			/*
-			 * (ks/hs): FIXME: Replace hard-coded
-			 *               100, error handling?
-			 */
-			for (i=0; i<100; i++) {
-				if (drive_is_ready(drive))
-					break;
-			}
-		}
+		ata_poll_drive_ready(drive);
 		return args->handler(drive);
 	}
 	return ide_started;
@@ -947,7 +581,7 @@
 /*
  * Handler for command with PIO data-out phase
  */
-ide_startstop_t task_out_intr (ide_drive_t *drive)
+static ide_startstop_t task_out_intr(ide_drive_t *drive)
 {
 	byte stat		= GET_STAT();
 	byte io_32bit		= drive->io_32bit;
@@ -978,98 +612,7 @@
 	return ide_started;
 }
 
-/*
- * Handler for command write multiple
- * Called directly from execute_drive_cmd for the first bunch of sectors,
- * afterwards only by the ISR
- */
-ide_startstop_t task_mulout_intr (ide_drive_t *drive)
-{
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
-	unsigned long flags;
-
-	/*
-	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent in this chunk
-	 */
-	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
-			return ide_error(drive, "task_mulout_intr", stat);
-
-		/*
-		 * there may be more, ide_do_request will restart it if
-		 * necessary
-		 */
-		ide_end_request(drive, 1);
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
-		}
-		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = ide_map_rq(rq, &flags);
-			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-			ide_unmap_rq(pBuf, &flags);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
-		}
-		ide_end_request(drive, 1);
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	nsect = rq->current_nr_sectors;
-	if (nsect > msect)
-		nsect = msect;
-
-	pBuf = ide_map_rq(rq, &flags);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	ide_unmap_rq(rq, pBuf, &flags);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
-	return ide_started;
-}
-
-ide_startstop_t pre_bio_out_intr (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq)
 {
 	ide_task_t *args = rq->special;
 	ide_startstop_t startstop;
@@ -1082,34 +625,14 @@
 	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
 		return startstop;
 
-	/*
-	 * (ks/hs): Stuff the first sector(s)
-	 * by implicitly calling the handler
-	 */
-	if (!(drive_is_ready(drive))) {
-		int i;
-		/*
-		 * (ks/hs): FIXME: Replace hard-coded
-		 *               100, error handling?
-		 */
-		for (i=0; i<100; i++) {
-			if (drive_is_ready(drive))
-				break;
-		}
-	}
-
+	ata_poll_drive_ready(drive);
 	return args->handler(drive);
 }
 
 
-ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
+static ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
 {
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
 	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
 	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= &HWGROUP(drive)->wrq;
 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
@@ -1147,8 +670,8 @@
 	}
 
 	do {
-  		char *buffer;
-  		int nsect = rq->current_nr_sectors;
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
 		unsigned long flags;
 
 		if (nsect > mcount)
@@ -1221,6 +744,60 @@
 	return(NULL);
 }
 
+/*
+ * Handler for command with Read Multiple
+ */
+static ide_startstop_t task_mulin_intr(ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulin_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): Fixed Multi-Sector transfer */
+	msect = drive->mult_count;
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+
+		pBuf = ide_map_rq(rq, &flags);
+
+		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+
+
+	/*
+	 * more data left
+	 */
+	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
 /* Called by internal to feature out type of command being called */
 ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
@@ -1316,8 +893,8 @@
 		case WIN_QUEUED_SERVICE:
 		case WIN_PACKETCMD:
 		default:
-			return(NULL);
-	}	
+			return NULL;
+	}
 }
 
 /* Called by ioctl to feature out type of command being called */
@@ -1450,7 +1027,7 @@
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
-void ide_init_drive_taskfile (struct request *rq)
+static void ide_init_drive_taskfile (struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
 	rq->flags = REQ_DRIVE_TASKFILE;
@@ -1463,7 +1040,7 @@
  *
  * ide_raw_taskfile is the one that user-space executes.
  */
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
+int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
 {
 	struct request rq;
 	ide_task_t args;
@@ -1499,7 +1076,7 @@
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *args, byte *buf)
 {
 	struct request rq;
 	ide_init_drive_taskfile(&rq);
@@ -1512,24 +1089,11 @@
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-char * ide_ioctl_verbose (unsigned int cmd)
-{
-	return("unknown");
-}
-
-char * ide_task_cmd_verbose (byte task)
-{
-	return("unknown");
-}
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
-
 /*
  *  The taskfile glue table
  *
  *  reqtask.data_phase	reqtask.req_cmd
- *  			args.command_type		args.handler
+ *			args.command_type		args.handler
  *
  *  TASKFILE_P_OUT_DMAQ	??				??
  *  TASKFILE_P_IN_DMAQ	??				??
@@ -1555,202 +1119,35 @@
  *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
  *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
  *
- *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
- *  			IDE_DRIVE_TASK_INVALID
+ *			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
+ *			IDE_DRIVE_TASK_INVALID
  *
  */
 
-#define MAX_DMA		(256*SECTOR_WORDS)
-
-int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+/*
+ * Issue ATA command and wait for completion. use for implementing commands in
+ * kernel.
+ *
+ * The caller has to make sure buf is never NULL!
+ */
+static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf)
 {
-	ide_task_request_t	*req_task;
-	ide_task_t		args;
-
-	byte *outbuf		= NULL;
-	byte *inbuf		= NULL;
-	task_ioreg_t *argsptr	= args.tfRegister;
-	task_ioreg_t *hobsptr	= args.hobRegister;
-	int err			= 0;
-	int tasksize		= sizeof(struct ide_task_request_s);
-	int taskin		= 0;
-	int taskout		= 0;
-
-	req_task = kmalloc(tasksize, GFP_KERNEL);
-	if (req_task == NULL) return -ENOMEM;
-	memset(req_task, 0, tasksize);
-	if (copy_from_user(req_task, (void *) arg, tasksize)) {
-		kfree(req_task);
-		return -EFAULT;
-	}
-
-	taskout = (int) req_task->out_size;
-	taskin  = (int) req_task->in_size;
-
-	if (taskout) {
-		int outtotal = tasksize;
-		outbuf = kmalloc(taskout, GFP_KERNEL);
-		if (outbuf == NULL) {
-			err = -ENOMEM;
-			goto abort;
-		}
-		memset(outbuf, 0, taskout);
-		if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
-			err = -EFAULT;
-			goto abort;
-		}
-	}
-
-	if (taskin) {
-		int intotal = tasksize + taskout;
-		inbuf = kmalloc(taskin, GFP_KERNEL);
-		if (inbuf == NULL) {
-			err = -ENOMEM;
-			goto abort;
-		}
-		memset(inbuf, 0, taskin);
-		if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
-			err = -EFAULT;
-			goto abort;
-		}
-	}
-
-	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
-	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
-	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
-	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
-
-	args.tf_in_flags  = req_task->in_flags;
-	args.tf_out_flags = req_task->out_flags;
-	args.data_phase   = req_task->data_phase;
-	args.command_type = req_task->req_cmd;
-
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-	DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
-		drive->name,
-		ide_ioctl_verbose(cmd),
-		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
-
-	switch(req_task->data_phase) {
-		case TASKFILE_OUT_DMAQ:
-		case TASKFILE_OUT_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
-			break;
-		case TASKFILE_IN_DMAQ:
-		case TASKFILE_IN_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
-			break;
-		case TASKFILE_IN_OUT:
-#if 0
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
-			break;
-#else
-			err = -EFAULT;
-			goto abort;
-#endif
-		case TASKFILE_MULTI_OUT:
-			if (drive->mult_count) {
-				args.prehandler = &pre_task_out_intr;
-				args.handler = &task_mulout_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, outbuf);
-			} else {
-				/* (hs): give up if multcount is not set */
-				printk("%s: %s Multimode Write " \
-					"multcount is not set\n",
-					 drive->name, __FUNCTION__);
-				err = -EPERM;
-				goto abort;
-			}
-			break;
-		case TASKFILE_OUT:
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
-			break;
-		case TASKFILE_MULTI_IN:
-			if (drive->mult_count) {
-				args.prehandler = NULL;
-				args.handler = &task_mulin_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, inbuf);
-			} else {
-				/* (hs): give up if multcount is not set */
-				printk("%s: %s Multimode Read failure " \
-					"multcount is not set\n",
-					drive->name, __FUNCTION__);
-				err = -EPERM;
-				goto abort;
-			}
-			break;
-		case TASKFILE_IN:
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
-			break;
-		case TASKFILE_NO_DATA:
-			args.prehandler = NULL;
-			args.handler = &task_no_data_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, NULL);
-			break;
-		default:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = -EFAULT;
-			goto abort;
-	}
+	struct request rq;
 
-	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
-	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
-	req_task->in_flags  = args.tf_in_flags;
-	req_task->out_flags = args.tf_out_flags;
+	/* FIXME: Do we really have to zero out the buffer?
+	 */
+	memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = argbuf;
+	*argbuf++ = cmd;
+	*argbuf++ = nsect;
+	*argbuf++ = feature;
+	*argbuf++ = sectors;
 
-	if (copy_to_user((void *)arg, req_task, tasksize)) {
-		err = -EFAULT;
-		goto abort;
-	}
-	if (taskout) {
-		int outtotal = tasksize;
-		if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
-			err = -EFAULT;
-			goto abort;
-		}
-	}
-	if (taskin) {
-		int intotal = tasksize + taskout;
-		if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
-			err = -EFAULT;
-			goto abort;
-		}
-	}
-abort:
-	kfree(req_task);
-	if (outbuf != NULL)
-		kfree(outbuf);
-	if (inbuf != NULL)
-		kfree(inbuf);
-	return err;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
 	byte args[4], *argbuf = args;
@@ -1806,19 +1203,26 @@
 int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
-	byte args[7], *argbuf = args;
+	u8 args[7];
+	u8 *argbuf;
 	int argsize = 7;
+	struct request rq;
+
+	argbuf = args;
 
 	if (copy_from_user(args, (void *)arg, 7))
 		return -EFAULT;
-	err = ide_wait_cmd_task(drive, argbuf);
+
+	ide_init_drive_cmd(&rq);
+	rq.flags = REQ_DRIVE_TASK;
+	rq.buffer = argbuf;
+	err = ide_do_drive_cmd(drive, &rq, ide_wait);
 	if (copy_to_user((void *)arg, argbuf, argsize))
 		err = -EFAULT;
 	return err;
 }
 
 EXPORT_SYMBOL(drive_is_ready);
-EXPORT_SYMBOL(task_read_24);
 EXPORT_SYMBOL(ata_input_data);
 EXPORT_SYMBOL(ata_output_data);
 EXPORT_SYMBOL(atapi_input_bytes);
@@ -1827,166 +1231,15 @@
 EXPORT_SYMBOL(taskfile_output_data);
 EXPORT_SYMBOL(do_rw_taskfile);
 EXPORT_SYMBOL(do_taskfile);
-// EXPORT_SYMBOL(flagged_taskfile);
-
-//EXPORT_SYMBOL(ide_end_taskfile);
 
 EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
 
 EXPORT_SYMBOL(task_no_data_intr);
-EXPORT_SYMBOL(task_in_intr);
-EXPORT_SYMBOL(task_mulin_intr);
-EXPORT_SYMBOL(pre_task_out_intr);
-EXPORT_SYMBOL(task_out_intr);
-EXPORT_SYMBOL(task_mulout_intr);
 
-EXPORT_SYMBOL(ide_init_drive_taskfile);
 EXPORT_SYMBOL(ide_wait_taskfile);
 EXPORT_SYMBOL(ide_raw_taskfile);
 EXPORT_SYMBOL(ide_pre_handler_parser);
 EXPORT_SYMBOL(ide_handler_parser);
 EXPORT_SYMBOL(ide_cmd_type_parser);
-EXPORT_SYMBOL(ide_taskfile_ioctl);
 EXPORT_SYMBOL(ide_cmd_ioctl);
 EXPORT_SYMBOL(ide_task_ioctl);
-
-
-#ifdef CONFIG_PKT_TASK_IOCTL
-
-#if 0
-{
-
-{ /* start cdrom */
-
-	struct cdrom_info *info = drive->driver_data;
-
-	if (info->dma) {
-		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
-		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
-		} else {
-			printk("ide-cd: DMA set, but not allowed\n");
-		}
-	}
-
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
-
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return ide_started;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
-	}
-
-} /* end cdrom */
-
-{ /* start floppy */
-
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
-
-	floppy->pc=pc;		/* Set the current packet command */
-
-	pc->retries++;
-	pc->actually_transferred=0; /* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-} /* end floppy */
-
-{ /* start tape */
-
-	idetape_tape_t *tape = drive->driver_data;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return ide_started;
-	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idetape_transfer_pc(drive);
-	}
-
-} /* end tape */
-
-}
-#endif
-
-int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-#if 0
-	switch(req_task->data_phase) {
-		case TASKFILE_P_OUT_DMAQ:
-		case TASKFILE_P_IN_DMAQ:
-		case TASKFILE_P_OUT_DMA:
-		case TASKFILE_P_IN_DMA:
-		case TASKFILE_P_OUT:
-		case TASKFILE_P_IN:
-	}
-#endif
-	return -ENOMSG;
-}
-
-EXPORT_SYMBOL(pkt_taskfile_ioctl);
-
-#endif /* CONFIG_PKT_TASK_IOCTL */
diff -urN linux-2.5.6-pre2/drivers/ide/ide.c linux-2.5.6-pre3/drivers/ide/ide.c
--- linux-2.5.6-pre2/drivers/ide/ide.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/ide.c	Wed Mar  6 17:17:46 2002
@@ -1,8 +1,6 @@
 /*
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- */
-
-/*
+ *
  *  Mostly written by Mark Lord  <mlord@pobox.com>
  *                and Gadi Oxman <gadio@netvision.net.il>
  *                and Andre Hedrick <andre@linux-ide.org>
@@ -119,8 +117,6 @@
 
 #define	VERSION	"7.0.0"
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -135,8 +131,8 @@
 #include <linux/blkpg.h>
 #include <linux/slab.h>
 #ifndef MODULE
-#include <linux/init.h>
-#endif /* MODULE */
+# include <linux/init.h>
+#endif
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -155,9 +151,52 @@
 
 #include "ide_modes.h"
 
-/* Constant tables for PIO mode programming:
+/*
+ * 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
+#ifdef CONFIG_BLK_DEV_CMD640
+extern void ide_probe_for_cmd640x(void);
+#endif
+#ifdef CONFIG_BLK_DEV_PDC4030
+extern int ide_probe_for_pdc4030(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+extern void pmac_ide_probe(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+extern void icside_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+extern void rapide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_GAYLE
+extern void gayle_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+extern void falconide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+extern void macide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_Q40IDE
+extern void q40ide_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_BUDDHA
+extern void buddha_init(void);
+#endif
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+extern void pnpide_init(int);
+#endif
 
+/*
+ * Constant tables for PIO mode programming:
+ */
 const ide_pio_timings_t ide_pio_timings[6] = {
 	{ 70,	165,	600 },	/* PIO Mode 0 */
 	{ 50,	125,	383 },	/* PIO Mode 1 */
@@ -174,7 +213,7 @@
 static struct ide_pio_info {
 	const char	*name;
 	int		pio;
-} ide_pio_blacklist [] = {
+} ide_pio_blacklist[] = {
 /*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
 	{ "Conner Peripherals 540MB - CFS540A", 3 },
 
@@ -224,8 +263,8 @@
 	{ "ST3600A",  1 },
 	{ "ST3290A",  0 },
 	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on
+				 * drive) according to Seagates FIND-ATA program */
 
 	{ "QUANTUM ELS127A", 0 },
 	{ "QUANTUM ELS170A", 0 },
@@ -238,7 +277,7 @@
 	{ "QUANTUM LIGHTNING 730A", 3 },
 
         { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_640", 3 },
         { "QUANTUM FIREBALL_1080", 3 },
         { "QUANTUM FIREBALL_1280", 3 },
 	{ NULL,	0 }
@@ -247,34 +286,33 @@
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES	1
 
-static int	idebus_parameter; /* holds the "idebus=" parameter */
-int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
-static int	initializing;     /* set while initializing built-in drivers */
+static int idebus_parameter;	/* holds the "idebus=" parameter */
+int system_bus_speed;		/* holds what we think is VESA/PCI bus speed */
+static int initializing;	/* set while initializing built-in drivers */
 
 /*
- * protects global structures etc, we want to split this into per-hwgroup
- * instead.
+ * Protects access to global structures etc.
  */
 spinlock_t ide_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
-static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
+#endif
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 /*
- * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
+ * This is used by the Atari code to obtain access to the IDE interrupt,
  * which is shared between several drivers.
  */
 static int	ide_intr_lock;
-#endif /* __mc68000__ || CONFIG_APUS */
+#endif
 
 int noautodma = 0;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
 
 
 /*
@@ -378,7 +416,7 @@
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
- * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * For really screwed hardware (hey, at least it *can* be used with Linux)
  * we can enforce a minimum delay time between successive operations.
  */
 static unsigned long read_timer (void)
@@ -389,7 +427,7 @@
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
 	t = jiffies * 11932;
-    	outb_p(0, 0x43);
+	outb_p(0, 0x43);
 	i = inb_p(0x40);
 	i |= inb(0x40) << 8;
 	__restore_flags(flags);	/* local CPU only */
@@ -476,7 +514,7 @@
 		return;		/* already initialized */
 	magic_cookie = 0;
 
-	/* Initialise all interface structures */
+	/* Initialize all interface structures */
 	for (index = 0; index < MAX_HWIFS; ++index)
 		init_hwif_data(index);
 
@@ -487,11 +525,13 @@
 }
 
 /*
- * CompactFlash cards and their brethern pretend to be removable hard disks, except:
+ * CompactFlash cards and their relatives pretend to be removable hard disks, except:
  *	(1) they never have a slave unit, and
- *	(2) they don't have doorlock mechanisms.
+ *	(2) they don't have a door lock mechanisms.
  * This test catches them, and is invoked elsewhere when setting appropriate config bits.
  *
+ * FIXME FIXME: Yes this is for certain applicable for all of them as time has shown.
+ *
  * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
  * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
  * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
@@ -503,7 +543,8 @@
 	struct hd_driveid *id = drive->id;
 
 	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (id->config == 0x848a)
+			return 1;	/* CompactFlash */
 		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
 		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
 		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
@@ -581,15 +622,76 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+static void ata_pre_reset (ide_drive_t *drive)
+{
+	if (ata_ops(drive) && ata_ops(drive)->pre_reset)
+		ata_ops(drive)->pre_reset(drive);
+
+	if (!drive->keep_settings && !drive->using_dma) {
+		drive->unmask = 0;
+		drive->io_32bit = 0;
+	}
+
+	if (drive->using_dma) {
+		/* check the DMA crc count */
+		if (drive->crc_count) {
+			HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
+			if ((HWIF(drive)->speedproc) != NULL)
+				HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+			if (drive->current_speed >= XFER_SW_DMA_0)
+				HWIF(drive)->dmaproc(ide_dma_on, drive);
+		} else
+			HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+}
+
 /*
  * The capacity of a drive according to its current geometry/LBA settings in
  * sectors.
  */
-unsigned long current_capacity (ide_drive_t *drive)
+unsigned long ata_capacity(ide_drive_t *drive)
 {
 	if (!drive->present || !drive->driver)
 		return 0;
-	return ata_ops(drive)->capacity(drive);
+
+	if (ata_ops(drive) && ata_ops(drive)->capacity)
+		return ata_ops(drive)->capacity(drive);
+
+	/* FIXME: This magic number seems to be bogous. */
+	return 0x7fffffff;
+}
+
+/*
+ * This is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT commands to
+ * a drive.  It used to do much more, but has been scaled back.
+ */
+static ide_startstop_t ata_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+#ifdef DEBUG
+	printk("%s: ata_special: 0x%02x\n", drive->name, s->all);
+#endif
+	if (s->b.set_tune) {
+		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+		s->b.set_tune = 0;
+		if (tuneproc != NULL)
+			tuneproc(drive, drive->tune_req);
+	} else if (drive->driver != NULL) {
+		if (ata_ops(drive)->special)
+			return ata_ops(drive)->special(drive);
+		else {
+			drive->special.all = 0;
+			drive->mult_req = 0;
+
+			return ide_stopped;
+		}
+	} else if (s->all) {
+		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
+		s->all = 0;
+	}
+
+	return ide_stopped;
 }
 
 extern struct block_device_operations ide_fops[];
@@ -612,17 +714,16 @@
 		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
 			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-			1<<PARTN_BITS, ide_fops,
-			current_capacity(drive));
+#endif
+			1 << PARTN_BITS, ide_fops, ata_capacity(drive));
 	}
 }
 
 static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
 
 /*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
+ * ATAPI_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ATAPI drive reset operation. If the drive has not yet responded,
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  */
@@ -695,44 +796,13 @@
 			printk("\n");
 #else
 			printk("failed\n");
-#endif /* FANCY_STATUS_DUMPS */
+#endif
 		}
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
 	return ide_stopped;
 }
 
-static void check_dma_crc (ide_drive_t *drive)
-{
-	if (drive->crc_count) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
-		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
-	} else {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-}
-
-static void pre_reset (ide_drive_t *drive)
-{
-	if (drive->driver != NULL)
-		ata_ops(drive)->pre_reset(drive);
-
-	if (!drive->keep_settings) {
-		if (drive->using_dma) {
-			check_dma_crc(drive);
-		} else {
-			drive->unmask = 0;
-			drive->io_32bit = 0;
-		}
-		return;
-	}
-	if (drive->using_dma)
-		check_dma_crc(drive);
-}
-
 /*
  * do_reset1() attempts to recover a confused drive by resetting it.
  * Unfortunately, resetting a disk drive actually resets all devices on
@@ -745,7 +815,7 @@
  * Unfortunately, the IDE interface does not generate an interrupt to let
  * us know when the reset operation has finished, so we must poll for this.
  * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * (up to 30 seconds worst case).  So, instead of busy-waiting here for it,
  * we set a timer to poll at 50ms intervals.
  */
 static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
@@ -760,7 +830,7 @@
 
 	/* For an ATAPI device, first try an ATAPI SRST. */
 	if (drive->type != ATA_DISK && !do_not_try_atapi) {
-		pre_reset(drive);
+		ata_pre_reset(drive);
 		SELECT_DRIVE(hwif,drive);
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
@@ -775,7 +845,7 @@
 	 * for any of the drives on this interface.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		pre_reset(&hwif->drives[unit]);
+		ata_pre_reset(&hwif->drives[unit]);
 
 #if OK_TO_RESET_CONTROLLER
 	if (!IDE_CONTROL_REG) {
@@ -809,7 +879,7 @@
 	if (hwif->resetproc != NULL)
 		hwif->resetproc(drive);
 
-#endif	/* OK_TO_RESET_CONTROLLER */
+#endif
 
 	__restore_flags (flags);	/* local CPU only */
 	return ide_started;
@@ -1011,11 +1081,6 @@
 	/* retry only "normal" I/O: */
 	if (!(rq->flags & REQ_CMD)) {
 		rq->errors = 1;
-#if 0
-		if (rq->flags & REQ_DRIVE_TASKFILE)
-			ide_end_taskfile(drive, stat, err);
-		else
-#endif
 		ide_end_drive_cmd(drive, stat, err);
 		return ide_stopped;
 	}
@@ -1044,7 +1109,7 @@
 
 	if (rq->errors >= ERROR_MAX) {
 		/* ATA-PATTERN */
-		if (drive->driver != NULL)
+		if (ata_ops(drive) && ata_ops(drive)->end_request)
 			ata_ops(drive)->end_request(drive, 0);
 		else
 			ide_end_request(drive, 0);
@@ -1101,31 +1166,6 @@
 }
 
 /*
- * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back.
- */
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-#ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_tune = 0;
-		if (tuneproc != NULL)
-			tuneproc(drive, drive->tune_req);
-	} else if (drive->driver != NULL) {
-		return ata_ops(drive)->special(drive);
-	} else if (s->all) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
-		s->all = 0;
-	}
-	return ide_stopped;
-}
-
-/*
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
  * of the "bad" bits, and if all is okay it returns 0.  All other
@@ -1140,7 +1180,7 @@
 	byte stat;
 	int i;
 	unsigned long flags;
- 
+
 	/* bail early if we've exceeded max_failures */
 	if (drive->max_failures && (drive->failures > drive->max_failures)) {
 		*startstop = ide_stopped;
@@ -1186,39 +1226,13 @@
 	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = rq->special;
 
-		if (!(args)) goto args_error;
-
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-	{
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
-	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
-	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
-	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
-	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
-	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
-	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
-	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
-	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
-	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
-	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
-	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
-	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
-	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
-	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
-	}
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+		if (!(args))
+			goto args_error;
 
-//		if (args->tf_out_flags.all == 0) {
-			do_taskfile(drive,
+		do_taskfile(drive,
 				(struct hd_drive_task_hdr *)&args->tfRegister,
 				(struct hd_drive_hob_hdr *)&args->hobRegister,
 				args->handler);
-//		} else {
-//				return flagged_taskfile(drive, args);
-//		}
 
 		if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
 		     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
@@ -1338,16 +1352,21 @@
 		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
 			return execute_drive_cmd(drive, rq);
 
-		if (drive->driver != NULL) {
-			return ata_ops(drive)->do_request(drive, rq, block);
+		if (ata_ops(drive)) {
+			if (ata_ops(drive)->do_request)
+				return ata_ops(drive)->do_request(drive, rq, block);
+			else {
+				ide_end_request(drive, 0);
+				return ide_stopped;
+			}
 		}
 		printk(KERN_WARNING "%s: device type %d not supported\n",
 		       drive->name, drive->type);
 		goto kill_rq;
 	}
-	return do_special(drive);
+	return ata_special(drive);
 kill_rq:
-	if (drive->driver != NULL)
+	if (ata_ops(drive) && ata_ops(drive)->end_request)
 		ata_ops(drive)->end_request(drive, 0);
 	else
 		ide_end_request(drive, 0);
@@ -1389,7 +1408,7 @@
 {
 	ide_drive_t *drive, *best;
 
-repeat:	
+repeat:
 	best = NULL;
 	drive = hwgroup->drive;
 	do {
@@ -1416,7 +1435,7 @@
 				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
 				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
 				{
-					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+					ide_stall_queue(best, min(t, 10 * WAIT_MIN_SLEEP));
 					goto repeat;
 				}
 			} while ((drive = drive->next) != best);
@@ -1455,7 +1474,7 @@
  * will start the next request from the queue.  If no more work remains,
  * the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
  */
-static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
@@ -1502,7 +1521,11 @@
 		hwif = HWIF(drive);
 		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
 			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(hwif, drive);
+
+			if (hwif->intrproc)
+				hwif->intrproc(drive);
+			else
+				OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
@@ -1539,7 +1562,7 @@
 }
 
 /*
- * ide_get_queue() returns the queue which corresponds to a given device.
+ * Returns the queue which corresponds to a given device.
  */
 request_queue_t *ide_get_queue (kdev_t dev)
 {
@@ -1558,7 +1581,7 @@
 
 /*
  * un-busy the hwgroup etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
+ * retry the current request in PIO mode instead of risking tossing it
  * all away
  */
 void ide_dma_timeout_retry(ide_drive_t *drive)
@@ -1569,13 +1592,13 @@
 	/*
 	 * end current dma transaction
 	 */
-	(void) hwif->dmaproc(ide_dma_end, drive);
+	hwif->dmaproc(ide_dma_end, drive);
 
 	/*
 	 * complain a little, later we might remove some of this verbosity
 	 */
 	printk("%s: timeout waiting for DMA\n", drive->name);
-	(void) hwif->dmaproc(ide_dma_timeout, drive);
+	hwif->dmaproc(ide_dma_timeout, drive);
 
 	/*
 	 * disable dma for now, but remember that we did so because of
@@ -1584,7 +1607,7 @@
 	 */
 	drive->retry_pio++;
 	drive->state = DMA_PIO_RETRY;
-	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
+	hwif->dmaproc(ide_dma_off_quietly, drive);
 
 	/*
 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1611,7 +1634,7 @@
 	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
 	ide_handler_t	*handler;
 	ide_expiry_t	*expiry;
- 	unsigned long	flags;
+	unsigned long	flags;
 	unsigned long	wait;
 
 	/*
@@ -1712,7 +1735,7 @@
  * drive is ready to accept one, in which case we know the drive is not
  * trying to interrupt us.  And ide_set_handler() is always invoked before
  * completing the issuance of any new drive command, so we will not be
- * accidently invoked as a result of any valid command completion interrupt.
+ * accidentally invoked as a result of any valid command completion interrupt.
  *
  */
 static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
@@ -1937,16 +1960,6 @@
 
 }
 
-/* Common for ide-floppy.c and ide-disk.c */
-void ide_revalidate_drive (ide_drive_t *drive)
-{
-        struct gendisk *g = HWIF(drive)->gd;
-        int minor = (drive->select.b.unit << g->minor_shift);
-        kdev_t dev = mk_kdev(g->major, minor);
-
-        grok_partitions(dev, current_capacity(drive));
-}
-
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -1975,13 +1988,16 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 
 	res = wipe_partitions(i_rdev);
-	if (res)
-		goto leave;
-
-	if (ata_ops(drive)->revalidate)
-		ata_ops(drive)->revalidate(drive);
+	if (!res) {
+		if (ata_ops(drive) && ata_ops(drive)->revalidate) {
+			ata_get(ata_ops(drive));
+			/* this is a no-op for tapes and SCSI based access */
+			ata_ops(drive)->revalidate(drive);
+			ata_put(ata_ops(drive));
+		} else
+			grok_partitions(i_rdev, ata_capacity(drive));
+	}
 
- leave:
 	drive->busy = 0;
 	wake_up(&drive->wqueue);
 	MOD_DEC_USE_COUNT;
@@ -1990,13 +2006,14 @@
 
 /*
  * Look again for all drives in the system on all interfaces.  This is used
- * after a new driver cathegory has been loaded as module.
+ * after a new driver category has been loaded as module.
  */
-void revalidate_drives (void)
+void revalidate_drives(void)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
-	int index, unit;
+	int index;
+	int unit;
 
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		hwif = &ide_hwifs[index];
@@ -2011,7 +2028,7 @@
 	}
 }
 
-static void ide_probe_module (void)
+static void ide_probe_module(void)
 {
 	ideprobe_init();
 	revalidate_drives();
@@ -2030,7 +2047,7 @@
 	revalidate_drives();
 }
 
-static int ide_open (struct inode * inode, struct file * filp)
+static int ide_open(struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
 
@@ -2048,35 +2065,42 @@
 
 #ifdef CONFIG_KMOD
 	if (drive->driver == NULL) {
+		char *module = NULL;
+
 		switch (drive->type) {
 			case ATA_DISK:
-				request_module("ide-disk");
+				module = "ide-disk";
 				break;
 			case ATA_ROM:
-				request_module("ide-cd");
+				module = "ide-cd";
 				break;
 			case ATA_TAPE:
-				request_module("ide-tape");
+				module = "ide-tape";
 				break;
 			case ATA_FLOPPY:
-				request_module("ide-floppy");
+				module = "ide-floppy";
 				break;
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
 			case ATA_SCSI:
-				request_module("ide-scsi");
+				module = "ide-scsi";
 				break;
-#endif
 			default:
-				/* nothing to be done about it */ ;
+				/* nothing we can do about it */ ;
 		}
+		if (module)
+			request_module(module);
 	}
-#endif /* CONFIG_KMOD */
+#endif
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
-	drive->usage++;
-	if (drive->driver != NULL)
+	++drive->usage;
+	if (ata_ops(drive) && ata_ops(drive)->open)
 		return ata_ops(drive)->open(inode, filp, drive);
-	printk ("%s: driver not present\n", drive->name);
+	else {
+		--drive->usage;
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
 }
@@ -2085,15 +2109,16 @@
  * Releasing a block device means we sync() it, so that it can safely
  * be forgotten about...
  */
-static int ide_release (struct inode * inode, struct file * file)
+static int ide_release(struct inode * inode, struct file * file)
 {
 	ide_drive_t *drive;
 
-	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
-		drive->usage--;
-		if (drive->driver != NULL)
-			ata_ops(drive)->release(inode, file, drive);
-	}
+	if (!(drive = get_info_ptr(inode->i_rdev)))
+		return 0;
+
+	drive->usage--;
+	if (ata_ops(drive) && ata_ops(drive)->release)
+		ata_ops(drive)->release(inode, file, drive);
 	return 0;
 }
 
@@ -2136,7 +2161,7 @@
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
 		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+#endif
 }
 
 void ide_unregister (unsigned int index)
@@ -2164,11 +2189,16 @@
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && ata_ops(drive)->cleanup(drive))
-			goto abort;
+		if (ata_ops(drive)) {
+			if (ata_ops(drive)->cleanup) {
+				if (ata_ops(drive)->cleanup(drive))
+					goto abort;
+			} else
+				ide_unregister_subdriver(drive);
+		}
 	}
 	hwif->present = 0;
-	
+
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
@@ -2268,7 +2298,7 @@
 		hwif->gd = NULL;
 	}
 	old_hwif		= *hwif;
-	init_hwif_data (index);	/* restore hwif data to pristine status */
+	init_hwif_data(index);	/* restore hwif data to pristine status */
 	hwif->hwgroup		= old_hwif.hwgroup;
 	hwif->tuneproc		= old_hwif.tuneproc;
 	hwif->speedproc		= old_hwif.speedproc;
@@ -2289,14 +2319,14 @@
 	hwif->proc		= old_hwif.proc;
 #ifndef CONFIG_BLK_DEV_IDECS
 	hwif->irq		= old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
+#endif
 	hwif->major		= old_hwif.major;
 	hwif->chipset		= old_hwif.chipset;
 	hwif->autodma		= old_hwif.autodma;
 	hwif->udma_four		= old_hwif.udma_four;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	hwif->pci_dev		= old_hwif.pci_dev;
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 	hwif->straight8		= old_hwif.straight8;
 abort:
 	restore_flags(flags);	/* all CPUs */
@@ -2342,7 +2372,7 @@
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
  */
-int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
 {
 	int index, retry = 1;
 	ide_hwif_t *hwif;
@@ -2392,7 +2422,7 @@
  * Compatability function with existing drivers.  If you want
  * something different, use the function above.
  */
-int ide_register (int arg1, int arg2, int irq)
+int ide_register(int arg1, int arg2, int irq)
 {
 	hw_regs_t hw;
 	ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
@@ -2503,7 +2533,7 @@
 
 /*
  * FIXME:  This should be changed to enqueue a special request
- * to the driver to change settings, and then wait on a sema for completion.
+ * to the driver to change settings, and then wait on a semaphore for completion.
  * The current scheme of polling is kludgey, though safe enough.
  */
 int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
@@ -2595,33 +2625,6 @@
 	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
 }
 
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
-{
-	struct request rq;
-	byte buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.flags = REQ_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 /*
  * Delay for *at least* 50ms.  As we don't know how much time is left
  * until the next tick occurs, we wait an extra tick to be safe.
@@ -2721,7 +2724,8 @@
 		}
 
 		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
 			return ide_revalidate_disk(inode->i_rdev);
 
 		case HDIO_OBSOLETE_IDENTITY:
@@ -2742,24 +2746,6 @@
 					drive->nice2		<<	IDE_NICE_2,
 					(long *) arg);
 
-#ifdef CONFIG_IDE_TASK_IOCTL
-		case HDIO_DRIVE_TASKFILE:
-		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-				return -EACCES;
-			switch(drive->type) {
-				case ATA_DISK:
-					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
-#ifdef CONFIG_PKT_TASK_IOCTL
-				case ATA_CDROM:
-				case ATA_TAPE:
-				case ATA_FLOPPY:
-					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
-#endif
-				default:
-					return -ENOMSG;
-			}
-#endif /* CONFIG_IDE_TASK_IOCTL */
-
 		case HDIO_DRIVE_CMD:
 			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 				return -EACCES;
@@ -2807,28 +2793,15 @@
 			spin_lock_irqsave(&ide_lock, flags);
 			if (hwgroup->handler != NULL) {
 				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
-				(void) hwgroup->handler(drive);
-//				hwgroup->handler = NULL;
-//				hwgroup->expiry	= NULL;
+				hwgroup->handler(drive);
 				hwgroup->timer.expires = jiffies + 0;;
 				del_timer(&hwgroup->timer);
 			}
 			spin_unlock_irqrestore(&ide_lock, flags);
-
 #endif
-			(void) ide_do_reset(drive);
-			if (drive->suspend_reset) {
-/*
- *				APM WAKE UP todo !!
- *				int nogoodpower = 1;
- *				while(nogoodpower) {
- *					check_power1() or check_power2()
- *					nogoodpower = 0;
- *				} 
- *				HWIF(drive)->multiproc(drive);
- */
+			ide_do_reset(drive);
+			if (drive->suspend_reset)
 				return ide_revalidate_disk(inode->i_rdev);
-			}
 			return 0;
 		}
 		case BLKGETSIZE:
@@ -2842,7 +2815,7 @@
 		case BLKELVSET:
 		case BLKBSZGET:
 		case BLKBSZSET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		/*
 		 * uniform packet command handling
@@ -2866,9 +2839,9 @@
 			return 0;
 
 		default:
-			if (drive->driver != NULL)
+			if (ata_ops(drive) && ata_ops(drive)->ioctl)
 				return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg);
-			return -EPERM;
+			return -EINVAL;
 	}
 }
 
@@ -2878,8 +2851,14 @@
 
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
-	if (drive->driver != NULL)
-		return ata_ops(drive)->media_change(drive);
+	if (ata_ops(drive)) {
+		ata_get(ata_ops(drive));
+		if (ata_ops(drive)->check_media_change)
+			return ata_ops(drive)->check_media_change(drive);
+		else
+			return 1; /* assume it was changed */
+		ata_put(ata_ops(drive));
+	}
 	return 0;
 }
 
@@ -2975,9 +2954,11 @@
 }
 
 /*
- * ide_setup() gets called VERY EARLY during initialization,
- * to handle kernel "command line" strings beginning with "hdx="
- * or "ide".  Here is the complete set currently supported:
+ * This gets called VERY EARLY during initialization, to handle kernel "command
+ * line" strings beginning with "hdx=" or "ide".It gets called even before the
+ * actual module gets initialized.
+ *
+ * Here is the complete set currently supported comand line options:
  *
  * "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
  * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
@@ -3017,7 +2998,7 @@
  *				As for VLB, it is safest to not specify it.
  *
  * "idex=noprobe"	: do not attempt to access/use this interface
- * "idex=base"		: probe for an interface at the addr specified,
+ * "idex=base"		: probe for an interface at the address specified,
  *				where "base" is usually 0x1f0 or 0x170
  *				and "ctl" is assumed to be "base"+0x206
  * "idex=base,ctl"	: specify both base and ctl
@@ -3063,8 +3044,8 @@
 	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
 	const char max_hwif  = '0' + (MAX_HWIFS - 1);
 
-	if (strncmp(s,"hd",2) == 0 && s[2] == '=')	/* hd= is for hd.c   */
-		return 0;				/* driver and not us */
+	if (!strncmp(s, "hd=", 3))	/* hd= is for hd.c driver and not us */
+		return 0;
 
 	if (strncmp(s,"ide",3) &&
 	    strncmp(s,"idebus",6) &&
@@ -3082,7 +3063,7 @@
 		ide_doubler = 1;
 		return 1;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+#endif
 
 	if (!strcmp(s, "ide=nodma")) {
 		printk("IDE: Prevented DMA\n");
@@ -3214,8 +3195,8 @@
 		 */
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
-			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+			"minus8", "minus9", "minus10", "minus11",
+			"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3290,18 +3271,7 @@
 				goto done;
 			}
 #endif /* CONFIG_BLK_DEV_QD65XX */
-#ifdef CONFIG_BLK_DEV_4DRIVES
-			case -11: /* "four" drives on one set of ports */
-			{
-				ide_hwif_t *mate = &ide_hwifs[hw^1];
-				mate->drives[0].select.all ^= 0x20;
-				mate->drives[1].select.all ^= 0x20;
-				hwif->chipset = mate->chipset = ide_4drives;
-				mate->irq = hwif->irq;
-				memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
-				goto do_serialize;
-			}
-#endif /* CONFIG_BLK_DEV_4DRIVES */
+			case -11: /* minus11 */
 			case -10: /* minus10 */
 			case -9: /* minus9 */
 			case -8: /* minus8 */
@@ -3368,230 +3338,14 @@
 	return 1;
 }
 
-/*
- * probe_for_hwifs() finds/initializes "known" IDE interfaces
- */
-static void __init probe_for_hwifs (void)
-{
-#ifdef CONFIG_PCI
-	if (pci_present())
-	{
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		ide_scan_pcibus(ide_scan_direction);
-#else
-#ifdef CONFIG_BLK_DEV_RZ1000
-		{
-			extern void ide_probe_for_rz100x(void);
-			ide_probe_for_rz100x();
-		}
-#endif /* CONFIG_BLK_DEV_RZ1000 */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-	}
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_ETRAX_IDE
-	{
-		extern void init_e100_ide(void);
-		init_e100_ide();
-	}
-#endif /* CONFIG_ETRAX_IDE */
-#ifdef CONFIG_BLK_DEV_CMD640
-	{
-		extern void ide_probe_for_cmd640x(void);
-		ide_probe_for_cmd640x();
-	}
-#endif /* CONFIG_BLK_DEV_CMD640 */
-#ifdef CONFIG_BLK_DEV_PDC4030
-	{
-		extern int ide_probe_for_pdc4030(void);
-		(void) ide_probe_for_pdc4030();
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	{
-		extern void pmac_ide_probe(void);
-		pmac_ide_probe();
-	}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
-	{
-		extern void icside_init(void);
-		icside_init();
-	}
-#endif /* CONFIG_BLK_DEV_IDE_ICSIDE */
-#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
-	{
-		extern void rapide_init(void);
-		rapide_init();
-	}
-#endif /* CONFIG_BLK_DEV_IDE_RAPIDE */
-#ifdef CONFIG_BLK_DEV_GAYLE
-	{
-		extern void gayle_init(void);
-		gayle_init();
-	}
-#endif /* CONFIG_BLK_DEV_GAYLE */
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-	{
-		extern void falconide_init(void);
-		falconide_init();
-	}
-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	{
-		extern void macide_init(void);
-		macide_init();
-	}
-#endif /* CONFIG_BLK_DEV_MAC_IDE */
-#ifdef CONFIG_BLK_DEV_Q40IDE
-	{
-		extern void q40ide_init(void);
-		q40ide_init();
-	}
-#endif /* CONFIG_BLK_DEV_Q40IDE */
-#ifdef CONFIG_BLK_DEV_BUDDHA
-	{
-		extern void buddha_init(void);
-		buddha_init();
-	}
-#endif /* CONFIG_BLK_DEV_BUDDHA */
-#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
-	{
-		extern void pnpide_init(int enable);
-		pnpide_init(1);
-	}
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-}
-
-void __init ide_init_builtin_drivers (void)
-{
-	/*
-	 * Probe for special PCI and other "known" interface chipsets
-	 */
-	probe_for_hwifs ();
-
-#ifdef CONFIG_BLK_DEV_IDE
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_intr_lock, NULL, NULL);/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-
-	ideprobe_init();
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_intr_lock);/* for atari only */
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-#endif /* CONFIG_BLK_DEV_IDE */
-
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
-	/*
-	 * Initialize all device type driver modules.
-	 */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-	idedisk_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDECD
-	ide_cdrom_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDETAPE
-	idetape_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-	idefloppy_init();
-#endif
-#ifdef CONFIG_BLK_DEV_IDESCSI
- #ifdef CONFIG_SCSI
-	idescsi_init();
- #else
-    #warning ide scsi-emulation selected but no SCSI-subsystem in kernel
- #endif
-#endif
-}
-
-static int default_cleanup (ide_drive_t *drive)
-{
-	return ide_unregister_subdriver(drive);
-}
-
-static int default_standby (ide_drive_t *drive)
-{
-	return 0;
-}
-
-static int default_flushcache (ide_drive_t *drive)
-{
-	return 0;
-}
-
-static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	ide_end_request(drive, 0);
-	return ide_stopped;
-}
-
 /* This is the default end request function as well */
 int ide_end_request(ide_drive_t *drive, int uptodate)
 {
 	return __ide_end_request(drive, uptodate, 0);
 }
 
-static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg)
-{
-	return -EIO;
-}
-
-static int default_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
-{
-	drive->usage--;
-	return -EIO;
-}
-
-static void default_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
-{
-}
-
-static int default_check_media_change (ide_drive_t *drive)
-{
-	return 1;
-}
-
-static void default_pre_reset (ide_drive_t *drive)
-{
-}
-
-static unsigned long default_capacity (ide_drive_t *drive)
-{
-	return 0x7fffffff;
-}
-
-static ide_startstop_t default_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-	s->all = 0;
-	drive->mult_req = 0;
-	return ide_stopped;
-}
-
-static int default_driver_reinit (ide_drive_t *drive)
-{
-	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
-
-	return 0;
-}
-
 /*
- * Lookup IDE devices, which requested a particular deriver
+ * Lookup IDE devices, which requested a particular driver
  */
 ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n)
 {
@@ -3627,37 +3381,11 @@
 		return 1;
 	}
 
-	drive->driver = driver;
-
-	/* Fill in the default handlers
+	/* FIXME: This will be pushed to the drivers! Thus allowing us to
+	 * save one parameter here eparate this out.
 	 */
 
-	if (driver->cleanup == NULL)
-	    driver->cleanup = default_cleanup;
-	if (driver->standby == NULL)
-	    driver->standby = default_standby;
-	if (driver->flushcache == NULL)
-	    driver->flushcache = default_flushcache;
-	if (driver->do_request == NULL)
-	    driver->do_request = default_do_request;
-	if (driver->end_request == NULL)
-	    driver->end_request = ide_end_request;
-	if (driver->ioctl == NULL)
-	    driver->ioctl = default_ioctl;
-	if (driver->open == NULL)
-	    driver->open = default_open;
-	if (driver->release == NULL)
-	    driver->release = default_release;
-	if (driver->media_change == NULL)
-	    driver->media_change = default_check_media_change;
-	if (driver->pre_reset == NULL)
-	    driver->pre_reset = default_pre_reset;
-	if (driver->capacity == NULL)
-	    driver->capacity = default_capacity;
-	if (driver->special == NULL)
-	    driver->special = default_special;
-	if (driver->driver_reinit == NULL)
-	    driver->driver_reinit = default_driver_reinit;
+	drive->driver = driver;
 
 	restore_flags(flags);		/* all CPUs */
 	/* FIXME: Check what this magic number is supposed to be about? */
@@ -3684,26 +3412,33 @@
 	drive->suspend_reset = 0;
 #ifdef CONFIG_PROC_FS
 	ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
-	ide_add_proc_entries(drive->proc, driver->proc, drive);
+	if (ata_ops(drive))
+		ide_add_proc_entries(drive->proc, ata_ops(drive)->proc, drive);
 #endif
 	return 0;
 }
 
+/*
+ * This is in fact the default cleanup routine.
+ *
+ * FIXME: Check whatever we maybe don't call it twice!.
+ */
 int ide_unregister_subdriver(ide_drive_t *drive)
 {
 	unsigned long flags;
 
 	save_flags(flags);		/* all CPUs */
 	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || ata_ops(drive)->busy) {
+	if (drive->usage || drive->busy || !ata_ops(drive) || ata_ops(drive)->busy) {
 		restore_flags(flags);	/* all CPUs */
 		return 1;
 	}
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
 	pnpide_init(0);
-#endif /* CONFIG_BLK_DEV_ISAPNP */
+#endif
 #ifdef CONFIG_PROC_FS
-	ide_remove_proc_entries(drive->proc, ata_ops(drive)->proc);
+	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);
@@ -3778,11 +3513,8 @@
 EXPORT_SYMBOL(ide_end_drive_cmd);
 EXPORT_SYMBOL(__ide_end_request);
 EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_drive);
 EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
-EXPORT_SYMBOL(ide_wait_cmd);
-EXPORT_SYMBOL(ide_wait_cmd_task);
 EXPORT_SYMBOL(ide_delay_50ms);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
@@ -3798,7 +3530,6 @@
 EXPORT_SYMBOL(ide_unregister);
 EXPORT_SYMBOL(ide_setup_ports);
 EXPORT_SYMBOL(get_info_ptr);
-EXPORT_SYMBOL(current_capacity);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -3828,12 +3559,14 @@
 
 			/* set the drive to standby */
 			printk("%s ", drive->name);
-			if (event != SYS_RESTART)
-				if (drive->driver != NULL && ata_ops(drive)->standby(drive))
-					continue;
+			if (ata_ops(drive)) {
+				if (event != SYS_RESTART)
+					if (ata_ops(drive)->standby && ata_ops(drive)->standby(drive))
+						continue;
 
-			if (drive->driver != NULL && ata_ops(drive)->cleanup(drive))
-				continue;
+				if (ata_ops(drive)->cleanup)
+					ata_ops(drive)->cleanup(drive);
+			}
 		}
 	}
 	printk("\n");
@@ -3881,7 +3614,103 @@
 
 	initializing = 1;
 
-	ide_init_builtin_drivers();
+	/*
+	 * Detect and initialize "known" IDE host chip types.
+	 */
+#ifdef CONFIG_PCI
+	if (pci_present()) {
+# ifdef CONFIG_BLK_DEV_IDEPCI
+		ide_scan_pcibus(ide_scan_direction);
+# else
+#  ifdef CONFIG_BLK_DEV_RZ1000
+		ide_probe_for_rz100x();
+#  endif
+# endif
+	}
+#endif
+
+#ifdef CONFIG_ETRAX_IDE
+	init_e100_ide();
+#endif
+#ifdef CONFIG_BLK_DEV_CMD640
+	ide_probe_for_cmd640x();
+#endif
+#ifdef CONFIG_BLK_DEV_PDC4030
+	ide_probe_for_pdc4030();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	pmac_ide_probe();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+	icside_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+	rapide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_GAYLE
+	gayle_init();
+#endif
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+	falconide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+	macide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_Q40IDE
+	q40ide_init();
+#endif
+#ifdef CONFIG_BLK_DEV_BUDDHA
+	buddha_init();
+#endif
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+	pnpide_init(1);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULES)
+# if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		ide_get_lock(&ide_intr_lock, NULL, NULL);/* for atari only */
+		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
+//		disable_irq_nosync(ide_hwifs[0].irq);
+	}
+# endif
+
+	ideprobe_init();
+
+# if defined(__mc68000__) || defined(CONFIG_APUS)
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
+		enable_irq(ide_hwifs[0].irq);
+		ide_release_lock(&ide_intr_lock);/* for atari only */
+	}
+# endif
+#endif
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_create();
+#endif
+
+	/*
+	 * Initialize all device type driver modules.
+	 */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+	idedisk_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDECD
+	ide_cdrom_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDETAPE
+	idetape_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+	idefloppy_init();
+#endif
+#ifdef CONFIG_BLK_DEV_IDESCSI
+# ifdef CONFIG_SCSI
+	idescsi_init();
+# else
+   #warning ATA SCSI emulation selected but no SCSI-subsystem in kernel
+# endif
+#endif
 
 	initializing = 0;
 
@@ -3928,7 +3757,7 @@
 		ide_unregister(index);
 # if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
-			(void) ide_release_dma(&ide_hwifs[index]);
+			ide_release_dma(&ide_hwifs[index]);
 # endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
 	}
 
diff -urN linux-2.5.6-pre2/drivers/ide/opti621.c linux-2.5.6-pre3/drivers/ide/opti621.c
--- linux-2.5.6-pre2/drivers/ide/opti621.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/opti621.c	Wed Mar  6 17:17:46 2002
@@ -1,10 +1,6 @@
 /*
- *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
- *
  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
+ *
  * Authors:
  * Jaromir Koutek <miri@punknet.cz>,
  * Jan Harkes <jaharkes@cwi.nl>,
@@ -62,9 +58,9 @@
  * by hdparm.
  *
  * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8. 
+ * by Jaromir Koutek, for 2.1.8.
  * Initial version of driver.
- * 
+ *
  * Version 0.2
  * Number 0.2 skipped.
  *
@@ -80,14 +76,13 @@
  * by Jaromir Koutek
  * Updates for use with (again) new IDE block driver.
  * Update of documentation.
- * 
+ *
  * Version 0.6, Jan 2, 1999
  * by Jaromir Koutek
  * Reversed to version 0.3 of the driver, because
  * 0.5 doesn't work.
  */
 
-#undef REALLY_SLOW_IO	/* most systems can safely undef this */
 #define OPTI621_DEBUG		/* define for debug messages */
 
 #include <linux/types.h>
diff -urN linux-2.5.6-pre2/drivers/ide/pdcraid.c linux-2.5.6-pre3/drivers/ide/pdcraid.c
--- linux-2.5.6-pre2/drivers/ide/pdcraid.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/pdcraid.c	Wed Mar  6 17:17:46 2002
@@ -148,7 +148,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		default:
 			printk("Invalid ioctl \n");
diff -urN linux-2.5.6-pre2/drivers/ide/piix.c linux-2.5.6-pre3/drivers/ide/piix.c
--- linux-2.5.6-pre2/drivers/ide/piix.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/piix.c	Wed Mar  6 17:17:46 2002
@@ -214,7 +214,7 @@
 {
 	unsigned long flags;
 	u16 master_data;
-	byte slave_data;
+	u8 slave_data;
 	int is_slave		= (&HWIF(drive)->drives[1] == drive);
 	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
 	int slave_port		= 0x44;
diff -urN linux-2.5.6-pre2/drivers/ide/qd65xx.c linux-2.5.6-pre3/drivers/ide/qd65xx.c
--- linux-2.5.6-pre2/drivers/ide/qd65xx.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/qd65xx.c	Wed Mar  6 17:17:46 2002
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
- *
  *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
  */
 
@@ -9,24 +7,20 @@
  *  Version 0.04	Added second channel tuning
  *  Version 0.05	Enhanced tuning ; added qd6500 support
  *  Version 0.06	Added dos driver's list
- *  Version 0.07	Second channel bug fix 
+ *  Version 0.07	Second channel bug fix
  *
  * QDI QD6500/QD6580 EIDE controller fast support
  *
  * Please set local bus speed using kernel parameter idebus
- * 	for example, "idebus=33" stands for 33Mhz VLbus
+ *	for example, "idebus=33" stands for 33Mhz VLbus
  * To activate controller support, use "ide0=qd65xx"
  * To enable tuning, use "ide0=autotune"
  * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- */
-
-/*
+ *
  * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
  * Samuel Thibault <samuel.thibault@fnac.net>
  */
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -262,7 +256,7 @@
 
 	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
 		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
-		pio = IDE_MIN(pio,4);
+		pio = min(pio,4);
 
 		switch (pio) {
 			case 0: break;
diff -urN linux-2.5.6-pre2/drivers/ide/rz1000.c linux-2.5.6-pre3/drivers/ide/rz1000.c
--- linux-2.5.6-pre2/drivers/ide/rz1000.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/drivers/ide/rz1000.c	Wed Mar  6 17:17:46 2002
@@ -1,10 +1,6 @@
 /*
- *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
- *
  *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
+ *
  *  Principal Author:  mlord@pobox.com (Mark Lord)
  *
  *  See linux/MAINTAINERS for address of current maintainer.
@@ -15,8 +11,6 @@
  *  Dunno if this fixes both ports, or only the primary port (?).
  */
 
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
 #include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -urN linux-2.5.6-pre2/drivers/ide/serverworks.c linux-2.5.6-pre3/drivers/ide/serverworks.c
--- linux-2.5.6-pre2/drivers/ide/serverworks.c	Wed Mar  6 17:17:36 2002
+++ linux-2.5.6-pre3/drivers/ide/serverworks.c	Wed Mar  6 17:17:46 2002
@@ -660,8 +660,10 @@
 	hwif->autodma = 0;
 #else /* CONFIG_BLK_DEV_IDEDMA */
 	if (hwif->dma_base) {
+#ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
 			hwif->autodma = 1;
+#endif
 		hwif->dmaproc = &svwks_dmaproc;
 		hwif->highmem = 1;
 	} else {
diff -urN linux-2.5.6-pre2/drivers/md/md.c linux-2.5.6-pre3/drivers/md/md.c
--- linux-2.5.6-pre2/drivers/md/md.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/md/md.c	Wed Mar  6 17:17:47 2002
@@ -645,8 +645,14 @@
 	if (!bdev)
 		return -ENOMEM;
 	err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
-	if (!err)
-		rdev->bdev = bdev;
+	if (err)
+		return err;
+	err = bd_claim(bdev, lock_rdev);
+	if (err) {
+		blkdev_put(bdev, BDEV_RAW);
+		return err;
+	}
+	rdev->bdev = bdev;
 	return err;
 }
 
@@ -656,6 +662,7 @@
 	rdev->bdev = NULL;
 	if (!bdev)
 		MD_BUG();
+	bd_release(bdev);
 	blkdev_put(bdev, BDEV_RAW);
 }
 
@@ -1086,13 +1093,6 @@
 	}
 	memset(rdev, 0, sizeof(*rdev));
 
-	if (is_mounted(newdev)) {
-		printk(KERN_WARNING "md: can not import %s, has active inodes!\n",
-			partition_name(newdev));
-		err = -EBUSY;
-		goto abort_free;
-	}
-
 	if ((err = alloc_disk_sb(rdev)))
 		goto abort_free;
 
@@ -2625,7 +2625,7 @@
 		case BLKFLSBUF:
 		case BLKBSZGET:
 		case BLKBSZSET:
-			err = blk_ioctl(dev, cmd, arg);
+			err = blk_ioctl(inode->i_bdev, cmd, arg);
 			goto abort;
 
 		default:;
diff -urN linux-2.5.6-pre2/drivers/message/i2o/i2o_block.c linux-2.5.6-pre3/drivers/message/i2o/i2o_block.c
--- linux-2.5.6-pre2/drivers/message/i2o/i2o_block.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/message/i2o/i2o_block.c	Wed Mar  6 17:17:47 2002
@@ -1105,7 +1105,7 @@
 		case BLKROSET:
 		case BLKROGET:
 		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 			
 		default:
 			return -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/mtd/devices/pmc551.c linux-2.5.6-pre3/drivers/mtd/devices/pmc551.c
--- linux-2.5.6-pre2/drivers/mtd/devices/pmc551.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/mtd/devices/pmc551.c	Wed Mar  6 17:17:47 2002
@@ -715,7 +715,7 @@
                 }
 
 		/*
-		 * This is needed untill the driver is capable of reading the
+		 * This is needed until the driver is capable of reading the
 		 * onboard I2C SROM to discover the "real" memory size.
 		 */
 		if(msize) {
diff -urN linux-2.5.6-pre2/drivers/mtd/ftl.c linux-2.5.6-pre3/drivers/mtd/ftl.c
--- linux-2.5.6-pre2/drivers/mtd/ftl.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/mtd/ftl.c	Wed Mar  6 17:17:47 2002
@@ -1144,7 +1144,7 @@
     case BLKROSET:
     case BLKROGET:
     case BLKFLSBUF:
-	ret = blk_ioctl(inode->i_rdev, cmd, arg);
+	ret = blk_ioctl(inode->i_bdev, cmd, arg);
 	break;
     default:
 	ret = -EINVAL;
diff -urN linux-2.5.6-pre2/drivers/mtd/nand/spia.c linux-2.5.6-pre3/drivers/mtd/nand/spia.c
--- linux-2.5.6-pre2/drivers/mtd/nand/spia.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/mtd/nand/spia.c	Wed Mar  6 17:17:47 2002
@@ -113,7 +113,7 @@
 	this->ALE = 0x02;
 	this->NCE = 0x04;
 
-	/* Scan to find existance of the device */
+	/* Scan to find existence of the device */
 	if (nand_scan (spia_mtd)) {
 		kfree (spia_mtd);
 		return -ENXIO;
diff -urN linux-2.5.6-pre2/drivers/mtd/nftlcore.c linux-2.5.6-pre3/drivers/mtd/nftlcore.c
--- linux-2.5.6-pre2/drivers/mtd/nftlcore.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/mtd/nftlcore.c	Wed Mar  6 17:17:47 2002
@@ -823,7 +823,7 @@
 	case BLKROSET:
 	case BLKROGET:
 	case BLKSSZGET:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 #endif
 
 	default:
diff -urN linux-2.5.6-pre2/drivers/net/irda/irda-usb.c linux-2.5.6-pre3/drivers/net/irda/irda-usb.c
--- linux-2.5.6-pre2/drivers/net/irda/irda-usb.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/net/irda/irda-usb.c	Wed Mar  6 17:17:49 2002
@@ -255,7 +255,7 @@
 		   self->new_speed, self->new_xbofs);
 
 	/* Grab the speed URB */
-	urb = &self->speed_urb;
+	urb = self->speed_urb;
 	if (urb->status != 0) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
 		return;
@@ -317,7 +317,7 @@
 	urb->status = 0;
 
 	/* If it was the speed URB, allow the stack to send more packets */
-	if(urb == &self->speed_urb) {
+	if(urb == self->speed_urb) {
 		netif_wake_queue(self->netdev);
 	}
 }
@@ -329,7 +329,7 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	struct urb *urb = &self->tx_urb;
+	struct urb *urb = self->tx_urb;
 	unsigned long flags;
 	s32 speed;
 	s16 xbofs;
@@ -378,10 +378,17 @@
 		return 0;
 	}
 
-	/* Make room for IrDA-USB header (note skb->len += USB_IRDA_HEADER) */
-	if (skb_cow(skb, USB_IRDA_HEADER)) {
-		dev_kfree_skb(skb);
-		return 0;
+	/* Make sure there is room for IrDA-USB header. The actual
+	 * allocation will be done lower in skb_push().
+	 * Also, we don't use directly skb_cow(), because it require
+	 * headroom >= 16, which force unnecessary copies - Jean II */
+	if (skb_headroom(skb) < USB_IRDA_HEADER) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n");
+		if (skb_cow(skb, USB_IRDA_HEADER)) {
+			WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n");
+			dev_kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	spin_lock_irqsave(&self->lock, flags);
@@ -432,7 +439,7 @@
 #ifdef IU_USB_MIN_RTT
 			/* Factor in USB delays -> Get rid of udelay() that
 			 * would be lost in the noise - Jean II */
-			diff -= IU_USB_MIN_RTT;
+			diff += IU_USB_MIN_RTT;
 #endif /* IU_USB_MIN_RTT */
 			if (diff < 0)
 				diff += 1000000;
@@ -546,7 +553,7 @@
 	}
 
 	/* Check speed URB */
-	urb = &(self->speed_urb);
+	urb = self->speed_urb;
 	if (urb->status != 0) {
 		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
@@ -571,7 +578,7 @@
 	}
 
 	/* Check Tx URB */
-	urb = &(self->tx_urb);
+	urb = self->tx_urb;
 	if (urb->status != 0) {
 		struct sk_buff *skb = urb->context;
 
@@ -848,8 +855,8 @@
 	/* Submit the idle URB to replace the URB we've just received */
 	irda_usb_submit(self, skb, self->idle_rx_urb);
 	/* Recycle Rx URB : Now, the idle URB is the present one */
-	self->idle_rx_urb = urb;
 	urb->context = NULL;
+	self->idle_rx_urb = urb;
 }
 
 /*------------------------------------------------------------------*/
@@ -952,13 +959,17 @@
 	/* Allow IrLAP to send data to us */
 	netif_start_queue(netdev);
 
+	/* We submit all the Rx URB except for one that we keep idle.
+	 * Need to be initialised before submitting other USBs, because
+	 * in some cases as soon as we submit the URBs the USB layer
+	 * will trigger a dummy receive - Jean II */
+	self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS];
+	self->idle_rx_urb->context = NULL;
+
 	/* Now that we can pass data to IrLAP, allow the USB layer
 	 * to send us some data... */
 	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
-		irda_usb_submit(self, NULL, &(self->rx_urb[i]));
-	/* Note : we submit all the Rx URB except for one - Jean II */
-	self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
-	self->idle_rx_urb->context = NULL;
+		irda_usb_submit(self, NULL, self->rx_urb[i]);
 
 	/* Ready to play !!! */
 	MOD_INC_USE_COUNT;
@@ -992,7 +1003,7 @@
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		struct urb *urb = &(self->rx_urb[i]);
+		struct urb *urb = self->rx_urb[i];
 		struct sk_buff *skb = (struct sk_buff *) urb->context;
 		/* Cancel the receive command */
 		usb_unlink_urb(urb);
@@ -1003,8 +1014,8 @@
 		}
 	}
 	/* Cancel Tx and speed URB */
-	usb_unlink_urb(&(self->tx_urb));
-	usb_unlink_urb(&(self->speed_urb));
+	usb_unlink_urb(self->tx_urb);
+	usb_unlink_urb(self->speed_urb);
 
 	/* Stop and remove instance of IrLAP */
 	if (self->irlap)
@@ -1429,7 +1440,31 @@
 	self->present = 0;
 	self->netopen = 0;
 
-       /* Is this really necessary? */
+	/* Create all of the needed urbs */
+	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+		self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!self->rx_urb[i]) {
+			int j;
+			for (j = 0; j < i; j++)
+				usb_free_urb(self->rx_urb[j]);
+			return NULL;
+		}
+	}
+	self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!self->tx_urb) {
+		for (i = 0; i < IU_MAX_RX_URBS; i++)
+			usb_free_urb(self->rx_urb[i]);
+		return NULL;
+	}
+	self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!self->speed_urb) {
+		for (i = 0; i < IU_MAX_RX_URBS; i++)
+			usb_free_urb(self->rx_urb[i]);
+		usb_free_urb(self->tx_urb);
+		return NULL;
+	}
+
+	/* Is this really necessary? */
 	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
 		err("set_configuration failed");
 		return NULL;
@@ -1501,10 +1536,10 @@
 		netif_stop_queue(self->netdev);
 		/* Stop all the receive URBs */
 		for (i = 0; i < IU_MAX_RX_URBS; i++)
-			usb_unlink_urb(&(self->rx_urb[i]));
+			usb_unlink_urb(self->rx_urb[i]);
 		/* Cancel Tx and speed URB */
-		usb_unlink_urb(&(self->tx_urb));
-		usb_unlink_urb(&(self->speed_urb));
+		usb_unlink_urb(self->tx_urb);
+		usb_unlink_urb(self->speed_urb);
 
 		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
 		/* better not do anything just yet, usb_irda_cleanup()
@@ -1516,6 +1551,14 @@
 	irda_usb_close(self);
 	/* No longer attached to USB bus */
 	self->usbdev = NULL;
+
+	/* Clean up our urbs */
+	for (i = 0; i < IU_MAX_RX_URBS; i++)
+		usb_free_urb(self->rx_urb[i]);
+	/* Cancel Tx and speed URB */
+	usb_free_urb(self->tx_urb);
+	usb_free_urb(self->speed_urb);
+
 	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
 }
 
diff -urN linux-2.5.6-pre2/drivers/net/irda/sa1100_ir.c linux-2.5.6-pre3/drivers/net/irda/sa1100_ir.c
--- linux-2.5.6-pre2/drivers/net/irda/sa1100_ir.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/net/irda/sa1100_ir.c	Wed Mar  6 17:17:49 2002
@@ -132,7 +132,7 @@
 	Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
 
 	/*
-	 * Enable the DMA, receiver and recieve interrupt.
+	 * Enable the DMA, receiver and receive interrupt.
 	 */
 	sa1100_dma_flush_all(si->rxdma);
 	sa1100_dma_queue_buffer(si->rxdma, NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN);
diff -urN linux-2.5.6-pre2/drivers/net/ppp_deflate.c linux-2.5.6-pre3/drivers/net/ppp_deflate.c
--- linux-2.5.6-pre2/drivers/net/ppp_deflate.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/net/ppp_deflate.c	Wed Mar  6 17:17:50 2002
@@ -35,12 +35,16 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
 
 #include <linux/zlib.h>
 
+static spinlock_t comp_free_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(comp_free_list);
+
 /*
  * State for a Deflate (de)compressor.
  */
@@ -52,6 +56,7 @@
     int		debug;
     z_stream	strm;
     struct compstat stats;
+    struct list_head list;
 };
 
 #define DEFLATE_OVHD	2		/* Deflate overhead/packet */
@@ -76,6 +81,27 @@
 static void	z_decomp_reset __P((void *state));
 static void	z_comp_stats __P((void *state, struct compstat *stats));
 
+static void z_comp_delayedfree(void *arg)
+{
+	struct ppp_deflate_state *state;
+
+	spin_lock_bh(&comp_free_list_lock);
+	while(!list_empty(&comp_free_list)) {
+		state = list_entry(comp_free_list.next, struct ppp_deflate_state, list);
+		list_del(&state->list);
+		spin_unlock_bh(&comp_free_list_lock);
+		if (state->strm.workspace)
+			vfree(state->strm.workspace);
+		kfree(state);
+		spin_lock_bh(&comp_free_list_lock);
+	}
+	spin_unlock_bh(&comp_free_list_lock);
+}
+
+static struct tq_struct z_comp_task = {
+	routine: z_comp_delayedfree
+};
+
 static void
 z_comp_free(arg)
     void *arg;
@@ -84,9 +110,12 @@
 
 	if (state) {
 		zlib_deflateEnd(&state->strm);
-		if (state->strm.workspace)
-			kfree(state->strm.workspace);
-		kfree(state);
+
+		spin_lock_bh(&comp_free_list_lock);
+		list_add(&state->list, &comp_free_list);
+		spin_unlock_bh(&comp_free_list_lock);
+
+		schedule_task(&z_comp_task);
 		MOD_DEC_USE_COUNT;
 	}
 }
@@ -121,8 +150,7 @@
 	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->strm.next_in   = NULL;
 	state->w_size         = w_size;
-	state->strm.workspace = kmalloc(zlib_deflate_workspacesize(),
-					GFP_KERNEL);
+	state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
 	if (state->strm.workspace == NULL)
 		goto out_free;
 
@@ -134,7 +162,6 @@
 
 out_free:
 	z_comp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -319,7 +346,6 @@
 
 out_free:
 	z_decomp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -590,8 +616,10 @@
 {
 	ppp_unregister_compressor(&ppp_deflate);
 	ppp_unregister_compressor(&ppp_deflate_draft);
+	/* Ensure that any deflate state pending free is actually freed */
+	flush_scheduled_tasks();
 }
 
 module_init(deflate_init);
 module_exit(deflate_cleanup);
-MODULE_LICENSE("BSD without advertisement clause");
+MODULE_LICENSE("Dual BSD/GPL");
diff -urN linux-2.5.6-pre2/drivers/net/wan/sdla_x25.c linux-2.5.6-pre3/drivers/net/wan/sdla_x25.c
--- linux-2.5.6-pre2/drivers/net/wan/sdla_x25.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/drivers/net/wan/sdla_x25.c	Wed Mar  6 17:17:50 2002
@@ -1272,7 +1272,7 @@
 			add_timer(&card->u.x.x25_timer);
 		}
 	}
-	/* Device is not up untill the we are in connected state */
+	/* Device is not up until the we are in connected state */
 	do_gettimeofday( &tv );
 	chan->router_start_time = tv.tv_sec;
 
@@ -4756,7 +4756,7 @@
  * send_delayed_cmd_result
  *
  *	Wait commands like PLEACE CALL or CLEAR CALL must wait
- *      untill the result arrivers. This function passes
+ *      until the result arrives. This function passes
  *      the result to a waiting sock. 
  *
  *===============================================================*/
diff -urN linux-2.5.6-pre2/drivers/pci/pci.c linux-2.5.6-pre3/drivers/pci/pci.c
--- linux-2.5.6-pre2/drivers/pci/pci.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/pci/pci.c	Wed Mar  6 17:17:51 2002
@@ -966,7 +966,7 @@
 	}
 }
 
-void __devinit  pci_read_bridge_bases(struct pci_bus *child)
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
 {
 	struct pci_dev *dev = child->self;
 	u8 io_base_lo, io_limit_lo;
@@ -1057,7 +1057,7 @@
 	}
 }
 
-static struct pci_bus * __devinit  pci_alloc_bus(void)
+static struct pci_bus * __devinit pci_alloc_bus(void)
 {
 	struct pci_bus *b;
 
@@ -1392,7 +1392,7 @@
 	return max;
 }
 
-int __devinit  pci_bus_exists(const struct list_head *list, int nr)
+int __devinit pci_bus_exists(const struct list_head *list, int nr)
 {
 	const struct list_head *l;
 
@@ -1404,7 +1404,7 @@
 	return 0;
 }
 
-struct pci_bus * __devinit  pci_alloc_primary_bus(int bus)
+struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
 {
 	struct pci_bus *b;
 
@@ -1431,7 +1431,7 @@
 	return b;
 }
 
-struct pci_bus * __devinit  pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+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) {
@@ -1965,7 +1965,7 @@
 	return 0;
 }
 
-static int __devinit  pci_setup(char *str)
+static int __devinit pci_setup(char *str)
 {
 	while (str) {
 		char *k = strchr(str, ',');
diff -urN linux-2.5.6-pre2/drivers/pcmcia/Config.in linux-2.5.6-pre3/drivers/pcmcia/Config.in
--- linux-2.5.6-pre2/drivers/pcmcia/Config.in	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/Config.in	Wed Mar  6 17:17:51 2002
@@ -24,5 +24,6 @@
       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
    fi
 fi
+dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
 
 endmenu
diff -urN linux-2.5.6-pre2/drivers/pcmcia/Makefile linux-2.5.6-pre3/drivers/pcmcia/Makefile
--- linux-2.5.6-pre2/drivers/pcmcia/Makefile	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/Makefile	Wed Mar  6 17:17:51 2002
@@ -62,22 +62,25 @@
 obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
 
 sa1100_cs-objs-y				:= sa1100_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o
-sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
+sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
+sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
-sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
+sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
+sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)	+= sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
-sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
-sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o
-sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)	+= sa1100_system3.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
 sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
-sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o
 sa1100_cs-objs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
+sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o sa1111_generic.o
+sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
 
 include $(TOPDIR)/Rules.make
 
@@ -85,7 +88,7 @@
 	$(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs)
 
 sa1100_cs.o: $(sa1100_cs-objs-y)
-	$(LD) -r -o $@ $(sa1100_cs-objs-y)
+	$(LD) -r -o $@ $(sort $(sa1100_cs-objs-y))
 
 yenta_socket.o: $(yenta_socket-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100.h linux-2.5.6-pre3/drivers/pcmcia/sa1100.h
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100.h	Wed Mar  6 17:17:51 2002
@@ -38,9 +38,7 @@
 #include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
-
-#include <asm/arch/pcmcia.h>
-
+#include "sa1100_generic.h"
 
 /* MECR: Expansion Memory Configuration Register
  * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
@@ -157,15 +155,24 @@
  * use when responding to a Card Services query of some kind.
  */
 struct sa1100_pcmcia_socket {
+  /*
+   * Core PCMCIA state
+   */
   socket_state_t        cs_state;
-  struct pcmcia_state   k_state;
-  unsigned int          irq;
-  void                  (*handler)(void *, unsigned int);
-  void                  *handler_info;
   pccard_io_map         io_map[MAX_IO_WIN];
   pccard_mem_map        mem_map[MAX_WIN];
-  ioaddr_t              virt_io, phys_attr, phys_mem;
+  void                  (*handler)(void *, unsigned int);
+  void                  *handler_info;
+
+  struct pcmcia_state   k_state;
+  ioaddr_t              phys_attr, phys_mem;
+  void			*virt_io;
   unsigned short        speed_io, speed_attr, speed_mem;
+
+  /*
+   * Info from low level handler
+   */
+  unsigned int          irq;
 };
 
 
@@ -180,23 +187,60 @@
 
 
 /*
- * Declaration for all implementation specific low_level operations.
+ * Declaration for all machine specific init/exit functions.
  */
-extern struct pcmcia_low_level assabet_pcmcia_ops;
-extern struct pcmcia_low_level neponset_pcmcia_ops;
-extern struct pcmcia_low_level h3600_pcmcia_ops;
-extern struct pcmcia_low_level cerf_pcmcia_ops;
-extern struct pcmcia_low_level gcplus_pcmcia_ops;
-extern struct pcmcia_low_level xp860_pcmcia_ops;
-extern struct pcmcia_low_level yopy_pcmcia_ops;
-extern struct pcmcia_low_level pangolin_pcmcia_ops;
-extern struct pcmcia_low_level freebird_pcmcia_ops;
-extern struct pcmcia_low_level pfs168_pcmcia_ops;
-extern struct pcmcia_low_level jornada720_pcmcia_ops;
-extern struct pcmcia_low_level flexanet_pcmcia_ops;
-extern struct pcmcia_low_level simpad_pcmcia_ops;
-extern struct pcmcia_low_level graphicsmaster_pcmcia_ops;
-extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
-extern struct pcmcia_low_level stork_pcmcia_ops;
+extern int pcmcia_adsbitsy_init(void);
+extern void pcmcia_adsbitsy_exit(void);
+
+extern int pcmcia_assabet_init(void);
+extern void pcmcia_assabet_exit(void);
+
+extern int pcmcia_badge4_init(void);
+extern void pcmcia_badge4_exit(void);
+
+extern int pcmcia_cerf_init(void);
+extern void pcmcia_cerf_exit(void);
+
+extern int pcmcia_flexanet_init(void);
+extern void pcmcia_flexanet_exit(void);
+
+extern int pcmcia_freebird_init(void);
+extern void pcmcia_freebird_exit(void);
+
+extern int pcmcia_gcplus_init(void);
+extern void pcmcia_gcplus_exit(void);
+
+extern int pcmcia_graphicsmaster_init(void);
+extern void pcmcia_graphicsmaster_exit(void);
+
+extern int pcmcia_jornada720_init(void);
+extern void pcmcia_jornada720_exit(void);
+
+extern int pcmcia_neponset_init(void);
+extern void pcmcia_neponset_exit(void);
+
+extern int pcmcia_pangolin_init(void);
+extern void pcmcia_pangolin_exit(void);
+
+extern int pcmcia_pfs168_init(void);
+extern void pcmcia_pfs168_exit(void);
+
+extern int pcmcia_shannon_init(void);
+extern void pcmcia_shannon_exit(void);
+
+extern int pcmcia_simpad_init(void);
+extern void pcmcia_simpad_exit(void);
+
+extern int pcmcia_stork_init(void);
+extern void pcmcia_stork_exit(void);
+
+extern int pcmcia_system3_init(void);
+extern void pcmcia_system3_exit(void);
+
+extern int pcmcia_xp860_init(void);
+extern void pcmcia_xp860_exit(void);
+
+extern int pcmcia_yopy_init(void);
+extern void pcmcia_yopy_exit(void);
 
 #endif  /* !defined(_PCMCIA_SA1100_H) */
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_adsbitsy.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_adsbitsy.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_adsbitsy.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_adsbitsy.c	Wed Mar  6 17:17:51 2002
@@ -11,206 +11,97 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
 {
-  int return_val=0;
-
   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
   /* Disable Power 3.3V/5V for PCMCIA/CF */
   PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) BVD1", NULL);
-
+  /* Why? */			 
   MECR = 0x09430943;
 
-  return (return_val<0) ? -1 : 2;
-}
-
-static int adsbitsy_pcmcia_shutdown(void)
-{
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+static int
+adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-  switch(info->sock){
+  switch (conf->sock) {
   case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
-}
-
-static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-  unsigned long pccr=PCCR, gpio=PA_DWR;
-
-  switch(configure->sock){
-  case 0:
-
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio &= ~GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio |= GPIO_GPIO0;
-      break;
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO3;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;				break;
+    case 33:	pa_dwr_set = GPIO_GPIO2;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO3;		break;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
   default:
     return -1;
   }
 
-  PCCR = pccr;
-  PA_DWR = gpio;
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+		__FUNCTION__, conf->vpp);
+    return -1;
+  }
 
-  return 0;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
+
+  return ret;
 }
 
-struct pcmcia_low_level adsbitsy_pcmcia_ops = {
-  adsbitsy_pcmcia_init,
-  adsbitsy_pcmcia_shutdown,
-  adsbitsy_pcmcia_socket_state,
-  adsbitsy_pcmcia_get_irq_info,
-  adsbitsy_pcmcia_configure_socket
+static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
+  init:			adsbitsy_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	adsbitsy_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_adsbitsy_init(void)
+{
+	int ret = -ENODEV;
+	if (machine_is_adsbitsy())
+		ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops);
+	return ret;
+}
+
+void __exit pcmcia_adsbitsy_exit(void)
+{
+	sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_assabet.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_assabet.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_assabet.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_assabet.c	Wed Mar  6 17:17:51 2002
@@ -4,146 +4,221 @@
  * PCMCIA implementation routines for Assabet
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 #include <asm/arch/assabet.h>
 
-static int assabet_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+#include "sa1100_generic.h"
 
-  /* Enable CF bus: */
-  ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
-
-  /* All those are inputs */
-  GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ);
-
-  /* Set transition detect */
-  set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
-
-  /* Register interrupts */
-  irq = ASSABET_IRQ_GPIO_CF_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = ASSABET_IRQ_GPIO_CF_BVD2;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = ASSABET_IRQ_GPIO_CF_BVD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
-  if( res < 0 ) goto irq_err;
-
-  /* There's only one slot, but it's "Slot 1": */
-  return 2;
-
-irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
-  return -1;
-}
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ ASSABET_IRQ_GPIO_CF_CD,   "CF_CD"   },
+	{ ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
+	{ ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" },
+};
 
-static int assabet_pcmcia_shutdown(void)
+static int assabet_pcmcia_init(struct pcmcia_init *init)
 {
-  /* disable IRQs */
-  free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL );
-  free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL );
-  free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL );
-  
-  /* Disable CF bus: */
-  ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF);
-
-  return 0;
-}
+	int i, res;
 
-static int assabet_pcmcia_socket_state(struct pcmcia_state_array
-				       *state_array){
-  unsigned long levels;
+	/* Set transition detect */
+	set_irq_type(ASSABET_IRQ_GPIO_CF_IRQ, IRQT_FALLING);
 
-  if(state_array->size<2) return -1;
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			goto irq_err;
+	}
+
+	/* There's only one slot, but it's "Slot 1": */
+	return 2;
+
+ irq_err:
+	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+		__FUNCTION__, irqs[i].irq, res);
 
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
+	while (i--)
+		free_irq(irqs[i].irq, NULL);
 
-  levels=GPLR;
-
-  state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0;
+	return res;
+}
 
-  state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0;
+/*
+ * Release all resources.
+ */
+static int assabet_pcmcia_shutdown(void)
+{
+	int i;
 
-  state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0;
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
+  
+	return 0;
+}
 
-  state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0;
+static int
+assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+	unsigned long levels;
 
-  state_array->state[1].wrprot=0; /* Not available on Assabet. */
+	if (state_array->size < 2)
+		return -1;
 
-  state_array->state[1].vs_3v=1;  /* Can only apply 3.3V on Assabet. */
+	levels = GPLR;
 
-  state_array->state[1].vs_Xv=0;
+	state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
+	state_array->state[1].ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
+	state_array->state[1].bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
+	state_array->state[1].bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
+	state_array->state[1].wrprot = 0; /* Not available on Assabet. */
+	state_array->state[1].vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
+	state_array->state[1].vs_Xv  = 0;
 
-  return 1;
+	return 1;
 }
 
-static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  if(info->sock>1) return -1;
+static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock > 1)
+		return -1;
 
-  if(info->sock==1)
-    info->irq=ASSABET_IRQ_GPIO_CF_IRQ;
+	if (info->sock == 1)
+		info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
 
-  return 0;
+	return 0;
 }
 
-static int assabet_pcmcia_configure_socket(const struct pcmcia_configure
-					   *configure)
+static int
+assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
 {
-  unsigned long value, flags;
+	unsigned int mask;
 
-  if(configure->sock>1) return -1;
+	if (configure->sock > 1)
+		return -1;
 
-  if(configure->sock==0) return 0;
+	if (configure->sock == 0)
+		return 0;
 
-  save_flags_cli(flags);
+	switch (configure->vcc) {
+	case 0:
+		mask = 0;
+		break;
+
+	case 50:
+		printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+			__FUNCTION__);
+
+	case 33:  /* Can only apply 3.3V to the CF slot. */
+		mask = ASSABET_BCR_CF_PWR;
+		break;
+
+	default:
+		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+			configure->vcc);
+		return -1;
+	}
+
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	if (configure->reset)
+		mask |= ASSABET_BCR_CF_RST;
+
+	ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
+
+	/*
+	 * Handle suspend mode properly.  This prevents a
+	 * flood of IRQs from the CF device.
+	 */
+	if (configure->irq)
+		enable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
+	else
+		disable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
 
-  value = BCR_value;
+	return 0;
+}
 
-  switch(configure->vcc){
-  case 0:
-    value &= ~ASSABET_BCR_CF_PWR;
-    break;
+/*
+ * Enable card status IRQs on (re-)initialisation.  This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+static int assabet_pcmcia_socket_init(int sock)
+{
+	int i;
 
-  case 50:
-    printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-	   __FUNCTION__);
+	if (sock == 1) {
+		/*
+		 * Enable CF bus
+		 */
+		ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
+
+		for (i = 0; i < ARRAY_SIZE(irqs); i++)
+			set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
+	}
 
-  case 33:  /* Can only apply 3.3V to the CF slot. */
-    value |= ASSABET_BCR_CF_PWR;
-    break;
+	return 0;
+}
 
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    restore_flags(flags);
-    return -1;
-  }
+/*
+ * Disable card status IRQs on suspend.
+ */
+static int assabet_pcmcia_socket_suspend(int sock)
+{
+	int i;
 
-  value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST);
+	if (sock == 1) {
+		for (i = 0; i < ARRAY_SIZE(irqs); i++)
+			set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+
+		/*
+		 * Tristate the CF bus signals.  Also assert CF
+		 * reset as per user guide page 4-11.
+		 */
+		ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	return 0;
+}
+
+static struct pcmcia_low_level assabet_pcmcia_ops = { 
+	init:			assabet_pcmcia_init,
+	shutdown:		assabet_pcmcia_shutdown,
+	socket_state:		assabet_pcmcia_socket_state,
+	get_irq_info:		assabet_pcmcia_get_irq_info,
+	configure_socket:	assabet_pcmcia_configure_socket,
 
-  ASSABET_BCR = BCR_value = value;
+	socket_init:		assabet_pcmcia_socket_init,
+	socket_suspend:		assabet_pcmcia_socket_suspend,
+};
 
-  restore_flags(flags);
+int __init pcmcia_assabet_init(void)
+{
+	int ret = -ENODEV;
 
-  return 0;
+	if (machine_is_assabet()) {
+		if (!machine_has_neponset())
+			ret = sa1100_register_pcmcia(&assabet_pcmcia_ops);
+#ifndef CONFIG_ASSABET_NEPONSET
+		else
+			printk(KERN_ERR "Card Services disabled: missing "
+				"Neponset support\n");
+#endif
+	}
+	return ret;
 }
 
-struct pcmcia_low_level assabet_pcmcia_ops = { 
-  assabet_pcmcia_init,
-  assabet_pcmcia_shutdown,
-  assabet_pcmcia_socket_state,
-  assabet_pcmcia_get_irq_info,
-  assabet_pcmcia_configure_socket
-};
+void __exit pcmcia_assabet_exit(void)
+{
+	sa1100_unregister_pcmcia(&assabet_pcmcia_ops);
+}
 
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_badge4.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_badge4.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_badge4.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_badge4.c	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,186 @@
+/*
+ * linux/drivers/pcmcia/sa1100_badge4.c
+ *
+ * BadgePAD 4 PCMCIA specific routines
+ *
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
+
+/*
+ * BadgePAD 4 Details
+ *
+ * PCM Vcc:
+ *
+ *  PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3
+ *  on JP6) or 5V (short pins 3 and 5 on JP6).  N.B., 5V supply rail
+ *  is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24).
+ *
+ * PCM Vpp:
+ *
+ *  PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4
+ *  on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6).  N.B., 12V
+ *  operation requires that the power supply actually supply 12V.
+ *
+ * CF Vcc:
+ *
+ *  CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1
+ *  and 2 on JP10) or 5V (short pins 2 and 3 on JP10).  The note above
+ *  about the 5V supply rail applies.
+ *
+ * There's no way programmatically to determine how a given board is
+ * jumpered.  This code assumes a default jumpering: 5V PCM Vcc (pins
+ * 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and
+ * no jumpering for CF Vcc.  If this isn't correct, Override these
+ * defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf
+ * vcc>.  E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp,
+ * and 5.0V CF Vcc.
+ *
+ */
+
+static int badge4_pcmvcc = 50;
+static int badge4_pcmvpp = 50;
+static int badge4_cfvcc = 0;
+
+static int badge4_pcmcia_init(struct pcmcia_init *init)
+{
+	printk(KERN_INFO __FUNCTION__
+	       ": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+	       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
+
+	return sa1111_pcmcia_init(init);
+}
+
+static int badge4_pcmcia_shutdown(void)
+{
+	int rc = sa1111_pcmcia_shutdown();
+
+	/* be sure to disable 5V use */
+	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
+	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
+
+	return rc;
+}
+
+static void complain_about_jumpering(const char *whom,
+				     const char *supply,
+				     int given, int wanted)
+{
+	printk(KERN_ERR
+	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
+	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
+	       whom, supply,
+	       wanted / 10, wanted % 10,
+	       supply,
+	       given / 10, given % 10);
+}
+
+static unsigned badge4_need_5V_bitmap = 0;
+
+static int
+badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	int ret;
+
+	switch (conf->sock) {
+	case 0:
+		if ((conf->vcc != 0) &&
+		    (conf->vcc != badge4_pcmvcc)) {
+			complain_about_jumpering(__FUNCTION__, "pcmvcc",
+						 badge4_pcmvcc, conf->vcc);
+			return -1;
+		}
+		if ((conf->vpp != 0) &&
+		    (conf->vpp != badge4_pcmvpp)) {
+			complain_about_jumpering(__FUNCTION__, "pcmvpp",
+						 badge4_pcmvpp, conf->vpp);
+			return -1;
+		}
+		break;
+
+	case 1:
+		if ((conf->vcc != 0) &&
+		    (conf->vcc != badge4_cfvcc)) {
+			complain_about_jumpering(__FUNCTION__, "cfvcc",
+						 badge4_cfvcc, conf->vcc);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(conf);
+	if (ret == 0) {
+		unsigned long flags;
+		int need5V;
+
+		local_irq_save(flags);
+
+		need5V = ((conf->vcc == 50) || (conf->vpp == 50));
+
+		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
+
+		local_irq_restore(flags);
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level badge4_pcmcia_ops = {
+	init:			badge4_pcmcia_init,
+	shutdown:		badge4_pcmcia_shutdown,
+	socket_state:		sa1111_pcmcia_socket_state,
+	get_irq_info:		sa1111_pcmcia_get_irq_info,
+	configure_socket:	badge4_pcmcia_configure_socket,
+
+	socket_init:		sa1111_pcmcia_socket_init,
+	socket_suspend:		sa1111_pcmcia_socket_suspend,
+};
+
+int __init pcmcia_badge4_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_badge4())
+		ret = sa1100_register_pcmcia(&badge4_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_badge4_exit(void)
+{
+	sa1100_unregister_pcmcia(&badge4_pcmcia_ops);
+}
+
+static int __init pcmv_setup(char *s)
+{
+	int v[4];
+
+	s = get_options(s, ARRAY_SIZE(v), v);
+
+	if (v[0] >= 1) badge4_pcmvcc = v[1];
+	if (v[0] >= 2) badge4_pcmvpp = v[2];
+	if (v[0] >= 3) badge4_cfvcc = v[3];
+
+	return 1;
+}
+
+__setup("pcmv=", pcmv_setup);
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_cerf.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_cerf.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_cerf.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_cerf.c	Wed Mar  6 17:17:51 2002
@@ -5,45 +5,62 @@
  * Based off the Assabet.
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+#ifdef CONFIG_SA1100_CERF_CPLD
+#define CERF_SOCKET	0
+#else
+#define CERF_SOCKET	1
+#endif
 
-static int cerf_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_CF_CD,   "CF_CD"   },
+	{ IRQ_GPIO_CF_BVD2, "CF_BVD2" },
+	{ IRQ_GPIO_CF_BVD1, "CF_BVD1" }
+};
+
+static int cerf_pcmcia_init(struct pcmcia_init *init)
+{
+  int i, res;
 
-  GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
-  GPDR |= (GPIO_CF_RESET);
+  set_irq_type(IRQ_GPIO_CF_IRQ, IRQT_FALLING);
 
-  set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
-
-  irq = IRQ_GPIO_CF_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_CF_BVD2;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_CF_BVD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
-  if( res < 0 ) goto irq_err;
+  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+		      irqs[i].str, NULL);
+    if (res)
+      goto irq_err;
+  }
 
   return 2;
 
-irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
-  return -1;
+ irq_err:
+  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	 __FUNCTION__, irqs[i].irq, res);
+
+  while (i--)
+    free_irq(irqs[i].irq, NULL);
+
+  return res;
 }
 
 static int cerf_pcmcia_shutdown(void)
 {
-  free_irq( IRQ_GPIO_CF_CD, NULL );
-  free_irq( IRQ_GPIO_CF_BVD2, NULL );
-  free_irq( IRQ_GPIO_CF_BVD1, NULL );
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+    free_irq(irqs[i].irq, NULL);
 
   return 0;
 }
@@ -51,31 +68,18 @@
 static int cerf_pcmcia_socket_state(struct pcmcia_state_array
 				       *state_array){
   unsigned long levels;
-#ifdef CONFIG_SA1100_CERF_CPLD
-  int i = 0;
-#else
-  int i = 1;
-#endif
+  int i = CERF_SOCKET;
 
   if(state_array->size<2) return -1;
 
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
   levels=GPLR;
 
   state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
-
   state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
-
   state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
-
   state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
-
   state_array->state[i].wrprot=0;
-
   state_array->state[i].vs_3v=1;
-
   state_array->state[i].vs_Xv=0;
 
   return 1;
@@ -85,11 +89,7 @@
 
   if(info->sock>1) return -1;
 
-#ifdef CONFIG_SA1100_CERF_CPLD
-  if(info->sock==0)
-#else
-  if(info->sock==1)
-#endif
+  if (info->sock == CERF_SOCKET)
     info->irq=IRQ_GPIO_CF_IRQ;
 
   return 0;
@@ -98,20 +98,12 @@
 static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
 					   *configure)
 {
-  unsigned long flags;
-
   if(configure->sock>1)
     return -1;
 
-#ifdef CONFIG_SA1100_CERF_CPLD
-  if(configure->sock==1)
-#else
-  if(configure->sock==0)
-#endif
+  if (configure->sock != CERF_SOCKET)
     return 0;
 
-  save_flags_cli(flags);
-
   switch(configure->vcc){
   case 0:
     break;
@@ -119,43 +111,76 @@
   case 50:
   case 33:
 #ifdef CONFIG_SA1100_CERF_CPLD
-     GPDR |= GPIO_PWR_SHUTDOWN;
-     GPCR |= GPIO_PWR_SHUTDOWN;
+     GPCR = GPIO_PWR_SHUTDOWN;
 #endif
      break;
 
   default:
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
-    restore_flags(flags);
     return -1;
   }
 
   if(configure->reset)
   {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPDR |= GPIO_CF_RESET;
-    GPSR |= GPIO_CF_RESET;
+    GPSR = GPIO_CF_RESET;
 #endif
   }
   else
   {
 #ifdef CONFIG_SA1100_CERF_CPLD
-    GPDR |= GPIO_CF_RESET;
-    GPCR |= GPIO_CF_RESET;
+    GPCR = GPIO_CF_RESET;
 #endif
   }
 
-  restore_flags(flags);
+  return 0;
+}
+
+static int cerf_pcmcia_socket_init(int sock)
+{
+  int i;
+
+  if (sock == CERF_SOCKET)
+    for (i = 0; i < ARRAY_SIZE(irqs); i++)
+      set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
 
   return 0;
 }
 
-struct pcmcia_low_level cerf_pcmcia_ops = { 
-  cerf_pcmcia_init,
-  cerf_pcmcia_shutdown,
-  cerf_pcmcia_socket_state,
-  cerf_pcmcia_get_irq_info,
-  cerf_pcmcia_configure_socket
+static int cerf_pcmcia_socket_suspend(int sock)
+{
+  int i;
+
+  if (sock == CERF_SOCKET)
+    for (i = 0; i < ARRAY_SIZE(irqs); i++)
+      set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+
+  return 0;
+}
+
+static struct pcmcia_low_level cerf_pcmcia_ops = { 
+  init:			cerf_pcmcia_init,
+  shutdown:		cerf_pcmcia_shutdown,
+  socket_state:		cerf_pcmcia_socket_state,
+  get_irq_info:		cerf_pcmcia_get_irq_info,
+  configure_socket:	cerf_pcmcia_configure_socket,
+
+  socket_init:		cerf_pcmcia_socket_init,
+  socket_suspend:	cerf_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_cerf_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_cerf())
+		ret = sa1100_register_pcmcia(&cerf_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_cerf_exit(void)
+{
+	sa1100_unregister_pcmcia(&cerf_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_flexanet.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_flexanet.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_flexanet.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_flexanet.c	Wed Mar  6 17:17:51 2002
@@ -4,16 +4,25 @@
  * PCMCIA implementation routines for Flexanet.
  * by Jordi Colomer, 09/05/2001
  *
- * Yet to be defined.
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct {
+  int irq;
+  const char *name;
+} irqs[] = {
+  { IRQ_GPIO_CF1_CD,   "CF1_CD"   },
+  { IRQ_GPIO_CF1_BVD1, "CF1_BVD1" },
+  { IRQ_GPIO_CF2_CD,   "CF2_CD"   },
+  { IRQ_GPIO_CF2_BVD1, "CF2_BVD1" }
+};
 
 /*
  * Socket initialization.
@@ -22,9 +31,37 @@
  * Must return the number of slots.
  *
  */
-static int flexanet_pcmcia_init(struct pcmcia_init *init){
+static int flexanet_pcmcia_init(struct pcmcia_init *init)
+{
+  int i, res;
 
-  return 0;
+  /* Configure the GPIOs as inputs (BVD2 is not implemented) */
+  GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
+            GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
+
+  /* Set IRQ edge */
+  set_irq_type(IRQ_GPIO_CF1_IRQ, IRQT_FALLING);
+  set_irq_type(IRQ_GPIO_CF2_IRQ, IRQT_FALLING);
+
+  /* Register the socket interrupts (not the card interrupts) */
+  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+		      irqs[i].name, NULL);
+    if (res < 0)
+      break;
+  }
+
+  /* If we failed, then free all interrupts requested thus far. */
+  if (res < 0) {
+    printk(KERN_ERR "%s: request for IRQ%d failed: %d\n",
+	   __FUNCTION__, irqs[i].irq, res);
+    while (i--)
+      free_irq(irqs[i].irq, NULL);
+    return res;
+  }
+
+  return 2;
 }
 
 
@@ -34,6 +71,12 @@
  */
 static int flexanet_pcmcia_shutdown(void)
 {
+  int i;
+
+  /* disable IRQs */
+  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+    free_irq(irqs[i].irq, NULL);
+
   return 0;
 }
 
@@ -46,7 +89,33 @@
  */
 static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
 				       *state_array){
-  return -1;
+  unsigned long levels;
+
+  if (state_array->size < 2)
+    return -1;
+
+  /* Sense the GPIOs, asynchronously */
+  levels = GPLR;
+
+  /* Socket 0 */
+  state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
+  state_array->state[0].ready  = (levels & GPIO_CF1_IRQ)?1:0;
+  state_array->state[0].bvd1   = (levels & GPIO_CF1_BVD1)?1:0;
+  state_array->state[0].bvd2   = 1;
+  state_array->state[0].wrprot = 0;
+  state_array->state[0].vs_3v  = 1;
+  state_array->state[0].vs_Xv  = 0;
+
+  /* Socket 1 */
+  state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
+  state_array->state[1].ready  = (levels & GPIO_CF2_IRQ)?1:0;
+  state_array->state[1].bvd1   = (levels & GPIO_CF2_BVD1)?1:0;
+  state_array->state[1].bvd2   = 1;
+  state_array->state[1].wrprot = 0;
+  state_array->state[1].vs_3v  = 1;
+  state_array->state[1].vs_Xv  = 0;
+
+  return 1;
 }
 
 
@@ -56,7 +125,16 @@
  */
 static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
 
-  return -1;
+  /* check the socket index */
+  if (info->sock > 1)
+    return -1;
+
+  if (info->sock == 0)
+    info->irq = IRQ_GPIO_CF1_IRQ;
+  else if (info->sock == 1)
+    info->irq = IRQ_GPIO_CF2_IRQ;
+
+  return 0;
 }
 
 
@@ -66,19 +144,105 @@
 static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
 					   *configure)
 {
-  return -1;
+  unsigned long value, flags, mask;
+
+
+  if (configure->sock > 1)
+    return -1;
+
+  /* Ignore the VCC level since it is 3.3V and always on */
+  switch (configure->vcc)
+  {
+    case 0:
+      printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
+      break;
+
+    case 50:
+      printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
+  	   __FUNCTION__);
+
+    case 33:
+      break;
+
+    default:
+      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+  	   configure->vcc);
+      return -1;
+  }
+
+  /* Reset the slot(s) using the controls in the BCR */
+  mask = 0;
+
+  switch (configure->sock)
+  {
+    case 0 : mask = FHH_BCR_CF1_RST; break;
+    case 1 : mask = FHH_BCR_CF2_RST; break;
+  }
+
+  local_irq_save(flags);
+
+  value = flexanet_BCR;
+  value = (configure->reset) ? (value | mask) : (value & ~mask);
+  FHH_BCR = flexanet_BCR = value;
+
+  local_irq_restore(flags);
+
+  return 0;
 }
 
+static int flexanet_pcmcia_socket_init(int sock)
+{
+  if (sock == 0) {
+    set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE);
+    set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE);
+  } else if (sock == 1) {
+    set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE);
+    set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE);
+  }
+
+  return 0;
+}
+
+static int flexanet_pcmcia_socket_suspend(int sock)
+{
+  if (sock == 0) {
+    set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE);
+    set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE);
+  } else if (sock == 1) {
+    set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE);
+    set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE);
+  }
+
+  return 0;
+}
 
 /*
  * The set of socket operations
  *
  */
-struct pcmcia_low_level flexanet_pcmcia_ops = {
-  flexanet_pcmcia_init,
-  flexanet_pcmcia_shutdown,
-  flexanet_pcmcia_socket_state,
-  flexanet_pcmcia_get_irq_info,
-  flexanet_pcmcia_configure_socket
+static struct pcmcia_low_level flexanet_pcmcia_ops = {
+  init:			flexanet_pcmcia_init,
+  shutdown:		flexanet_pcmcia_shutdown,
+  socket_state:		flexanet_pcmcia_socket_state,
+  get_irq_info:		flexanet_pcmcia_get_irq_info,
+  configure_socket:	flexanet_pcmcia_configure_socket,
+
+  socket_init:		flexanet_pcmcia_socket_init,
+  socket_suspend:	flexanet_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_flexanet_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_flexanet())
+		ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_flexanet_exit(void)
+{
+	sa1100_unregister_pcmcia(&flexanet_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_freebird.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_freebird.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_freebird.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_freebird.c	Wed Mar  6 17:17:51 2002
@@ -6,14 +6,22 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_FREEBIRD_CF_CD,  "CF_CD"   },
+	{ IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" },
+};
 
 static int freebird_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+  int i, res;
 
   /* Enable Linkup CF card */
   LINKUP_PRC = 0xc0;
@@ -26,37 +34,38 @@
   mdelay(100);
   LINKUP_PRC = 0xc0;
 
-  /* All those are inputs */
-  ////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
-  GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD);
-
   /* Set transition detect */
-  //set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES );
-  //set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
-  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES);
-  set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE);
+  set_irq_type(IRQ_GPIO_FREEBIRD_CF_IRQ, IRQT_FALLING);
 
   /* Register interrupts */
-  irq = IRQ_GPIO_FREEBIRD_CF_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_FREEBIRD_CF_BVD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
-  if( res < 0 ) goto irq_err;
+  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+    set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+    		      irqs[i].str, NULL);
+    if (res)
+      goto irq_err;
+  }
 
   /* There's only one slot, but it's "Slot 1": */
   return 2;
 
 irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
-  return -1;
+  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	 __FUNCTION__, irqs[i].irq, res);
+
+  while (i--)
+    free_irq(irqs[i].irq, NULL);
+
+  return res;
 }
 
 static int freebird_pcmcia_shutdown(void)
 {
+  int i;
+
   /* disable IRQs */
-  free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL );
-  free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL );
+  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+    free_irq(irqs[i].irq, NULL);
 
   /* Disable CF card */
   LINKUP_PRC = 0x40;  /* SSP=1   SOE=0 */
@@ -75,7 +84,7 @@
 	 (state_array->size)*sizeof(struct pcmcia_state));
 
   levels = LINKUP_PRS;
-//printk("LINKUP_PRS=%x \n",levels);
+//printk("LINKUP_PRS=%x\n",levels);
 
   state_array->state[0].detect=
     ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
@@ -114,7 +123,7 @@
 
   if(configure->sock==1) return 0;
 
-  save_flags_cli(flags);
+  local_irq_save(flags);
 
   value = 0xc0;   /* SSP=1  SOE=1  CFE=1 */
 
@@ -134,7 +143,7 @@
   default:
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
-    restore_flags(flags);
+    local_irq_restore(flags);
     return -1;
   }
 
@@ -145,16 +154,51 @@
 
   LINKUP_PRC = value;
 //printk("LINKUP_PRC=%x\n",value);
-  restore_flags(flags);
+  local_irq_restore(flags);
+
+  return 0;
+}
+
+static int freebird_pcmcia_socket_init(int sock)
+{
+  if (sock == 1) {
+    set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
+    set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
+  }
+  return 0;
+}
 
+static int freebird_pcmcia_socket_suspend(int sock)
+{
+  if (sock == 1) {
+    set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE);
+    set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE);
+  }
   return 0;
 }
 
-struct pcmcia_low_level freebird_pcmcia_ops = {
-  freebird_pcmcia_init,
-  freebird_pcmcia_shutdown,
-  freebird_pcmcia_socket_state,
-  freebird_pcmcia_get_irq_info,
-  freebird_pcmcia_configure_socket
+static struct pcmcia_low_level freebird_pcmcia_ops = {
+  init:			freebird_pcmcia_init,
+  shutdown:		freebird_pcmcia_shutdown,
+  socket_state:		freebird_pcmcia_socket_state,
+  get_irq_info:		freebird_pcmcia_get_irq_info,
+  configure_socket:	freebird_pcmcia_configure_socket,
+
+  socket_init:		freebird_pcmcia_socket_init,
+  socket_suspend:	freebird_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_freebird_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_freebird())
+		ret = sa1100_register_pcmcia(&freebird_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_freebird_exit(void)
+{
+	sa1100_unregister_pcmcia(&freebird_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_generic.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_generic.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_generic.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_generic.c	Wed Mar  6 17:17:51 2002
@@ -29,6 +29,10 @@
     file under either the MPL or the GPL.
     
 ======================================================================*/
+/*
+ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
+ * on the low-level kernel interface.
+ */
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -43,6 +47,7 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
+#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -62,338 +67,94 @@
 static int pc_debug;
 #endif
 
-MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
-
 /* This structure maintains housekeeping state for each socket, such
  * as the last known values of the card detect pins, or the Card Services
  * callback value associated with the socket:
  */
-static struct sa1100_pcmcia_socket 
-sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
-
 static int sa1100_pcmcia_socket_count;
+static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK];
 
+#define PCMCIA_SOCKET(x)	(sa1100_pcmcia_socket + (x))
 
 /* Returned by the low-level PCMCIA interface: */
 static struct pcmcia_low_level *pcmcia_low_level;
 
-/* Event poll timer structure */
 static struct timer_list poll_timer;
-
-
-/* Prototypes for routines which are used internally: */
-
-static int  sa1100_pcmcia_driver_init(void);
-static void sa1100_pcmcia_driver_shutdown(void);
-static void sa1100_pcmcia_task_handler(void *data);
-static void sa1100_pcmcia_poll_event(unsigned long data);
-static void sa1100_pcmcia_interrupt(int irq, void *dev,
-				    struct pt_regs *regs);
 static struct tq_struct sa1100_pcmcia_task;
 
-#ifdef CONFIG_PROC_FS
-static int  sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-				      int count, int *eof, void *data);
-#endif
-
-
-/* Prototypes for operations which are exported to the
- * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
+/*
+ * sa1100_pcmcia_state_to_config
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Convert PCMCIA socket state to our socket configure structure.
  */
+static struct pcmcia_configure
+sa1100_pcmcia_state_to_config(unsigned int sock, socket_state_t *state)
+{
+  struct pcmcia_configure conf;
 
-static int sa1100_pcmcia_init(unsigned int sock);
-static int sa1100_pcmcia_suspend(unsigned int sock);
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *, 
-							   unsigned int),
-					   void *info);
-static int sa1100_pcmcia_inquire_socket(unsigned int sock, 
-					socket_cap_t *cap);
-static int sa1100_pcmcia_get_status(unsigned int sock, u_int *value);
-static int sa1100_pcmcia_get_socket(unsigned int sock, 
-				    socket_state_t *state);
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state);
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *io);
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *mem);
-#ifdef CONFIG_PROC_FS
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
-				     struct proc_dir_entry *base);
-#endif
-
-static struct pccard_operations sa1100_pcmcia_operations = {
-  sa1100_pcmcia_init,
-  sa1100_pcmcia_suspend,
-  sa1100_pcmcia_register_callback,
-  sa1100_pcmcia_inquire_socket,
-  sa1100_pcmcia_get_status,
-  sa1100_pcmcia_get_socket,
-  sa1100_pcmcia_set_socket,
-  sa1100_pcmcia_get_io_map,
-  sa1100_pcmcia_set_io_map,
-  sa1100_pcmcia_get_mem_map,
-  sa1100_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
-  sa1100_pcmcia_proc_setup
-#endif
-};
-
-#ifdef CONFIG_CPU_FREQ
-/* forward declaration */
-static struct notifier_block sa1100_pcmcia_notifier_block;
-#endif
+  conf.sock    = sock;
+  conf.vcc     = state->Vcc;
+  conf.vpp     = state->Vpp;
+  conf.output  = state->flags & SS_OUTPUT_ENA ? 1 : 0;
+  conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0;
+  conf.reset   = state->flags & SS_RESET ? 1 : 0;
+  conf.irq     = state->io_irq != 0;
 
+  return conf;
+}
 
-/* sa1100_pcmcia_driver_init()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * This routine performs a basic sanity check to ensure that this
- * kernel has been built with the appropriate board-specific low-level
- * PCMCIA support, performs low-level PCMCIA initialization, registers
- * this socket driver with Card Services, and then spawns the daemon
- * thread which is the real workhorse of the socket driver.
+/* sa1100_pcmcia_sock_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^
  *
- * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
- * on the low-level kernel interface.
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus.  This must wait for power to stabilise
+ * so that the card status signals report correctly.
  *
- * Returns: 0 on success, -1 on error
- */
-static int __init sa1100_pcmcia_driver_init(void){
-  servinfo_t info;
-  struct pcmcia_init pcmcia_init;
-  struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
-  struct pcmcia_state_array state_array;
-  unsigned int i, clock;
-  unsigned long mecr;
-
-  printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
-
-  CardServices(GetCardServicesInfo, &info);
-
-  if(info.Revision!=CS_RELEASE_CODE){
-    printk(KERN_ERR "Card Services release codes do not match\n");
-    return -1;
-  }
-
-  if(machine_is_assabet()){
-#ifdef CONFIG_SA1100_ASSABET
-    if(machine_has_neponset()){
-#ifdef CONFIG_ASSABET_NEPONSET
-      pcmcia_low_level=&neponset_pcmcia_ops;
-#else
-      printk(KERN_ERR "Card Services disabled: missing Neponset support\n");
-      return -1;
-#endif
-    }else{
-      pcmcia_low_level=&assabet_pcmcia_ops;
-    }
-#endif
-  } else if (machine_is_freebird()) {
-#ifdef CONFIG_SA1100_FREEBIRD
-    pcmcia_low_level = &freebird_pcmcia_ops;
-#endif
-  } else if (machine_is_h3600()) {
-#ifdef CONFIG_SA1100_H3600
-    pcmcia_low_level = &h3600_pcmcia_ops;
-#endif    
-  } else if (machine_is_cerf()) {
-#ifdef CONFIG_SA1100_CERF
-    pcmcia_low_level = &cerf_pcmcia_ops;
-#endif
-  } else if (machine_is_graphicsclient()) {
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-    pcmcia_low_level = &gcplus_pcmcia_ops;
-#endif
-  } else if (machine_is_xp860()) {
-#ifdef CONFIG_SA1100_XP860
-    pcmcia_low_level = &xp860_pcmcia_ops;
-#endif
-  } else if (machine_is_yopy()) {
-#ifdef CONFIG_SA1100_YOPY
-    pcmcia_low_level = &yopy_pcmcia_ops;
-#endif
-  } else if (machine_is_pangolin()) {
-#ifdef CONFIG_SA1100_PANGOLIN
-    pcmcia_low_level = &pangolin_pcmcia_ops;
-#endif
-  } else if (machine_is_jornada720()) {
-#ifdef CONFIG_SA1100_JORNADA720
-    pcmcia_low_level = &jornada720_pcmcia_ops;
-#endif
-  } else if(machine_is_pfs168()){
-#ifdef CONFIG_SA1100_PFS168
-    pcmcia_low_level=&pfs168_pcmcia_ops;
-#endif
-  } else if(machine_is_flexanet()){
-#ifdef CONFIG_SA1100_FLEXANET
-    pcmcia_low_level=&flexanet_pcmcia_ops;
-#endif
- } else if(machine_is_simpad()){
-#ifdef CONFIG_SA1100_SIMPAD
-    pcmcia_low_level=&simpad_pcmcia_ops;
-#endif
-  } else if(machine_is_graphicsmaster()) {
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-    pcmcia_low_level=&graphicsmaster_pcmcia_ops;
-#endif
-  } else if(machine_is_adsbitsy()) {
-#ifdef CONFIG_SA1100_ADSBITSY
-    pcmcia_low_level=&adsbitsy_pcmcia_ops;
-#endif
-  } else if(machine_is_stork()) {
-#ifdef CONFIG_SA1100_STORK
-    pcmcia_low_level=&stork_pcmcia_ops;
-#endif
-  }
-
-  if (!pcmcia_low_level) {
-    printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n");
-    return -ENODEV;
-  }
-
-  pcmcia_init.handler=sa1100_pcmcia_interrupt;
-
-  if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
-    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
-    return -EIO;
-  }
-
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
-
-  if(pcmcia_low_level->socket_state(&state_array)<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
-    return -EIO;
-  }
-
-  /* We initialize the MECR to default values here, because we are
-   * not guaranteed to see a SetIOMap operation at runtime.
-   */
-  mecr=0;
-
-  clock = get_cclk_frequency() * 100;
-
-  for(i=0; i<sa1100_pcmcia_socket_count; ++i){
-    sa1100_pcmcia_socket[i].k_state=state[i];
-
-    /* This is an interim fix. Apparently, SetSocket is no longer
-     * called to initialize each socket (prior to the first detect
-     * event). For now, we'll just manually set up the mask.
-     */
-    sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
-
-    sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
-    sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
-    sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
-
-    MECR_FAST_SET(mecr, i, 0);
-    MECR_BSIO_SET(mecr, i,
-		  sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock));
-    MECR_BSA_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-    MECR_BSM_SET(mecr, i,
-		 sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock));
-
-    sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS;
-    sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS;
-    sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS;
-  }
-
-  MECR=mecr;
-
-#ifdef CONFIG_CPU_FREQ
-  if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){
-    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
-    return -ENXIO;
-  }
-#endif
-
-  /* Only advertise as many sockets as we can detect: */
-  if(register_ss_entry(sa1100_pcmcia_socket_count, 
-		       &sa1100_pcmcia_operations)<0){
-    printk(KERN_ERR "Unable to register socket service routine\n");
-    return -ENXIO;
-  }
-
-  /* Start the event poll timer.  It will reschedule by itself afterwards. */
-  sa1100_pcmcia_poll_event(0);
-
-  DEBUG(1, "sa1100: initialization complete\n");
-
-  return 0;
-
-}  /* sa1100_pcmcia_driver_init() */
-
-module_init(sa1100_pcmcia_driver_init);
-
-
-/* sa1100_pcmcia_driver_shutdown()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
+ * Returns: 0
  */
-static void __exit sa1100_pcmcia_driver_shutdown(void){
+static int sa1100_pcmcia_sock_init(unsigned int sock)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
 
-  del_timer_sync(&poll_timer);
-  unregister_ss_entry(&sa1100_pcmcia_operations);
-#ifdef CONFIG_CPU_FREQ
-  cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
-#endif
-  pcmcia_low_level->shutdown();
-  flush_scheduled_tasks();
+  DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
 
-  DEBUG(1, "sa1100: shutdown complete\n");
-}
+  skt->cs_state = dead_socket;
 
-module_exit(sa1100_pcmcia_driver_shutdown);
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
 
+  pcmcia_low_level->configure_socket(&conf);
 
-/* sa1100_pcmcia_init()
- * ^^^^^^^^^^^^^^^^^^^^
- * We perform all of the interesting initialization tasks in 
- * sa1100_pcmcia_driver_init().
- *
- * Returns: 0
- */
-static int sa1100_pcmcia_init(unsigned int sock){
-  
-  DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
-
-  return 0;
+  return pcmcia_low_level->socket_init(sock);
 }
 
 
-/* sa1100_pcmcia_suspend()
+/*
+ * sa1100_pcmcia_suspend()
  * ^^^^^^^^^^^^^^^^^^^^^^^
- * We don't currently perform any actions on a suspend.
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
  *
  * Returns: 0
  */
 static int sa1100_pcmcia_suspend(unsigned int sock)
 {
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   struct pcmcia_configure conf;
   int ret;
 
   DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
 
-  conf.sock = sock;
-  conf.vcc = 0;
-  conf.vpp = 0;
-  conf.output = 0;
-  conf.speaker = 0;
-  conf.reset = 1;
+  conf = sa1100_pcmcia_state_to_config(sock, &dead_socket);
 
   ret = pcmcia_low_level->configure_socket(&conf);
 
-  if (ret == 0)
-    sa1100_pcmcia_socket[sock].cs_state = dead_socket;
+  if (ret == 0) {
+    skt->cs_state = dead_socket;
+    ret = pcmcia_low_level->socket_suspend(sock);
+  }
 
   return ret;
 }
@@ -407,52 +168,50 @@
  *
  * Returns: an event mask for the given socket state.
  */
-static inline unsigned sa1100_pcmcia_events(struct pcmcia_state *state,
-					    struct pcmcia_state *prev_state,
-					    unsigned int mask,
-					    unsigned int flags){
-  unsigned int events=0;
-
-  if(state->detect!=prev_state->detect){
+static inline unsigned int
+sa1100_pcmcia_events(struct pcmcia_state *state,
+		     struct pcmcia_state *prev_state,
+		     unsigned int mask, unsigned int flags)
+{
+  unsigned int events = 0;
 
-    DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
+  if (state->detect != prev_state->detect) {
+    DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
 
-    events|=mask&SS_DETECT;
+    events |= SS_DETECT;
   }
 
-  if(state->ready!=prev_state->ready){
-
-    DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
+  if (state->ready != prev_state->ready) {
+    DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
 
-    events|=mask&((flags&SS_IOCARD)?0:SS_READY);
+    events |= flags & SS_IOCARD ? 0 : SS_READY;
   }
 
-  if(state->bvd1!=prev_state->bvd1){
+  if (state->bvd1 != prev_state->bvd1) {
+    DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
 
-    DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
-
-    events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
+    events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD;
   }
 
-  if(state->bvd2!=prev_state->bvd2){
-
-    DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
+  if (state->bvd2 != prev_state->bvd2) {
+    DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
 
-    events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
+    events |= flags & SS_IOCARD ? 0 : SS_BATWARN;
   }
 
-  DEBUG(2, "events: %s%s%s%s%s%s\n",
-	(events==0)?"<NONE>":"",
-	(events&SS_DETECT)?"DETECT ":"",
-	(events&SS_READY)?"READY ":"",
-	(events&SS_BATDEAD)?"BATDEAD ":"",
-	(events&SS_BATWARN)?"BATWARN ":"",
-	(events&SS_STSCHG)?"STSCHG ":"");
+  *prev_state = *state;
 
-  *prev_state=*state;
+  events &= mask;
 
-  return events;
+  DEBUG(2, "events: %s%s%s%s%s%s\n",
+	events == 0         ? "<NONE>"   : "",
+	events & SS_DETECT  ? "DETECT "  : "",
+	events & SS_READY   ? "READY "   : "",
+	events & SS_BATDEAD ? "BATDEAD " : "",
+	events & SS_BATWARN ? "BATWARN " : "",
+	events & SS_STSCHG  ? "STSCHG "  : "");
 
+  return events;
 }  /* sa1100_pcmcia_events() */
 
 
@@ -464,38 +223,43 @@
  * callback) occurs in this thread rather than in the actual interrupt
  * handler due to the use of scheduling operations in the PCMCIA core.
  */
-static void sa1100_pcmcia_task_handler(void *data) {
+static void sa1100_pcmcia_task_handler(void *data)
+{
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
-  int i, events, all_events, irq_status;
+  unsigned int all_events;
 
-  DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
+  DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
   do {
+    unsigned int events;
+    int ret, i;
 
-    DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
+    memset(state, 0, sizeof(state));
 
-    if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
-      printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
+    DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
 
-    all_events=0;
+    ret = pcmcia_low_level->socket_state(&state_array);
+    if (ret < 0) {
+      printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n");
+      break;
+    }
 
-    if(irq_status>0){
+    all_events = 0;
 
-      for(i=0; i<state_array.size; ++i, all_events|=events)
-	if((events=
-	    sa1100_pcmcia_events(&state[i],
-				 &sa1100_pcmcia_socket[i].k_state,
-				 sa1100_pcmcia_socket[i].cs_state.csc_mask,
-				 sa1100_pcmcia_socket[i].cs_state.flags)))
-	  if(sa1100_pcmcia_socket[i].handler!=NULL)
-	    sa1100_pcmcia_socket[i].handler(sa1100_pcmcia_socket[i].handler_info,
-					    events);
-    }
+    for (i = 0; i < state_array.size; i++, all_events |= events) {
+      struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
 
+      events = sa1100_pcmcia_events(&state[i], &skt->k_state,
+				    skt->cs_state.csc_mask,
+				    skt->cs_state.flags);
+
+      if (events && sa1100_pcmcia_socket[i].handler != NULL)
+	skt->handler(skt->handler_info, events);
+    }
   } while(all_events);
 }  /* sa1100_pcmcia_task_handler() */
 
@@ -510,7 +274,7 @@
  */
 static void sa1100_pcmcia_poll_event(unsigned long dummy)
 {
-  DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
+  DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
   poll_timer.function = sa1100_pcmcia_poll_event;
   poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
   add_timer(&poll_timer);
@@ -527,7 +291,8 @@
  * handling code performs scheduling operations which cannot be
  * executed from within an interrupt context.
  */
-static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
+static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
   DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
   schedule_task(&sa1100_pcmcia_task);
 }
@@ -546,17 +311,20 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_register_callback(unsigned int sock,
-					   void (*handler)(void *,
-							   unsigned int),
-					   void *info){
-  if(handler==NULL){
-    sa1100_pcmcia_socket[sock].handler=NULL;
+static int
+sa1100_pcmcia_register_callback(unsigned int sock,
+				void (*handler)(void *, unsigned int),
+				void *info)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+
+  if (handler == NULL) {
+    skt->handler = NULL;
     MOD_DEC_USE_COUNT;
   } else {
     MOD_INC_USE_COUNT;
-    sa1100_pcmcia_socket[sock].handler=handler;
-    sa1100_pcmcia_socket[sock].handler_info=info;
+    skt->handler_info = info;
+    skt->handler = handler;
   }
 
   return 0;
@@ -580,51 +348,41 @@
  * an offset which is applied to client-requested base I/O addresses
  * in alloc_io_space().
  *
- * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
+ *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
+ *   general, the mapped * addresses of the PCMCIA memory regions
+ *   will not be within 0xffff, setting force_low would be
+ *   undesirable.
+ *
+ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
+ *   resource database; we instead pass up physical address ranges
+ *   and allow other parts of Card Services to deal with remapping.
+ *
+ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
+ *   not 32-bit CardBus devices.
+ *
+ * Return value is irrelevant; the pcmcia subsystem ignores it.
  */
-static int sa1100_pcmcia_inquire_socket(unsigned int sock,
-					socket_cap_t *cap){
-  struct pcmcia_irq_info irq_info;
-
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if(sock>=sa1100_pcmcia_socket_count){
-    printk(KERN_ERR "sa1100: socket %u not configured\n", sock);
-    return -1;
-  }
+static int
+sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
-   *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
-   *   general, the mapped * addresses of the PCMCIA memory regions
-   *   will not be within 0xffff, setting force_low would be
-   *   undesirable.
-   *
-   * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
-   *   resource database; we instead pass up physical address ranges
-   *   and allow other parts of Card Services to deal with remapping.
-   *
-   * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
-   *   not 32-bit CardBus devices.
-   */
-  cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  irq_info.sock=sock;
-  irq_info.irq=-1;
+  if (sock < sa1100_pcmcia_socket_count) {
+    cap->features  = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+    cap->irq_mask  = 0;
+    cap->map_size  = PAGE_SIZE;
+    cap->pci_irq   = skt->irq;
+    cap->io_offset = (unsigned long)skt->virt_io;
 
-  if(pcmcia_low_level->get_irq_info(&irq_info)<0){
-    printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
-	   sock);
-    return -1;
+    ret = 0;
   }
 
-  cap->irq_mask=0;
-  cap->map_size=PAGE_SIZE;
-  cap->pci_irq=irq_info.irq;
-  cap->io_offset=sa1100_pcmcia_socket[sock].virt_io;
-
-  return 0;
-
-}  /* sa1100_pcmcia_inquire_socket() */
+  return ret;
+}
 
 
 /* sa1100_pcmcia_get_status()
@@ -643,58 +401,61 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_status(unsigned int sock,
-				    unsigned int *status){
+static int
+sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
   struct pcmcia_state_array state_array;
+  unsigned int stat;
+
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  state_array.size = sa1100_pcmcia_socket_count;
+  state_array.state = state;
 
-  state_array.size=sa1100_pcmcia_socket_count;
-  state_array.state=state;
+  memset(state, 0, sizeof(state));
 
-  if((pcmcia_low_level->socket_state(&state_array))<0){
-    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
+  if ((pcmcia_low_level->socket_state(&state_array)) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n");
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].k_state=state[sock];
+  skt->k_state = state[sock];
 
-  *status=state[sock].detect?SS_DETECT:0;
-
-  *status|=state[sock].ready?SS_READY:0;
+  stat = state[sock].detect ? SS_DETECT : 0;
+  stat |= state[sock].ready ? SS_READY  : 0;
+  stat |= state[sock].vs_3v ? SS_3VCARD : 0;
+  stat |= state[sock].vs_Xv ? SS_XVCARD : 0;
 
   /* The power status of individual sockets is not available
    * explicitly from the hardware, so we just remember the state
    * and regurgitate it upon request:
    */
-  *status|=sa1100_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
+  stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
 
-  if(sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
-    *status|=state[sock].bvd1?SS_STSCHG:0;
+  if (skt->cs_state.flags & SS_IOCARD)
+    stat |= state[sock].bvd1 ? SS_STSCHG : 0;
   else {
-    if(state[sock].bvd1==0)
-      *status|=SS_BATDEAD;
-    else if(state[sock].bvd2==0)
-      *status|=SS_BATWARN;
+    if (state[sock].bvd1 == 0)
+      stat |= SS_BATDEAD;
+    else if (state[sock].bvd2 == 0)
+      stat |= SS_BATWARN;
   }
 
-  *status|=state[sock].vs_3v?SS_3VCARD:0;
-
-  *status|=state[sock].vs_Xv?SS_XVCARD:0;
-
   DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
-	(*status&SS_DETECT)?"DETECT ":"",
-	(*status&SS_READY)?"READY ":"", 
-	(*status&SS_BATDEAD)?"BATDEAD ":"",
-	(*status&SS_BATWARN)?"BATWARN ":"",
-	(*status&SS_POWERON)?"POWERON ":"",
-	(*status&SS_STSCHG)?"STSCHG ":"",
-	(*status&SS_3VCARD)?"3VCARD ":"",
-	(*status&SS_XVCARD)?"XVCARD ":"");
+	stat & SS_DETECT  ? "DETECT "  : "",
+	stat & SS_READY   ? "READY "   : "", 
+	stat & SS_BATDEAD ? "BATDEAD " : "",
+	stat & SS_BATWARN ? "BATWARN " : "",
+	stat & SS_POWERON ? "POWERON " : "",
+	stat & SS_STSCHG  ? "STSCHG "  : "",
+	stat & SS_3VCARD  ? "3VCARD "  : "",
+	stat & SS_XVCARD  ? "XVCARD "  : "");
 
-  return 0;
+  *status = stat;
 
+  return 0;
 }  /* sa1100_pcmcia_get_status() */
 
 
@@ -706,20 +467,18 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_get_socket(unsigned int sock,
-				    socket_state_t *state){
+static int
+sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  /* This information was given to us in an earlier call to set_socket(),
-   * so we're just regurgitating it here:
-   */
-  *state=sa1100_pcmcia_socket[sock].cs_state;
+  *state = skt->cs_state;
 
   return 0;
 }
 
-
 /* sa1100_pcmcia_set_socket()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the set_socket() operation for the in-kernel PCMCIA
@@ -730,14 +489,15 @@
  *
  * Returns: 0
  */
-static int sa1100_pcmcia_set_socket(unsigned int sock,
-				    socket_state_t *state){
-  struct pcmcia_configure configure;
+static int
+sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  struct pcmcia_configure conf;
 
-  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
-	"\tVcc %d  Vpp %d  irq %d\n",
+  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
 	(state->csc_mask==0)?"<NONE>":"",
 	(state->csc_mask&SS_DETECT)?"DETECT ":"",
 	(state->csc_mask&SS_READY)?"READY ":"",
@@ -749,25 +509,20 @@
 	(state->flags&SS_IOCARD)?"IOCARD ":"",
 	(state->flags&SS_RESET)?"RESET ":"",
 	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
+  DEBUG(3, "\tVcc %d  Vpp %d  irq %d\n",
 	state->Vcc, state->Vpp, state->io_irq);
 
-  configure.sock=sock;
-  configure.vcc=state->Vcc;
-  configure.vpp=state->Vpp;
-  configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
-  configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
-  configure.reset=(state->flags&SS_RESET)?1:0;
+  conf = sa1100_pcmcia_state_to_config(sock, state);
 
-  if(pcmcia_low_level->configure_socket(&configure)<0){
-    printk(KERN_ERR "Unable to configure socket %u\n", sock);
+  if (pcmcia_low_level->configure_socket(&conf) < 0) {
+    printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock);
     return -1;
   }
 
-  sa1100_pcmcia_socket[sock].cs_state=*state;
+  skt->cs_state = *state;
   
   return 0;
-
 }  /* sa1100_pcmcia_set_socket() */
 
 
@@ -779,20 +534,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
+static int
+sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_IO_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_IO_WIN) {
+    *map = skt->io_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].io_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -805,16 +560,16 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_io_map(unsigned int sock,
-				    struct pccard_io_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->start, map->stop,
+  DEBUG(3, "\tmap %u  speed %u\n\tstart 0x%08x  stop 0x%08x\n",
+	map->map, map->speed, map->start, map->stop);
+  DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
 	(map->flags==0)?"<NONE>":"",
 	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 	(map->flags&MAP_16BIT)?"16BIT ":"",
@@ -824,45 +579,45 @@
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
 	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
 
-  if(map->map>=MAX_IO_WIN){
+  if (map->map >= MAX_IO_WIN) {
     printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
 	   map->map);
     return -1;
   }
 
-  if(map->flags&MAP_ACTIVE){
+  if (map->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
 
-    speed=(map->speed>0)?map->speed:SA1100_PCMCIA_IO_ACCESS;
+    if (speed == 0)
+      speed = SA1100_PCMCIA_IO_ACCESS;
 
-    clock = get_cclk_frequency() * 100;
+    clock = cpufreq_get(0);
 
-    mecr=MECR;
+    mecr = MECR;
 
     MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
 
-    sa1100_pcmcia_socket[sock].speed_io=speed;
+    skt->speed_io = speed;
 
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
 
-    MECR=mecr;
-
+    MECR = mecr;
   }
 
-  start=map->start;
-
-  if(map->stop==1)
-    map->stop=PAGE_SIZE-1;
+  if (map->stop == 1)
+    map->stop = PAGE_SIZE-1;
 
-  map->start=sa1100_pcmcia_socket[sock].virt_io;
-  map->stop=map->start+(map->stop-start);
+  map->stop -= map->start;
+  map->stop += (unsigned long)skt->virt_io;
+  map->start = (unsigned long)skt->virt_io;
 
-  sa1100_pcmcia_socket[sock].io_map[map->map]=*map;
+  skt->io_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_io_map() */
 
 
@@ -875,20 +630,20 @@
  *
  * Returns: 0 on success, -1 if the map index was out of range
  */
-static int sa1100_pcmcia_get_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
+static int
+sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  int ret = -1;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  if(map->map>=MAX_WIN){
-    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
-	   map->map);
-    return -1;
+  if (map->map < MAX_WIN) {
+    *map = skt->mem_map[map->map];
+    ret = 0;
   }
 
-  *map=sa1100_pcmcia_socket[sock].mem_map[map->map];
-
-  return 0;
+  return ret;
 }
 
 
@@ -901,18 +656,18 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_set_mem_map(unsigned int sock,
-				     struct pccard_mem_map *map){
-  unsigned int clock, speed;
-  unsigned long mecr, start;
+static int
+sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
+{
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
+  unsigned long start;
 
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+  DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
-  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
-	"\tsys_stop   %#lx\n\tcard_start %#x\n"
-	"\tflags: %s%s%s%s%s%s%s%s\n",
-	map->map, map->speed, map->sys_start, map->sys_stop,
-	map->card_start, (map->flags==0)?"<NONE>":"",
+  DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n",
+	map->map, map->speed, map->sys_start, map->sys_stop, map->card_start);
+  DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n",
+	(map->flags==0)?"<NONE>":"",
 	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
 	(map->flags&MAP_16BIT)?"16BIT ":"",
 	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
@@ -921,177 +676,175 @@
 	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
 
-  if(map->map>=MAX_WIN){
+  if (map->map >= MAX_WIN){
     printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
 	   map->map);
     return -1;
   }
 
-  if(map->flags&MAP_ACTIVE){
-
-    /* When clients issue RequestMap, the access speed is not always
-     * properly configured:
+  if (map->flags & MAP_ACTIVE) {
+    unsigned int clock, speed = map->speed;
+    unsigned long mecr;
+
+    /*
+     * When clients issue RequestMap, the access speed is not always
+     * properly configured.  Choose some sensible defaults.
      */
-    if(map->speed > 0)
-      speed = map->speed;
-    else
-      switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){
-      case 33:
+    if (speed == 0) {
+      if (skt->cs_state.Vcc == 33)
 	speed = SA1100_PCMCIA_3V_MEM_ACCESS;
-	break;
-      default:
+      else
 	speed = SA1100_PCMCIA_5V_MEM_ACCESS;
-      }
+    }
 
-    clock = get_cclk_frequency() * 100;
-    
-    mecr=MECR;
-    
-    if(map->flags&MAP_ATTRIB){
+    clock = cpufreq_get(0);
 
-      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_attr=speed;
+    /* Fixme: MECR is not pre-empt safe. */
+    mecr = MECR;
 
+    if (map->flags & MAP_ATTRIB) {
+      MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
+      skt->speed_attr = speed;
     } else {
-
       MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock));
-      sa1100_pcmcia_socket[sock].speed_mem=speed;
-
+      skt->speed_mem = speed;
     }
-    
+
     DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
 	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
 	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
 	  sock, MECR_BSIO_GET(mecr, sock));
-    
-    MECR=mecr;
 
+    MECR = mecr;
   }
 
-  start=map->sys_start;
+  start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem;
 
-  if(map->sys_stop==0)
-    map->sys_stop=PAGE_SIZE-1;
+  if (map->sys_stop == 0)
+    map->sys_stop = PAGE_SIZE-1;
 
-  map->sys_start=(map->flags & MAP_ATTRIB)?\
-    sa1100_pcmcia_socket[sock].phys_attr:\
-    sa1100_pcmcia_socket[sock].phys_mem;
+  map->sys_stop -= map->sys_start;
+  map->sys_stop += start;
+  map->sys_start = start;
 
-  map->sys_stop=map->sys_start+(map->sys_stop-start);
-
-  sa1100_pcmcia_socket[sock].mem_map[map->map]=*map;
+  skt->mem_map[map->map] = *map;
 
   return 0;
-
 }  /* sa1100_pcmcia_set_mem_map() */
 
 
 #if defined(CONFIG_PROC_FS)
 
-/* sa1100_pcmcia_proc_setup()
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- * Implements the proc_setup() operation for the in-kernel PCMCIA
- * service (formerly SS_ProcSetup in Card Services).
- *
- * Returns: 0 on success, -1 on error
- */
-static void sa1100_pcmcia_proc_setup(unsigned int sock,
-				     struct proc_dir_entry *base){
-  struct proc_dir_entry *entry;
-
-  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
-
-  if((entry=create_proc_entry("status", 0, base))==NULL){
-    printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
-    return;
-  }
-
-  entry->read_proc=sa1100_pcmcia_proc_status;
-  entry->data=(void *)sock;
-}
-
-
 /* sa1100_pcmcia_proc_status()
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  * Implements the /proc/bus/pccard/??/status file.
  *
  * Returns: the number of characters added to the buffer
  */
-static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
-				     int count, int *eof, void *data){
-  char *p=buf;
-  unsigned int sock=(unsigned int)data;
-  unsigned int clock = get_cclk_frequency() * 100;
+static int
+sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+  unsigned int sock = (unsigned int)data;
+  unsigned int clock = cpufreq_get(0);
+  struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
   unsigned long mecr = MECR;
+  char *p = buf;
 
-  p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
-	     sa1100_pcmcia_socket[sock].k_state.detect?"detect ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"ready ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
-	     sa1100_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
+  p+=sprintf(p, "k_state  : %s%s%s%s%s%s%s\n", 
+	     skt->k_state.detect ? "detect " : "",
+	     skt->k_state.ready  ? "ready "  : "",
+	     skt->k_state.bvd1   ? "bvd1 "   : "",
+	     skt->k_state.bvd2   ? "bvd2 "   : "",
+	     skt->k_state.wrprot ? "wrprot " : "",
+	     skt->k_state.vs_3v  ? "vs_3v "  : "",
+	     skt->k_state.vs_Xv  ? "vs_Xv "  : "");
 
   p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     (sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
-	      sa1100_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
-	     ((sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (sa1100_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
-	     sa1100_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
+	     skt->k_state.detect ? "SS_DETECT " : "",
+	     skt->k_state.ready  ? "SS_READY " : "",
+	     skt->cs_state.Vcc   ? "SS_POWERON " : "",
+	     skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "",
+	     (skt->cs_state.flags & SS_IOCARD &&
+	      skt->k_state.bvd1) ? "SS_STSCHG " : "",
+	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
+	      (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "",
+	     ((skt->cs_state.flags & SS_IOCARD)==0 &&
+	      (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "",
+	     skt->k_state.vs_3v  ? "SS_3VCARD " : "",
+	     skt->k_state.vs_Xv  ? "SS_XVCARD " : "");
 
   p+=sprintf(p, "mask     : %s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
-	     "SS_DETECT ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
-	     "SS_READY ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
-	     "SS_BATDEAD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
-	     "SS_BATWARN ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
-	     "SS_STSCHG ":"");
+	     skt->cs_state.csc_mask & SS_DETECT  ? "SS_DETECT "  : "",
+	     skt->cs_state.csc_mask & SS_READY   ? "SS_READY "   : "",
+	     skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "",
+	     skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "",
+	     skt->cs_state.csc_mask & SS_STSCHG  ? "SS_STSCHG "  : "");
 
   p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
-	     "SS_PWR_AUTO ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
-	     "SS_RESET ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
-	     "SS_SPKR_ENA ":"",
-	     sa1100_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
-	     "SS_OUTPUT_ENA ":"");
-
-  p+=sprintf(p, "Vcc      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vcc);
+	     skt->cs_state.flags & SS_PWR_AUTO   ? "SS_PWR_AUTO "   : "",
+	     skt->cs_state.flags & SS_IOCARD     ? "SS_IOCARD "     : "",
+	     skt->cs_state.flags & SS_RESET      ? "SS_RESET "      : "",
+	     skt->cs_state.flags & SS_SPKR_ENA   ? "SS_SPKR_ENA "   : "",
+	     skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : "");
+
+  p+=sprintf(p, "Vcc      : %d\n", skt->cs_state.Vcc);
+  p+=sprintf(p, "Vpp      : %d\n", skt->cs_state.Vpp);
+  p+=sprintf(p, "IRQ      : %d\n", skt->cs_state.io_irq);
 
-  p+=sprintf(p, "Vpp      : %d\n", sa1100_pcmcia_socket[sock].cs_state.Vpp);
-
-  p+=sprintf(p, "irq      : %d\n", sa1100_pcmcia_socket[sock].cs_state.io_irq);
-
-  p+=sprintf(p, "I/O      : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_io,
+  p+=sprintf(p, "I/O      : %u (%u)\n", skt->speed_io,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock)));
 
-  p+=sprintf(p, "attribute: %u (%u)\n", sa1100_pcmcia_socket[sock].speed_attr,
+  p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock)));
 
-  p+=sprintf(p, "common   : %u (%u)\n", sa1100_pcmcia_socket[sock].speed_mem,
+  p+=sprintf(p, "common   : %u (%u)\n", skt->speed_mem,
 	     sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock)));
 
   return p-buf;
 }
 
+/* sa1100_pcmcia_proc_setup()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Implements the proc_setup() operation for the in-kernel PCMCIA
+ * service (formerly SS_ProcSetup in Card Services).
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static void
+sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+  struct proc_dir_entry *entry;
+
+  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+  if ((entry = create_proc_entry("status", 0, base)) == NULL){
+    printk(KERN_ERR "unable to install \"status\" procfs entry\n");
+    return;
+  }
+
+  entry->read_proc = sa1100_pcmcia_proc_status;
+  entry->data = (void *)sock;
+}
+
 #endif  /* defined(CONFIG_PROC_FS) */
 
+static struct pccard_operations sa1100_pcmcia_operations = {
+  init:			sa1100_pcmcia_sock_init,
+  suspend:		sa1100_pcmcia_suspend,
+  register_callback:	sa1100_pcmcia_register_callback,
+  inquire_socket:	sa1100_pcmcia_inquire_socket,
+  get_status:		sa1100_pcmcia_get_status,
+  get_socket:		sa1100_pcmcia_get_socket,
+  set_socket:		sa1100_pcmcia_set_socket,
+  get_io_map:		sa1100_pcmcia_get_io_map,
+  set_io_map:		sa1100_pcmcia_set_io_map,
+  get_mem_map:		sa1100_pcmcia_get_mem_map,
+  set_mem_map:		sa1100_pcmcia_set_mem_map,
+#ifdef CONFIG_PROC_FS
+  proc_setup:		sa1100_pcmcia_proc_setup
+#endif
+};
 
 #ifdef CONFIG_CPU_FREQ
 
@@ -1101,25 +854,23 @@
  * to a core clock frequency change) is needed, this routine establishes
  * new BS_xx values consistent with the clock speed `clock'.
  */
-static void sa1100_pcmcia_update_mecr(unsigned int clock){
+static void sa1100_pcmcia_update_mecr(unsigned int clock)
+{
   unsigned int sock;
   unsigned long mecr = MECR;
 
   for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){
+    struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock);
 
     MECR_BSIO_SET(mecr, sock,
-		  sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io,
-					clock));
+		  sa1100_pcmcia_mecr_bs(skt->speed_io, clock));
     MECR_BSA_SET(mecr, sock,
-		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr,
-				       clock));
+		 sa1100_pcmcia_mecr_bs(skt->speed_attr, clock));
     MECR_BSM_SET(mecr, sock,
-		 sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem,
-				       clock));
+		 sa1100_pcmcia_mecr_bs(skt->speed_mem, clock));
   }
 
   MECR = mecr;
-
 }
 
 /* sa1100_pcmcia_notifier()
@@ -1132,53 +883,371 @@
  *
  * Returns: 0 on success, -1 on error
  */
-static int sa1100_pcmcia_notifier(struct notifier_block *nb,
-				  unsigned long val, void *data){
+static int
+sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
   struct cpufreq_info *ci = data;
 
-  switch(val){
-  case CPUFREQ_MINMAX:
-
-    break;
-
+  switch (val) {
   case CPUFREQ_PRECHANGE:
-
-    if(ci->new_freq > ci->old_freq){
+    if (ci->new_freq > ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
 
   case CPUFREQ_POSTCHANGE:
-
-    if(ci->new_freq < ci->old_freq){
+    if (ci->new_freq < ci->old_freq) {
       DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
 	    __FUNCTION__,
 	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
 	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
       sa1100_pcmcia_update_mecr(ci->new_freq);
     }
-
     break;
-
-  default:
-    printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
-	   val);
-    return -1;
-
   }
 
   return 0;
-
 }
 
 static struct notifier_block sa1100_pcmcia_notifier_block = {
-  notifier_call: sa1100_pcmcia_notifier
+	notifier_call:	sa1100_pcmcia_notifier
 };
+#endif
+
+/* sa1100_register_pcmcia()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Register an SA1100 PCMCIA low level driver with the SA1100 core.
+ */
+int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
+{
+	struct pcmcia_init pcmcia_init;
+	struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
+	struct pcmcia_state_array state_array;
+	unsigned int i, clock;
+	unsigned long mecr;
+	int ret;
+
+	/*
+	 * Refuse to replace an existing driver.
+	 */
+	if (pcmcia_low_level)
+		return -EBUSY;
+
+	pcmcia_low_level = ops;
+
+	pcmcia_init.handler = sa1100_pcmcia_interrupt;
+	ret = ops->init(&pcmcia_init);
+	if (ret < 0) {
+		printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret);
+		if (ret == -1)
+			ret = -EIO;
+		goto out;
+	}
+
+	sa1100_pcmcia_socket_count = ret;
+
+	state_array.size  = ret;
+	state_array.state = state;
+
+	memset(state, 0, sizeof(state));
+
+	if (ops->socket_state(&state_array) < 0) {
+		printk(KERN_ERR "Unable to get PCMCIA status driver.\n");
+		ret = -EIO;
+		goto shutdown;
+	}
+
+	/*
+	 * We initialize the MECR to default values here, because we are
+	 * not guaranteed to see a SetIOMap operation at runtime.
+	 */
+	mecr = 0;
+
+	clock = cpufreq_get(0);
+
+	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+		struct pcmcia_irq_info irq_info;
+
+		if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) {
+			ret = -EBUSY;
+			goto out_err;
+		}
+
+		irq_info.sock = i;
+		irq_info.irq  = -1;
+		ret = ops->get_irq_info(&irq_info);
+		if (ret < 0)
+			printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret);
+
+		skt->irq        = irq_info.irq;
+		skt->k_state    = state[i];
+		skt->speed_io   = SA1100_PCMCIA_IO_ACCESS;
+		skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS;
+		skt->speed_mem  = SA1100_PCMCIA_5V_MEM_ACCESS;
+		skt->phys_attr  = _PCMCIAAttr(i);
+		skt->phys_mem   = _PCMCIAMem(i);
+		skt->virt_io    = ioremap(_PCMCIAIO(i), 0x10000);
+
+		if (skt->virt_io == NULL) {
+			ret = -ENOMEM;
+			goto out_err;
+		}
+
+		MECR_FAST_SET(mecr, i, 0);
+		MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock));
+		MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock));
+		MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock));
+	}
+
+	MECR = mecr;
+
+	/* Only advertise as many sockets as we can detect */
+	ret = register_ss_entry(sa1100_pcmcia_socket_count,
+				&sa1100_pcmcia_operations);
+	if (ret < 0) {
+		printk(KERN_ERR "Unable to register sockets\n");
+		goto out_err;
+	}
+
+	/*
+	 * Start the event poll timer.  It will reschedule by itself afterwards.
+	 */
+	sa1100_pcmcia_poll_event(0);
+	return 0;
+
+ out_err:
+	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+		iounmap(skt->virt_io);
+		skt->virt_io = NULL;
+		release_mem_region(_PCMCIA(i), PCMCIASp);
+	}
+
+ shutdown:
+	ops->shutdown();
+
+ out:
+	pcmcia_low_level = NULL;
+	return ret;
+}
+
+/* sa1100_unregister_pcmcia()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Unregister a previously registered pcmcia driver
+ */
+void sa1100_unregister_pcmcia(struct pcmcia_low_level *ops)
+{
+	int i;
+
+	if (!ops)
+		return;
+
+	if (ops != pcmcia_low_level) {
+		printk(KERN_DEBUG "PCMCIA: Trying to unregister wrong "
+			"low-level driver (%p != %p)", ops,
+			pcmcia_low_level);
+		return;
+	}
+
+	del_timer_sync(&poll_timer);
+
+	unregister_ss_entry(&sa1100_pcmcia_operations);
+
+	for (i = 0; i < sa1100_pcmcia_socket_count; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+
+		iounmap(skt->virt_io);
+		skt->virt_io = NULL;
+		
+		release_mem_region(_PCMCIA(i), PCMCIASp);
+	}
+
+	ops->shutdown();
+
+	flush_scheduled_tasks();
+
+	pcmcia_low_level = NULL;
+}
+
+/* sa1100_pcmcia_init()
+ * ^^^^^^^^^^^^^^^^^^^^
+ *
+ * This routine performs a basic sanity check to ensure that this
+ * kernel has been built with the appropriate board-specific low-level
+ * PCMCIA support, performs low-level PCMCIA initialization, registers
+ * this socket driver with Card Services, and then spawns the daemon
+ * thread which is the real workhorse of the socket driver.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int __init sa1100_pcmcia_init(void)
+{
+	servinfo_t info;
+	int ret, i;
+
+	printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
 
+	CardServices(GetCardServicesInfo, &info);
+	if (info.Revision != CS_RELEASE_CODE) {
+		printk(KERN_ERR "Card Services release codes do not match\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SA1100_PCMCIA_MAX_SOCK; i++) {
+		struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+
+		skt->speed_io   = SA1100_PCMCIA_IO_ACCESS;
+		skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS;
+		skt->speed_mem  = SA1100_PCMCIA_5V_MEM_ACCESS;
+	}
+
+#ifdef CONFIG_CPU_FREQ
+	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
+	if (ret < 0) {
+		printk(KERN_ERR "Unable to register CPU frequency change "
+			"notifier (%d)\n", ret);
+		return ret;
+	}
+#endif
+
+#ifdef CONFIG_SA1100_ADSBITSY
+	pcmcia_adsbitsy_init();
+#endif
+#ifdef CONFIG_SA1100_ASSABET
+	pcmcia_assabet_init();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+	pcmcia_badge4_init();
+#endif
+#ifdef CONFIG_SA1100_CERF
+	pcmcia_cerf_init();
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+	pcmcia_flexanet_init();
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+	pcmcia_freebird_init();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+	pcmcia_gcplus_init();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+	pcmcia_graphicsmaster_init();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	pcmcia_jornada720_init();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+	pcmcia_neponset_init();
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+	pcmcia_pangolin_init();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+	pcmcia_pfs_init();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	pcmcia_system3_init();
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	pcmcia_shannon_init();
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+	pcmcia_simpad_init();
+#endif
+#ifdef CONFIG_SA1100_STORK
+	pcmcia_stork_init();
+#endif
+#ifdef CONFIG_SA1100_XP860
+	pcmcia_xp860_init();
+#endif
+#ifdef CONFIG_SA1100_YOPY
+	pcmcia_yopy_init();
 #endif
 
+	return 0;
+}
+
+/* sa1100_pcmcia_exit()
+ * ^^^^^^^^^^^^^^^^^^^^
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit sa1100_pcmcia_exit(void)
+{
+#ifdef CONFIG_SA1100_ADSBITSY
+	pcmcia_adsbitsy_exit();
+#endif
+#ifdef CONFIG_SA1100_ASSABET
+	pcmcia_assabet_exit();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+	pcmcia_badge4_exit();
+#endif
+#ifdef CONFIG_SA1100_CERF
+	pcmcia_cerf_exit();
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+	pcmcia_flexanet_exit();
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+	pcmcia_freebird_exit();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+	pcmcia_gcplus_exit();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+	pcmcia_graphicsmaster_exit();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	pcmcia_jornada720_exit();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+	pcmcia_neponset_exit();
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+	pcmcia_pangolin_exit();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+	pcmcia_pfs_exit();
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	pcmcia_shannon_exit();
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+	pcmcia_simpad_exit();
+#endif
+#ifdef CONFIG_SA1100_STORK
+	pcmcia_stork_exit();
+#endif
+#ifdef CONFIG_SA1100_XP860
+	pcmcia_xp860_exit();
+#endif
+#ifdef CONFIG_SA1100_YOPY
+	pcmcia_yopy_exit();
+#endif
+
+	if (pcmcia_low_level) {
+		printk(KERN_ERR "PCMCIA: low level driver still registered\n");
+		sa1100_unregister_pcmcia(pcmcia_low_level);
+	}
+
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+#endif
+}
+
+MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller");
+MODULE_LICENSE("Dual MPL/GPL");
+
+module_init(sa1100_pcmcia_init);
+module_exit(sa1100_pcmcia_exit);
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_generic.h linux-2.5.6-pre3/drivers/pcmcia/sa1100_generic.h
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_generic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_generic.h	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,77 @@
+/*
+ * linux/include/asm/arch/pcmcia.h
+ *
+ * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
+ *
+ * This file contains definitions for the low-level SA-1100 kernel PCMCIA
+ * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
+ */
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
+ * has support for two. This shows up in lots of hardwired ways, such
+ * as the fact that MECR only has enough bits to configure two sockets.
+ * Since it's so entrenched in the hardware, limiting the software
+ * in this way doesn't seem too terrible.
+ */
+#define SA1100_PCMCIA_MAX_SOCK   (2)
+
+struct pcmcia_init {
+  void (*handler)(int irq, void *dev, struct pt_regs *regs);
+};
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+             bvd1: 1,
+             bvd2: 1,
+           wrprot: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+struct pcmcia_state_array {
+  unsigned int size;
+  struct pcmcia_state *state;
+};
+
+struct pcmcia_configure {
+  unsigned sock: 8,
+            vcc: 8,
+            vpp: 8,
+         output: 1,
+        speaker: 1,
+          reset: 1,
+            irq: 1;
+};
+
+struct pcmcia_irq_info {
+  unsigned int sock;
+  unsigned int irq;
+};
+
+struct pcmcia_low_level {
+  int (*init)(struct pcmcia_init *);
+  int (*shutdown)(void);
+  int (*socket_state)(struct pcmcia_state_array *);
+  int (*get_irq_info)(struct pcmcia_irq_info *);
+  int (*configure_socket)(const struct pcmcia_configure *);
+
+  /*
+   * Enable card status IRQs on (re-)initialisation.  This can
+   * be called at initialisation, power management event, or
+   * pcmcia event.
+   */
+  int (*socket_init)(int sock);
+
+  /*
+   * Disable card status IRQs and PCMCIA bus on suspend.
+   */
+  int (*socket_suspend)(int sock);
+};
+
+extern int sa1100_register_pcmcia(struct pcmcia_low_level *);
+extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *);
+
+#endif
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_graphicsclient.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_graphicsclient.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_graphicsclient.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_graphicsclient.c	Wed Mar  6 17:17:51 2002
@@ -14,10 +14,13 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
+
+#error This is broken!
 
 #define	S0_CD_IRQ		60				// Socket 0 Card Detect IRQ
 #define	S0_STS_IRQ		55				// Socket 0 PCMCIA IRQ
@@ -47,8 +50,9 @@
   irq = S0_CD_IRQ;
   res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
   if (res < 0) {
-	  printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq);
-	  return	-1;
+    printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	   __FUNCTION__, irq, res);
+    return res;
   }
 
   return 1;			// 1 PCMCIA Slot
@@ -106,7 +110,7 @@
 
   if(configure->sock>1) return -1;
 
-  save_flags_cli(flags);
+  local_irq_save(flags);
 
   switch (configure->vcc) {
   case 0:
@@ -126,7 +130,7 @@
   default:
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
-    restore_flags(flags);
+    local_irq_restore(flags);
     return -1;
   }
 
@@ -139,16 +143,44 @@
   *PCMCIA_Power |= ADS_CS_PR_A_RESET;
   mdelay(30);
 
-  restore_flags(flags);
+  local_irq_restore(flags);
 
   return 0;
 }
 
-struct pcmcia_low_level gcplus_pcmcia_ops = { 
-  gcplus_pcmcia_init,
-  gcplus_pcmcia_shutdown,
-  gcplus_pcmcia_socket_state,
-  gcplus_pcmcia_get_irq_info,
-  gcplus_pcmcia_configure_socket
+static int gcplus_pcmcia_socket_init(int sock)
+{
+  return 0;
+}
+
+static int gcplus_pcmcia_socket_suspend(int sock)
+{
+  return 0;
+}
+
+static struct pcmcia_low_level gcplus_pcmcia_ops = { 
+  init:			gcplus_pcmcia_init,
+  shutdown:		gcplus_pcmcia_shutdown,
+  socket_state:		gcplus_pcmcia_socket_state,
+  get_irq_info:		gcplus_pcmcia_get_irq_info,
+  configure_socket:	gcplus_pcmcia_configure_socket,
+
+  socket_init:		gcplus_pcmcia_socket_init,
+  socket_suspend:	gcplus_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_gcplus_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_gcplus())
+		ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_gcplus_exit(void)
+{
+	sa1100_unregister_pcmcia(&gcplus_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_graphicsmaster.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_graphicsmaster.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_graphicsmaster.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_graphicsmaster.c	Wed Mar  6 17:17:51 2002
@@ -10,11 +10,12 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
 {
@@ -26,190 +27,82 @@
   /* Disable Power 3.3V/5V for PCMCIA/CF */
   PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-  INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-			 (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    		 (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    		 (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    		 (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "GC Master CF (1) BVD1", NULL);
-
+  /* why? */
   MECR = 0x09430943;
 
-  return (return_val<0) ? -1 : 2;
-}
-
-static int graphicsmaster_pcmcia_shutdown(void)
-{
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-			   (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      		   (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      		   (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array)
-{
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+static int
+graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
 
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio |= GPIO_GPIO0 | GPIO_GPIO1;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio &= ~GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-	  gpio |= GPIO_GPIO0;
-      break;
-
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio |= GPIO_GPIO2 | GPIO_GPIO3;
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio &= ~GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
-	  gpio |= GPIO_GPIO2;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
+    case 0:	pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;	break;
+    case 33:	pa_dwr_set = GPIO_GPIO3;		break;
+    case 50:	pa_dwr_set = GPIO_GPIO2;		break;
     }
+  }
 
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
-  default:
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
+	   conf->vpp);
     return -1;
   }
 
-  PCCR = pccr;
-  PA_DWR = gpio;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
 
-  return 0;
+  return ret;
 }
 
-struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
-  graphicsmaster_pcmcia_init,
-  graphicsmaster_pcmcia_shutdown,
-  graphicsmaster_pcmcia_socket_state,
-  graphicsmaster_pcmcia_get_irq_info,
-  graphicsmaster_pcmcia_configure_socket
+static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
+  init:			graphicsmaster_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	graphicsmaster_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_graphicsmaster_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_graphicsmaster())
+		ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_graphicsmaster_exit(void)
+{
+	sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_h3600.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_h3600.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_h3600.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_h3600.c	Wed Mar  6 17:17:51 2002
@@ -6,142 +6,192 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
+	{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
+};
 
-static int h3600_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
-
-  /* Enable CF bus: */
-  set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON);
-  clr_h3600_egpio(EGPIO_H3600_OPT_RESET);
-
-  /* All those are inputs */
-  GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1);
-
-  /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
-
-  /* Register interrupts */
-  irq = IRQ_GPIO_H3600_PCMCIA_CD0;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_H3600_PCMCIA_CD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
-  if( res < 0 ) goto irq_err;
+static int h3600_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, res;
 
-  return 2;
+	/*
+	 * Set transition detect
+	 */
+	set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ0, IRQT_FALLING);
+	set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ1, IRQT_FALLING);
+
+	/*
+	 * Register interrupts
+	 */
+	for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			break;
+	}
+
+	if (res) {
+		printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+		       __FUNCTION__, irqs[i].irq, res);
+
+		while (i--)
+			free_irq(irqs[i].irq, NULL);
+	}
 
-irq_err:
-  printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
-  return -1;
+	return res ? res : 2;
 }
 
 static int h3600_pcmcia_shutdown(void)
 {
-  /* disable IRQs */
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL );
+	int i;
+
+	/*
+	 * disable IRQs
+	 */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
   
-  /* Disable CF bus: */
-  clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON);
-  set_h3600_egpio(EGPIO_H3600_OPT_RESET);
+	/* Disable CF bus: */
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
 
-  return 0;
+	return 0;
 }
 
-static int h3600_pcmcia_socket_state(struct pcmcia_state_array
-				       *state_array){
-  unsigned long levels;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
+static int
+h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
+{
+	unsigned long levels;
 
-  levels=GPLR;
+	if (state->size < 2)
+		return -1;
 
-  state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0;
-  state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0;
-  state_array->state[0].bvd1= 0;
-  state_array->state[0].bvd2= 0;
-  state_array->state[0].wrprot=0; /* Not available on H3600. */
-  state_array->state[0].vs_3v=0;
-  state_array->state[0].vs_Xv=0;
+	levels = GPLR;
 
-  state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0;
-  state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0;
-  state_array->state[1].bvd1=0;
-  state_array->state[1].bvd2=0;
-  state_array->state[1].wrprot=0; /* Not available on H3600. */
-  state_array->state[1].vs_3v=0;
-  state_array->state[1].vs_Xv=0;
+	state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
+	state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
+	state->state[0].bvd1 = 0;
+	state->state[0].bvd2 = 0;
+	state->state[0].wrprot = 0; /* Not available on H3600. */
+	state->state[0].vs_3v = 0;
+	state->state[0].vs_Xv = 0;
+
+	state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
+	state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
+	state->state[1].bvd1 = 0;
+	state->state[1].bvd2 = 0;
+	state->state[1].wrprot = 0; /* Not available on H3600. */
+	state->state[1].vs_3v = 0;
+	state->state[1].vs_Xv = 0;
 
-  return 1;
+	return 1;
 }
 
-static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch (info->sock) {
-  case 0:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0;
-    break;
-  case 1:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1;
-    break;
-  default:
-    return -1;
-  }
-  return 0;
+static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	switch (info->sock) {
+	case 0:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
+		break;
+	case 1:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
 }
 
-static int h3600_pcmcia_configure_socket(const struct pcmcia_configure
-					   *configure)
+static int
+h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long flags;
-
-  if(configure->sock>1) return -1;
+	if (conf->sock > 1)
+		return -1;
 
-  save_flags_cli(flags);
+	if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
+		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
+		       conf->vcc / 10, conf->vcc % 10);
+		return -1;
+	}
+
+	if (conf->reset)
+		set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
+	else
+		clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
 
-  switch (configure->vcc) {
-  case 0:
-    clr_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
+	/* Silently ignore Vpp, output enable, speaker enable. */
 
-  case 33:
-  case 50:
-    set_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
-
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    restore_flags(flags);
-    return -1;
-  }
+	return 0;
+}
 
-  if (configure->reset)
-    set_h3600_egpio(EGPIO_H3600_CARD_RESET);
-  else
-    clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
+static int h3600_pcmcia_socket_init(int sock)
+{
+	/* Enable CF bus: */
+	set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(10*HZ / 1000);
+
+	switch (sock) {
+	case 0:
+		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE);
+		break;
+	case 1:
+		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE);
+		break;
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	return 0;
+}
 
-  restore_flags(flags);
+static int h3600_pcmcia_socket_suspend(int sock)
+{
+	switch (sock) {
+	case 0:
+		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE);
+		break;
+	case 1:
+		set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE);
+		break;
+	}
+
+	/*
+	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
+	 * the generic PCMCIA layer to deal with the idea of two sockets
+	 * on one bus.  We rely on the cs.c behaviour shutting down
+	 * socket 0 then socket 1.
+	 */
+	if (sock == 1) {
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+		/* hmm, does this suck power? */
+		set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+	}
 
-  return 0;
+	return 0;
 }
 
 struct pcmcia_low_level h3600_pcmcia_ops = { 
-  h3600_pcmcia_init,
-  h3600_pcmcia_shutdown,
-  h3600_pcmcia_socket_state,
-  h3600_pcmcia_get_irq_info,
-  h3600_pcmcia_configure_socket
+	init:			h3600_pcmcia_init,
+	shutdown:		h3600_pcmcia_shutdown,
+	socket_state:		h3600_pcmcia_socket_state,
+	get_irq_info:		h3600_pcmcia_get_irq_info,
+	configure_socket:	h3600_pcmcia_configure_socket,
+
+	socket_init:		h3600_pcmcia_socket_init,
+	socket_suspend:		h3600_pcmcia_socket_suspend,
 };
 
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_jornada720.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_jornada720.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_jornada720.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_jornada720.c	Wed Mar  6 17:17:51 2002
@@ -6,21 +6,24 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
 #define SOCKET0_POWER   GPIO_GPIO0
 #define SOCKET0_3V      GPIO_GPIO2
 #define SOCKET1_POWER   (GPIO_GPIO1 | GPIO_GPIO3)
-#define SOCKET1_3V   GPIO_GPIO3
+#warning *** Does SOCKET1_3V actually do anything?
+#define SOCKET1_3V	GPIO_GPIO3
 
 static int jornada720_pcmcia_init(struct pcmcia_init *init)
 {
-  int return_val=0;
-
+  /*
+   * What is all this crap for?
+   */
   GRER |= 0x00000002;
   /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
   PA_DDR = 0;
@@ -38,178 +41,82 @@
   PC_SDR = 0;
   PC_SSR = 0;
 
-  INTPOL1 |=
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Jornada720 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Jornada720 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Jornada720 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Jornada720 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
-
-static int jornada720_pcmcia_shutdown(void)
-{
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &=
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int jornada720_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array)
-{
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-  status=PCSR;
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-  return return_val;
-}
-
-static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure)
+static int
+jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+  unsigned int pa_dwr_mask, pa_dwr_set;
+  int ret;
 
 printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
-	       configure->sock, configure->vcc, configure->vpp);
-  switch(configure->sock){
+	       conf->sock, conf->vcc, conf->vpp);
+
+  switch (conf->sock) {
   case 0:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio&=~(SOCKET0_POWER | SOCKET0_3V);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio |= SOCKET0_POWER | SOCKET0_3V;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER;
-      break;
+    pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-    switch(configure->vpp){
-    case 0:
-      break;
-    case 50:
-	printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-      break;
-    case 120:
-	printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-      break;
-    default:
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-	return -1;
+    case 0:	pa_dwr_set = 0;					break;
+    case 33:	pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;	break;
+    case 50:	pa_dwr_set = SOCKET0_POWER;			break;
     }
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      gpio &= ~(SOCKET1_POWER);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio |= SOCKET1_POWER;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER;
-      break;
+    pa_dwr_mask = SOCKET1_POWER;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
+    case 0:	pa_dwr_set = 0;					break;
+    case 33:	pa_dwr_set = SOCKET1_POWER;			break;
+    case 50:	pa_dwr_set = SOCKET1_POWER;			break;
     }
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
     break;
-  default:
+  }
+
+  if (conf->vpp != conf->vcc && conf->vpp != 0) {
+    printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
+	   __FUNCTION__, conf->vpp);
     return -1;
   }
-  PCCR = pccr;
-  PA_DWR = gpio;
-  return 0;
+
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    locla_irq_restore(flags);
+  }
+
+  return ret;
 }
 
-struct pcmcia_low_level jornada720_pcmcia_ops = {
-  jornada720_pcmcia_init,
-  jornada720_pcmcia_shutdown,
-  jornada720_pcmcia_socket_state,
-  jornada720_pcmcia_get_irq_info,
-  jornada720_pcmcia_configure_socket
+static struct pcmcia_low_level jornada720_pcmcia_ops = {
+  init:			jornada720_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	jornada720_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_jornada720_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_jornada720())
+		ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_jornada720_exit(void)
+{
+	sa1100_unregister_pcmcia(&jornada720_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_neponset.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_neponset.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_neponset.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_neponset.c	Wed Mar  6 17:17:51 2002
@@ -1,249 +1,145 @@
 /*
- * drivers/pcmcia/sa1100_neponset.c
+ * linux/drivers/pcmcia/sa1100_neponset.c
  *
  * Neponset PCMCIA specific routines
- *
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 #include <asm/arch/assabet.h>
+#include <asm/hardware/sa1111.h>
 
-static int neponset_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
-
-  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
-  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-  
-  /* MAX1600 to standby mode: */
-  PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-  NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
-
-  INTPOL1 |= 
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Neponset PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "Neponset CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Neponset PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "Neponset CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
-static int neponset_pcmcia_shutdown(void){
+static int neponset_pcmcia_init(struct pcmcia_init *init)
+{
+	/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+	PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= 
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
+	/* MAX1600 to standby mode: */
+	PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+	NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
 
-  return 0;
+	return sa1111_pcmcia_init(init);
 }
 
-static int neponset_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
+static int
+neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	unsigned int ncr_mask, pa_dwr_mask;
+	unsigned int ncr_set, pa_dwr_set;
+	int ret;
+
+	/* Neponset uses the Maxim MAX1600, with the following connections:
+
+	 *   MAX1600      Neponset
+	 *
+	 *    A0VCC        SA-1111 GPIO A<1>
+	 *    A1VCC        SA-1111 GPIO A<0>
+	 *    A0VPP        CPLD NCR A0VPP
+	 *    A1VPP        CPLD NCR A1VPP
+	 *    B0VCC        SA-1111 GPIO A<2>
+	 *    B1VCC        SA-1111 GPIO A<3>
+	 *    B0VPP        ground (slot B is CF)
+	 *    B1VPP        ground (slot B is CF)
+	 *
+	 *     VX          VCC (5V)
+	 *     VY          VCC3_3 (3.3V)
+	 *     12INA       12V
+	 *     12INB       ground (slot B is CF)
+	 *
+	 * The MAX1600 CODE pin is tied to ground, placing the device in 
+	 * "Standard Intel code" mode. Refer to the Maxim data sheet for
+	 * the corresponding truth table.
+	 */
+
+	switch (conf->sock) {
+	case 0:
+		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+		ncr_mask = NCR_A0VPP | NCR_A1VPP;
+
+		switch (conf->vcc) {
+		default:
+		case 0:		pa_dwr_set = 0;			break;
+		case 33:	pa_dwr_set = GPIO_GPIO1;	break;
+		case 50:	pa_dwr_set = GPIO_GPIO0;	break;
+		}
+
+		switch (conf->vpp) {
+		case 0:		ncr_set = 0;			break;
+		case 120:	ncr_set = NCR_A1VPP;		break;
+		default:
+			if (conf->vpp == conf->vcc)
+				ncr_set = NCR_A0VPP;
+			else {
+				printk(KERN_ERR "%s(): unrecognized VPP %u\n",
+				       __FUNCTION__, conf->vpp);
+				return -1;
+			}
+		}
+		break;
+
+	case 1:
+		pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+		ncr_mask = 0;
+		ncr_set = 0;
+
+		switch (conf->vcc) {
+		default:
+		case 0:		pa_dwr_set = 0;			break;
+		case 33:	pa_dwr_set = GPIO_GPIO2;	break;
+		case 50:	pa_dwr_set = GPIO_GPIO3;	break;
+		}
+
+		if (conf->vpp != conf->vcc && conf->vpp != 0) {
+			printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+			       __FUNCTION__, conf->vpp);
+			return -1;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	ret = sa1111_pcmcia_configure_socket(conf);
+	if (ret == 0) {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
+		PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+		local_irq_restore(flags);
+	}
 
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
+	return 0;
 }
 
-static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+static struct pcmcia_low_level neponset_pcmcia_ops = {
+	init:			neponset_pcmcia_init,
+	shutdown:		sa1111_pcmcia_shutdown,
+	socket_state:		sa1111_pcmcia_socket_state,
+	get_irq_info:		sa1111_pcmcia_get_irq_info,
+	configure_socket:	neponset_pcmcia_configure_socket,
 
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
+	socket_init:		sa1111_pcmcia_socket_init,
+	socket_suspend:		sa1111_pcmcia_socket_suspend,
+};
 
-  return 0;
-}
+int __init pcmcia_neponset_init(void)
+{
+	int ret = -ENODEV;
 
-static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR;
-
-  /* Neponset uses the Maxim MAX1600, with the following connections:
-   *
-   *   MAX1600      Neponset
-   *
-   *    A0VCC        SA-1111 GPIO A<1>
-   *    A1VCC        SA-1111 GPIO A<0>
-   *    A0VPP        CPLD NCR A0VPP
-   *    A1VPP        CPLD NCR A1VPP
-   *    B0VCC        SA-1111 GPIO A<2>
-   *    B1VCC        SA-1111 GPIO A<3>
-   *    B0VPP        ground (slot B is CF)
-   *    B1VPP        ground (slot B is CF)
-   *
-   *     VX          VCC (5V)
-   *     VY          VCC3_3 (3.3V)
-   *     12INA       12V
-   *     12INB       ground (slot B is CF)
-   *
-   * The MAX1600 CODE pin is tied to ground, placing the device in 
-   * "Standard Intel code" mode. Refer to the Maxim data sheet for
-   * the corresponding truth table.
-   */
-
-  switch(configure->sock){
-  case 0:
-    
-    switch(configure->vcc){
-    case 0:
-      pccr=(pccr & ~PCCR_S0_FLT);
-      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    switch(configure->vpp){
-    case 0:
-      ncr&=~(NCR_A0VPP | NCR_A1VPP);
-      break;
-
-    case 120:
-      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
-      break;
-
-    default:
-      if(configure->vpp == configure->vcc)
-	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
-      else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
-	return -1;
-      }
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
-    break;
-
-  case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr=(pccr & ~PCCR_S1_FLT);
-      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
-      break;
-
-    default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
-    }
-
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
-      return -1;
-    }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
-    break;
-
-  default:
-    return -1;
-  }
-
-  PCCR = pccr;
-  NCR_0 = ncr;
-  PA_DWR = gpio;
+	if (machine_is_assabet() && machine_has_neponset())
+		ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
 
-  return 0;
+	return ret;
 }
 
-struct pcmcia_low_level neponset_pcmcia_ops = { 
-  neponset_pcmcia_init,
-  neponset_pcmcia_shutdown,
-  neponset_pcmcia_socket_state,
-  neponset_pcmcia_get_irq_info,
-  neponset_pcmcia_configure_socket
-};
-
+void __exit pcmcia_neponset_exit(void)
+{
+	sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_pangolin.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_pangolin.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_pangolin.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_pangolin.c	Wed Mar  6 17:17:51 2002
@@ -4,48 +4,45 @@
  * PCMCIA implementation routines for Pangolin
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 static int pangolin_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
+  int res;
 
-  /* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */
-  GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ);
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
-  /* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
-  GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
   /* Enable PCMCIA bus: */
   GPCR = GPIO_PCMCIA_BUS_ON;
-#else
-  /* set GPIO pin GPIO_PCMCIA_RESET as output */
-  GPDR |= GPIO_PCMCIA_RESET;
 #endif
+
   /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE );
+  set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
+  set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING);
 
   /* Register interrupts */
-  irq = IRQ_PCMCIA_CD;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL );
-  if( res < 0 ) goto irq_err;
-
-  /* There's only one slot, but it's "Slot 1": */
-  return 2;
+  res = request_irq(IRQ_PCMCIA_CD, init->handler, SA_INTERRUPT,
+		    "PCMCIA_CD", NULL);
+  if (res >= 0)
+    /* There's only one slot, but it's "Slot 1": */
+    return 2;
 
 irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
-  return -1;
+  printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	 __FUNCTION__, IRQ_PCMCIA_CD, res);
+
+  return res;
 }
 
 static int pangolin_pcmcia_shutdown(void)
 {
   /* disable IRQs */
-  free_irq( IRQ_PCMCIA_CD, NULL );
+  free_irq(IRQ_PCMCIA_CD, NULL);
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
     /* Disable PCMCIA bus: */
     GPSR = GPIO_PCMCIA_BUS_ON;
@@ -105,7 +102,7 @@
 #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
   if(configure->sock==0) return 0;
 #endif
-  save_flags_cli(flags);
+  local_irq_save(flags);
 
   /* Murphy: BUS_ON different from POWER ? */
 
@@ -129,7 +126,7 @@
   default:
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
-    restore_flags(flags);
+    local_irq_restore(flags);
     return -1;
   }
 #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
@@ -143,15 +140,47 @@
   }
 #endif
   /* Silently ignore Vpp, output enable, speaker enable. */
-  restore_flags(flags);
+  local_irq_restore(flags);
   return 0;
 }
 
-struct pcmcia_low_level pangolin_pcmcia_ops = { 
-  pangolin_pcmcia_init,
-  pangolin_pcmcia_shutdown,
-  pangolin_pcmcia_socket_state,
-  pangolin_pcmcia_get_irq_info,
-  pangolin_pcmcia_configure_socket
+static int pangolin_pcmcia_socket_init(int sock)
+{
+  if (sock == 1)
+    set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE);
+  return 0;
+}
+
+static int pangolin_pcmcia_socket_suspend(int sock)
+{
+  if (sock == 1)
+    set_irq_type(IRQ_PCmCIA_CD, IRQT_NOEDGE);
+  return 0;
+}
+
+static struct pcmcia_low_level pangolin_pcmcia_ops = { 
+  init:			pangolin_pcmcia_init,
+  shutdown:		pangolin_pcmcia_shutdown,
+  socket_state:		pangolin_pcmcia_socket_state,
+  get_irq_info:		pangolin_pcmcia_get_irq_info,
+  configure_socket:	pangolin_pcmcia_configure_socket,
+
+  socket_init:		pangolin_pcmcia_socket_init,
+  socket_suspend,	pangolin_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_pangolin_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_pangolin())
+		ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_pangolin_exit(void)
+{
+	sa1100_unregister_pcmcia(&pangolin_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_pfs168.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_pfs168.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_pfs168.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_pfs168.c	Wed Mar  6 17:17:51 2002
@@ -7,121 +7,31 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/delay.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
 
-static int pfs168_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
 
+static int pfs168_pcmcia_init(struct pcmcia_init *init)
+{
   /* TPS2211 to standby mode: */
   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
   /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 
-  INTPOL1 |=
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "PFS168 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "PFS168 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "PFS168 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "PFS168 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
-
-static int pfs168_pcmcia_shutdown(void){
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &=
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int pfs168_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0,
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
-}
-
-static int pfs168_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
+  return sa1111_pcmcia_init(init);
 }
 
-static int pfs168_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, gpio=PA_DWR;
+static int
+pfs168_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+  unsigned int pa_dwr_mask = 0, pa_dwr_set = 0;
+  int ret;
 
   /* PFS168 uses the Texas Instruments TPS2211 for PCMCIA (socket 0) voltage control only,
    * with the following connections:
@@ -135,103 +45,100 @@
    *
    */
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S0_FLT);
-      gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
-      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
-
-    case 50:
-      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
-      gpio = (gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO0;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO1;	break;
     }
 
-    switch(configure->vpp){
+    switch (conf->vpp) {
     case 0:
-      gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
       break;
 
     case 120:
-      printk(KERN_ERR "%s(): PFS-168 does not support Vpp %uV\n", __FUNCTION__,
-	     configure->vpp/10);
+      printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n",
+	     __FUNCTION__, conf->vpp / 10);
       return -1;
       break;
 
     default:
-      if(configure->vpp == configure->vcc)
-        gpio = (gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
+      if (conf->vpp == conf->vcc)
+        pa_dwr_set |= GPIO_GPIO3;
       else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
+	printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__,
+	       conf->vpp);
 	return -1;
       }
     }
-
-    pccr = (configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-
-    PA_DWR = gpio;
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      pccr = (pccr & ~PCCR_S1_FLT);
-      break;
+    pa_dwr_mask = 0;
+    pa_dwr_set = 0;
 
+    switch (conf->vcc) {
+    case 0:
     case 33:
-      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
       break;
 
     case 50:
-      printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support Vcc %uV\n", __FUNCTION__,
-	     configure->vcc/10);
+      printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n",
+	     __FUNCTION__, conf->vcc / 10);
       return -1;
-      break;
 
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
+      printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__,
+	     conf->vcc);
       return -1;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CompactFlash socket does not support Vpp %uV\n", __FUNCTION__,
-	     configure->vpp/10);
+    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+      printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n"
+	     __FUNCTION__, conf->vpp / 10);
       return -1;
     }
-
-    pccr = (configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-
     break;
-
-  default:
-    return -1;
   }
 
-  PCCR = pccr;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    local_irq_restore(flags);
+  }
 
   return 0;
 }
 
-struct pcmcia_low_level pfs168_pcmcia_ops = {
-  pfs168_pcmcia_init,
-  pfs168_pcmcia_shutdown,
-  pfs168_pcmcia_socket_state,
-  pfs168_pcmcia_get_irq_info,
-  pfs168_pcmcia_configure_socket
+static struct pcmcia_low_level pfs168_pcmcia_ops = {
+  init:			pfs168_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	pfs168_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
+
+int __init pcmcia_pfs168_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_pfs168())
+		ret = sa1100_register_pcmcia(&pfs168_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_pfs168_exit(void)
+{
+	sa1100_unregister_pcmcia(&pfs168_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_shannon.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_shannon.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_shannon.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_shannon.c	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,177 @@
+/*
+ * drivers/pcmcia/sa1100_shannon.c
+ *
+ * PCMCIA implementation routines for Shannon
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/shannon.h>
+#include <asm/irq.h>
+#include "sa1100_generic.h"
+
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
+	{ SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
+};
+
+static int shannon_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, res;
+
+	/* All those are inputs */
+	GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
+		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
+	GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
+		  SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
+
+	/* Set transition detect */
+	set_irq_type(SHANNON_IRQ_GPIO_RDY_0, IRQT_FALLING);
+	set_irq_type(SHANNON_IRQ_GPIO_RDY_1, IRQT_FALLING);
+
+	/* Register interrupts */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			goto irq_err;
+	}
+
+	return 2;
+
+ irq_err:
+	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+		__FUNCTION__, irqs[i].irq, res);
+
+	while (i--)
+		free_irq(irqs[i].irq, NULL);
+
+	return res;
+}
+
+static int shannon_pcmcia_shutdown(void)
+{
+	int i;
+
+	/* disable IRQs */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_state(struct pcmcia_state_array *state_array)
+{
+	unsigned long levels;
+
+	memset(state_array->state, 0,
+	       state_array->size * sizeof(struct pcmcia_state));
+
+	levels = GPLR;
+
+	state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
+	state_array->state[0].ready  = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
+	state_array->state[0].wrprot = 0; /* Not available on Shannon. */
+	state_array->state[0].bvd1 = 1; 
+	state_array->state[0].bvd2 = 1; 
+	state_array->state[0].vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+	state_array->state[0].vs_Xv  = 0;
+
+	state_array->state[1].detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1;
+	state_array->state[1].ready  = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0;
+	state_array->state[1].wrprot = 0; /* Not available on Shannon. */
+	state_array->state[1].bvd1 = 1; 
+	state_array->state[1].bvd2 = 1; 
+	state_array->state[1].vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
+	state_array->state[1].vs_Xv  = 0;
+
+	return 1;
+}
+
+static int shannon_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	if (info->sock == 0)
+		info->irq = SHANNON_IRQ_GPIO_RDY_0;
+	else if (info->sock == 1)
+		info->irq = SHANNON_IRQ_GPIO_RDY_1;
+	else return -1;
+	
+	return 0;
+}
+
+static int shannon_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+
+	switch (configure->vcc) {
+	case 0:	/* power off */
+		printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n");
+		break;
+	case 50:
+		printk(KERN_WARNING __FUNCTION__"(): CS asked for 5V, applying 3.3V..\n");
+	case 33:
+		break;
+	default:
+		printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n",
+		       configure->vcc);
+		return -1;
+	}
+
+	printk(KERN_WARNING __FUNCTION__"(): Warning, Can't perform reset\n");
+	
+	/* Silently ignore Vpp, output enable, speaker enable. */
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_init(int sock)
+{
+	if (sock == 0)
+		set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_BOTHEDGE);
+	else if (sock == 1)
+		set_irq_Type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_BOTHEDGE);
+
+	return 0;
+}
+
+static int shannon_pcmcia_socket_suspend(int sock)
+{
+	if (sock == 0)
+		set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_NOEDGE);
+	else if (sock == 1)
+		set_irq_type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_NOEDGE);
+
+	return 0;
+}
+
+static struct pcmcia_low_level shannon_pcmcia_ops = {
+	init:			shannon_pcmcia_init,
+	shutdown:		shannon_pcmcia_shutdown,
+	socket_state:		shannon_pcmcia_socket_state,
+	get_irq_info:		shannon_pcmcia_get_irq_info,
+	configure_socket:	shannon_pcmcia_configure_socket,
+
+	socket_init:		shannon_pcmcia_socket_init,
+	socket_suspend:		shannon_pcmcia_socket_suspend,
+};
+
+int __init pcmcia_shannon_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_shannon())
+		ret = sa1100_register_pcmcia(&shannon_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_shannon_exit(void)
+{
+	sa1100_unregister_pcmcia(&shannon_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_simpad.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_simpad.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_simpad.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_simpad.c	Wed Mar  6 17:17:51 2002
@@ -6,10 +6,11 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
  
 extern long get_cs3_shadow(void);
 extern void set_cs3_bit(int value); 
@@ -19,9 +20,6 @@
 static int simpad_pcmcia_init(struct pcmcia_init *init){
   int irq, res;
 
-  /* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */
-  GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ);
-  
   set_cs3_bit(PCMCIA_RESET);
   clear_cs3_bit(PCMCIA_BUFF_DIS);
   clear_cs3_bit(PCMCIA_RESET);
@@ -29,8 +27,8 @@
   clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
 
   /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
+  set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE );
+  set_irq_type( IRQ_GPIO_CF_IRQ, IRQT_FALLING );
 
   /* Register interrupts */
   irq = IRQ_GPIO_CF_CD;
@@ -41,8 +39,9 @@
   return 2;
 
 irq_err:
-  printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq );
-  return -1;
+  printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	 __FUNCTION__, irq, res);
+  return res;
 }
 
 static int simpad_pcmcia_shutdown(void)
@@ -112,7 +111,7 @@
 
   if(configure->sock==0) return 0;
 
-  save_flags_cli(flags);
+  local_irq_save(flags);
 
   /* Murphy: see table of MIC2562a-1 */
 
@@ -135,22 +134,51 @@
     printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 	   configure->vcc);
     clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
-    restore_flags(flags);
+    local_irq_restore(flags);
     return -1;
   }
 
   /* Silently ignore Vpp, output enable, speaker enable. */
 
-  restore_flags(flags);
+  local_irq_restore(flags);
 
   return 0;
 }
 
-struct pcmcia_low_level simpad_pcmcia_ops = { 
-  simpad_pcmcia_init,
-  simpad_pcmcia_shutdown,
-  simpad_pcmcia_socket_state,
-  simpad_pcmcia_get_irq_info,
-  simpad_pcmcia_configure_socket
+static int simpad_pcmcia_socket_init(int sock)
+{
+  set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE);
+  return 0;
+}
+
+static int simpad_pcmcia_socket_suspend(int sock)
+{
+  set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE);
+  return 0;
+}
+
+static struct pcmcia_low_level simpad_pcmcia_ops = { 
+  init:			simpad_pcmcia_init,
+  shutdown:		simpad_pcmcia_shutdown,
+  socket_state:		simpad_pcmcia_socket_state,
+  get_irq_info:		simpad_pcmcia_get_irq_info,
+  configure_socket:	simpad_pcmcia_configure_socket,
+
+  socket_init:		simpad_pcmcia_socket_init,
+  socket_suspend:	simpad_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_simpad_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_simpad())
+		ret = sa1100_register_pcmcia(&simpad_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_simpad_exit(void)
+{
+	sa1100_unregister_pcmcia(&simpad_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_stork.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_stork.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_stork.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_stork.c	Wed Mar  6 17:17:51 2002
@@ -18,8 +18,6 @@
  * PCMCIA implementation routines for stork
  *
  */
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -28,50 +26,58 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 static int debug = 0;
 
-static struct pcmcia_init sa1100_stork_pcmcia_init;
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" },
+	{ IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" },
+};
 
 static int stork_pcmcia_init(struct pcmcia_init *init)
 {
-        int irq, res;
-        printk("in stork_pcmcia_init\n");
-
-        sa1100_stork_pcmcia_init = *init;
-
-        /* Enable CF bus: */
-        storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+	int irq, res;
 
-        /* All those are inputs */
-	GPDR &= ~(GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT | GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY);
+	printk("in stork_pcmcia_init\n");
 
 	/* Set transition detect */
-	set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_CARD_DETECT | GPIO_STORK_PCMCIA_B_CARD_DETECT, GPIO_BOTH_EDGES );
-        set_GPIO_IRQ_edge( GPIO_STORK_PCMCIA_A_RDY| GPIO_STORK_PCMCIA_B_RDY, GPIO_FALLING_EDGE );
+	set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_RDY, IRQT_FALLING);
+	set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_RDY, IRQT_FALLING);
 
 	/* Register interrupts */
-	irq = IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT;
-	res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
-	if( res < 0 ) goto irq_err;
-	irq = IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT;
-	res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
-	if( res < 0 ) goto irq_err;
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			goto irq_err;
+	}
 
         return 2;
 
  irq_err:
-        printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
-        return -1;
+        printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	       __FUNCTION__, irq, res);
+
+	while (i--)
+		free_irq(irqs[i].irq, NULL);
+
+        return res;
 }
 
 static int stork_pcmcia_shutdown(void)
 {
+	int i;
+
         printk(__FUNCTION__ "\n");
+
         /* disable IRQs */
-        free_irq( IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, NULL );
-        free_irq( IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, NULL );
+        for (i = 0; i < ARRAY_SIZE(irqs); i++)
+        	free_irq(irqs[i].irq, NULL);
   
         /* Disable CF bus: */
         storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
@@ -140,7 +146,7 @@
 	printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", 
                        card, configure->vcc, configure->vpp, configure->reset);
 
-	save_flags_cli(flags);
+	local_irq_save(flags);
 
         if (card == 0) {
     	    DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT;
@@ -174,7 +180,7 @@
 	default:
 		printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
 		       configure->vcc);
-		restore_flags(flags);
+		local_irq_restore(flags);
 		return -1;
 	}
 
@@ -183,7 +189,7 @@
 	else
                 storkClearLatchB(RESET);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 
         /* silently ignore vpp and speaker enables. */
 
@@ -192,11 +198,57 @@
         return 0;
 }
 
-struct pcmcia_low_level stork_pcmcia_ops = { 
-        stork_pcmcia_init,
-        stork_pcmcia_shutdown,
-        stork_pcmcia_socket_state,
-        stork_pcmcia_get_irq_info,
-        stork_pcmcia_configure_socket
+static int stork_pcmcia_socket_init(int sock)
+{
+        storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+
+        if (sock == 0)
+		set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_BOTHEDGE);
+        else if (sock == 1)
+		set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_BOTHEDGE);
+
+	return 0;
+}
+
+static int stork_pcmcia_socket_suspend(int sock)
+{
+        if (sock == 0)
+		set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_NOEDGE);
+        else if (sock == 1) {
+		set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_NOEDGE);
+
+		/*
+		 * Hack!
+		 */
+	        storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON);
+	}
+
+	return 0;
+}
+
+static struct pcmcia_low_level stork_pcmcia_ops = { 
+	init:			stork_pcmcia_init,
+	shutdown:		stork_pcmcia_shutdown,
+	socket_state:		stork_pcmcia_socket_state,
+	get_irq_info:		stork_pcmcia_get_irq_info,
+	configure_socket:	stork_pcmcia_configure_socket,
+
+	socket_init:		stork_pcmcia_socket_init,
+	socket_suspend:		stork_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_stork_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_stork())
+		ret = sa1100_register_pcmcia(&stork_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_stork_exit(void)
+{
+	sa1100_unregister_pcmcia(&stork_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_system3.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_system3.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_system3.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_system3.c	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,131 @@
+/*
+ * drivers/pcmcia/sa1100_system3.c
+ *
+ * PT Diagital Board PCMCIA specific routines
+ *
+ * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
+ *
+ * $Id: sa1100_system3.c,v 1.1.4.2 2002/02/25 13:56:45 seletz Exp $
+ *
+ * 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.
+ *
+ * $Log: sa1100_system3.c,v $
+ * Revision 1.1.4.2  2002/02/25 13:56:45  seletz
+ * - more cleanups
+ * - setup interrupts for CF card only ATM
+ *
+ * Revision 1.1.4.1  2002/02/14 02:23:27  seletz
+ * - 2.5.2-rmk6 PCMCIA changes
+ *
+ * Revision 1.1.2.1  2002/02/13 23:49:33  seletz
+ * - added from 2.4.16-rmk2
+ * - cleanups
+ *
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
+
+#define DEBUG 0
+
+#ifdef DEBUG
+#	define DPRINTK( x, args... )	printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args  );
+#else
+#	define DPRINTK( x, args... )	/* nix */
+#endif
+
+int system3_pcmcia_init(struct pcmcia_init *init)
+{
+	/* Don't need no CD and BVD* interrupts */
+	return 2;
+}
+
+int system3_pcmcia_shutdown(void)
+{
+	return 0;
+}
+
+int system3_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	if (!conf)
+		return -1;
+
+	/* only CF ATM */
+	if (conf->sock == 0)
+		return -1;
+
+	return sa1111_pcmcia_configure_socket( conf );
+}
+
+static int system3_pcmcia_socket_state(struct pcmcia_state_array
+		*state)
+{
+	unsigned long	status		= 0;
+
+	if(state->size<2) return -1;
+
+	memset(state->state, 0,
+			(state->size)*sizeof(struct pcmcia_state));
+
+	status=PCSR;
+
+#if 0 /* PCMCIA socket not yet connected */
+	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
+	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
+	state->state[0].bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
+	state->state[0].bvd2   = 1;
+	state->state[0].wrprot = status & PCSR_S0_WP     ? 1 : 0;
+	state->state[0].vs_3v  = 1;
+	state->state[0].vs_Xv  = 0;
+#endif
+
+	state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1;
+	state->state[1].ready  = status & PCSR_S1_READY  ? 1 : 0;
+	state->state[1].bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
+	state->state[1].bvd2   = 1;
+	state->state[1].wrprot = status & PCSR_S1_WP     ? 1 : 0;
+	state->state[1].vs_3v  = 1;
+	state->state[1].vs_Xv  = 0;
+
+	DPRINTK( "PCSR=0x%08lx, S1_RDY_nIREQ=%d\n", status,
+			state->state[1].ready );
+
+	return 1;
+}
+
+struct pcmcia_low_level system3_pcmcia_ops = {
+	init:				system3_pcmcia_init,
+	shutdown:			system3_pcmcia_shutdown,
+	socket_state:		system3_pcmcia_socket_state,
+	get_irq_info:		sa1111_pcmcia_get_irq_info,
+	configure_socket:	system3_pcmcia_configure_socket,
+
+	socket_init:		sa1111_pcmcia_socket_init,
+	socket_suspend:		sa1111_pcmcia_socket_suspend,
+};
+
+int __init pcmcia_system3_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_pt_system3())
+		ret = sa1100_register_pcmcia(&system3_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_system3_exit(void)
+{
+	sa1100_unregister_pcmcia(&system3_pcmcia_ops);
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_xp860.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_xp860.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_xp860.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_xp860.c	Wed Mar  6 17:17:51 2002
@@ -7,128 +7,46 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 #define NCR_A0VPP	(1<<16)
 #define NCR_A1VPP	(1<<17)
 
-static int xp860_pcmcia_init(struct pcmcia_init *init){
-  int return_val=0;
-
+static int xp860_pcmcia_init(struct pcmcia_init *init)
+{
   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
   
   /* MAX1600 to standby mode: */
   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+
+#error Consider the following comment
+  /*
+   * 1- Please move GPDR initialisation  where it is interrupt or preemption
+   *    safe (like from xp860_map_io).
+   * 2- The GPCR line is bogus i.e. it will simply have absolutely no effect.
+   *    Please see its definition in the SA1110 manual.
+   * 3- Please do not use NCR_* values!
+   */
   GPDR |= (NCR_A0VPP | NCR_A1VPP);
   GPCR &= ~(NCR_A0VPP | NCR_A1VPP);
 
-  INTPOL1 |= 
-    (1 << (S0_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S1_READY_NINT - SA1111_IRQ(32))) |
-    (1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-    (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-    (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
-
-  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
-			  "XP860 PCMCIA (0) CD", NULL);
-  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
-			  "XP860 CF (1) CD", NULL);
-  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "XP860 PCMCIA (0) BVD1", NULL);
-  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
-			  "XP860 CF (1) BVD1", NULL);
-
-  return (return_val<0) ? -1 : 2;
-}
-
-static int xp860_pcmcia_shutdown(void){
-
-  free_irq(S0_CD_VALID, NULL);
-  free_irq(S1_CD_VALID, NULL);
-  free_irq(S0_BVD1_STSCHG, NULL);
-  free_irq(S1_BVD1_STSCHG, NULL);
-
-  INTPOL1 &= 
-    ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S1_CD_VALID - SA1111_IRQ(32))) |
-      (1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
-      (1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
-
-  return 0;
-}
-
-static int xp860_pcmcia_socket_state(struct pcmcia_state_array
-					*state_array){
-  unsigned long status;
-  int return_val=1;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
-
-  status=PCSR;
-
-  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
-
-  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
-
-  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
-
-  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
-
-  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
-
-  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
-
-  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
-
-  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
-
-  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
-
-  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
-
-  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
-
-  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
-
-  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
-
-  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
-
-  return return_val;
+  return sa1111_pcmcia_init(init);
 }
 
-static int xp860_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch(info->sock){
-  case 0:
-    info->irq=S0_READY_NINT;
-    break;
-
-  case 1:
-    info->irq=S1_READY_NINT;
-    break;
-
-  default:
-    return -1;
-  }
-
-  return 0;
-}
-
-static int xp860_pcmcia_configure_socket(const struct pcmcia_configure
-					    *configure){
-  unsigned long pccr=PCCR, ncr=GPLR, gpio=PA_DWR;
-
+static int
+xp860_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+  unsigned int gpio_mask, pa_dwr_mask;
+  unsigned int gpio_set, pa_dwr_set;
+  int ret;
 
   /* Neponset uses the Maxim MAX1600, with the following connections:
+#warning ^^^ This isn't a neponset!
    *
    *   MAX1600      Neponset
    *
@@ -151,105 +69,90 @@
    * the corresponding truth table.
    */
 
-  switch(configure->sock){
+  switch (conf->sock) {
   case 0:
-    
-    switch(configure->vcc){
-    case 0:
-      gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S0_PSE);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S0_PSE);
-      gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
-      break;
+    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
+    gpio_mask = NCR_A0VPP | NCR_A1VPP;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO1;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO0;	break;
     }
 
-    switch(configure->vpp){
-    case 0:
-      ncr&=~(NCR_A0VPP | NCR_A1VPP);
-      break;
-
-    case 120:
-      ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
-      break;
+    switch (conf->vpp) {
+    case 0:	gpio_set = 0;			break;
+    case 120:	gpio_set = NCR_A1VPP;		break;
 
     default:
-      if(configure->vpp == configure->vcc)
-	ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
+      if (conf->vpp == conf->vcc)
+	gpio_set = NCR_A0VPP;
       else {
-	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
-	       configure->vpp);
+	printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+	       __FUNCTION__, conf->vpp);
 	return -1;
       }
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
-    pccr=(configure->output)?(pccr | PCCR_S0_FLT):(pccr & ~PCCR_S0_FLT);
-
     break;
 
   case 1:
-    switch(configure->vcc){
-    case 0:
-      gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
-      break;
-
-    case 33:
-      pccr=(pccr & ~PCCR_S1_PSE);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
-      break;
-
-    case 50:
-      pccr=(pccr | PCCR_S1_PSE);
-      gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
-      break;
+    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
+    gpio_mask = 0;
+    gpio_set = 0;
 
+    switch (conf->vcc) {
     default:
-      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	     configure->vcc);
-      return -1;
+    case 0:	pa_dwr_set = 0;			break;
+    case 33:	pa_dwr_set = GPIO_GPIO2;	break;
+    case 50:	pa_dwr_set = GPIO_GPIO3;	break;
     }
 
-    if(configure->vpp!=configure->vcc && configure->vpp!=0){
-      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
-	     configure->vpp);
+    if (conf->vpp != conf->vcc && conf->vpp != 0) {
+      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+	     __FUNCTION__, conf->vpp);
       return -1;
     }
-
-    pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
-    pccr=(configure->output)?(pccr | PCCR_S1_FLT):(pccr & ~PCCR_S1_FLT);
-
     break;
-
-  default:
-    return -1;
   }
 
-  PCCR = pccr;
-  ncr &= NCR_A0VPP|NCR_A1VPP;
-  GPSR = ncr;
-  GPCR = (~ncr)&(NCR_A0VPP|NCR_A1VPP);
-  PA_DWR = gpio;
+  ret = sa1111_pcmcia_configure_socket(conf);
+  if (ret == 0) {
+    unsigned long flags;
+
+    local_irq_save(flags);
+    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+    GPSR = gpio_set;
+    GPCR = gpio_set ^ gpio_mask;
+    local_irq_restore(flags);
+  }
 
-  return 0;
+  return ret;
 }
 
-struct pcmcia_low_level xp860_pcmcia_ops = { 
-  xp860_pcmcia_init,
-  xp860_pcmcia_shutdown,
-  xp860_pcmcia_socket_state,
-  xp860_pcmcia_get_irq_info,
-  xp860_pcmcia_configure_socket
+static struct pcmcia_low_level xp860_pcmcia_ops = { 
+  init:			xp860_pcmcia_init,
+  shutdown:		sa1111_pcmcia_shutdown,
+  socket_state:		sa1111_pcmcia_socket_state,
+  get_irq_info:		sa1111_pcmcia_get_irq_info,
+  configure_socket:	xp860_pcmcia_configure_socket,
+
+  socket_init:		sa1111_pcmcia_socket_init,
+  socket_suspend:	sa1111_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_xp860_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_xp860())
+		ret = sa1100_register_pcmcia(&xp860_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_xp860_exit(void)
+{
+	sa1100_unregister_pcmcia(&xp860_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1100_yopy.c linux-2.5.6-pre3/drivers/pcmcia/sa1100_yopy.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1100_yopy.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1100_yopy.c	Wed Mar  6 17:17:51 2002
@@ -6,10 +6,11 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
 
 static inline void pcmcia_power(int on) {
@@ -23,45 +24,53 @@
 	yopy_gpio_set(GPIO_CF_RESET, reset);
 }
 
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_CF_CD,   "CF_CD"   },
+	{ IRQ_CF_BVD2, "CF_BVD2" },
+	{ IRQ_CF_BVD1, "CF_BVD1" },
+};
+
 static int yopy_pcmcia_init(struct pcmcia_init *init)
 {
-	int irq, res;
+	int i, res;
 
 	pcmcia_power(0);
 	pcmcia_reset(1);
 
-	/* All those are inputs */
-	GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
-	GAFR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IREQ);
-
 	/* Set transition detect */
-	set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1,
-			   GPIO_BOTH_EDGES );
-	set_GPIO_IRQ_edge( GPIO_CF_IREQ, GPIO_FALLING_EDGE );
+	set_irq_type(IRQ_CF_IREQ, IRQT_FALLING);
 
 	/* Register interrupts */
-	irq = IRQ_CF_CD;
-	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_CD", NULL);
-	if (res < 0) goto irq_err;
-	irq = IRQ_CF_BVD2;
-	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL);
-	if (res < 0) goto irq_err;
-	irq = IRQ_CF_BVD1;
-	res = request_irq(irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL);
-	if (res < 0) goto irq_err;
+	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			goto irq_err;
+	}
 
 	return 1;
-irq_err:
-	printk(KERN_ERR "%s: Request for IRQ %d failed\n", __FUNCTION__, irq);
-	return -1;
+
+ irq_err:
+	printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
+	       __FUNCTION__, irqs[i].irq, res);
+
+	while (i--)
+		free_irq(irqs[i].irq, NULL);
+
+	return res;
 }
 
 static int yopy_pcmcia_shutdown(void)
 {
+	int i;
+
 	/* disable IRQs */
-	free_irq( IRQ_CF_CD, NULL );
-	free_irq( IRQ_CF_BVD2, NULL );
-	free_irq( IRQ_CF_BVD1, NULL );
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
 
 	/* Disable CF */
 	pcmcia_reset(1);
@@ -109,7 +118,7 @@
 		return -1;
 
 	switch (configure->vcc) {
-	case 0:	/* power off */;
+	case 0:	/* power off */
 		pcmcia_power(0);
 		break;
 	case 50:
@@ -130,10 +139,49 @@
 	return 0;
 }
 
-struct pcmcia_low_level yopy_pcmcia_ops = {
-	yopy_pcmcia_init,
-	yopy_pcmcia_shutdown,
-	yopy_pcmcia_socket_state,
-	yopy_pcmcia_get_irq_info,
-	yopy_pcmcia_configure_socket
+static int yopy_pcmcia_socket_init(int sock)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
+
+	return 0;
+}
+
+static int yopy_pcmcia_socket_suspend(int sock)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		set_irq_type(irqs[i].irq, IRQT_NOEDGE);
+
+	return 0;
+}
+
+static struct pcmcia_low_level yopy_pcmcia_ops = {
+	init:			yopy_pcmcia_init,
+	shutdown:		yopy_pcmcia_shutdown,
+	socket_state:		yopy_pcmcia_socket_state,
+	get_irq_info:		yopy_pcmcia_get_irq_info,
+	configure_socket:	yopy_pcmcia_configure_socket,
+
+	socket_init:		yopy_pcmcia_socket_init,
+	socket_suspend:		yopy_pcmcia_socket_suspend,
 };
+
+int __init pcmcia_yopy_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_yopy())
+		ret = sa1100_register_pcmcia(&yopy_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_yopy_exit(void)
+{
+	sa1100_unregister_pcmcia(&yopy_pcmcia_ops);
+}
+
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1111_generic.c linux-2.5.6-pre3/drivers/pcmcia/sa1111_generic.c
--- linux-2.5.6-pre2/drivers/pcmcia/sa1111_generic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1111_generic.c	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,180 @@
+/*
+ * linux/drivers/pcmcia/sa1100_sa1111.c
+ *
+ * We implement the generic parts of a SA1111 PCMCIA driver.  This
+ * basically means we handle everything except controlling the
+ * power.  Power is machine specific...
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/irq.h>
+
+#include "sa1100_generic.h"
+#include "sa1111_generic.h"
+
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ S0_CD_VALID,    "SA1111 PCMCIA card detect" },
+	{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
+	{ S1_CD_VALID,    "SA1111 CF card detect"     },
+	{ S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
+};
+
+int sa1111_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, ret;
+
+	if (!request_mem_region(_PCCR, 512, "PCMCIA"))
+		return -1;
+
+	for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
+		set_irq_type(irqs[i].irq, IRQT_FALLING);
+		ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (ret)
+			break;
+	}
+
+	if (i < ARRAY_SIZE(irqs)) {
+		printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n",
+			irqs[i].irq, ret);
+		while (i--)
+			free_irq(irqs[i].irq, NULL);
+
+		release_mem_region(_PCCR, 16);
+	}
+
+	return ret ? -1 : 2;
+}
+
+int sa1111_pcmcia_shutdown(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
+
+	release_mem_region(_PCCR, 512);
+
+	return 0;
+}
+
+int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state)
+{
+	unsigned long status;
+
+	if (state->size < 2)
+		return -1;
+
+	status = PCSR;
+
+	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
+	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
+	state->state[0].bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
+	state->state[0].bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
+	state->state[0].wrprot = status & PCSR_S0_WP     ? 1 : 0;
+	state->state[0].vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
+	state->state[0].vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
+
+	state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1;
+	state->state[1].ready  = status & PCSR_S1_READY  ? 1 : 0;
+	state->state[1].bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
+	state->state[1].bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
+	state->state[1].wrprot = status & PCSR_S1_WP     ? 1 : 0;
+	state->state[1].vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
+	state->state[1].vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
+
+	return 1;
+}
+
+int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	int ret = 0;
+
+	switch (info->sock) {
+	case 0:	info->irq = S0_READY_NINT;	break;
+	case 1: info->irq = S1_READY_NINT;	break;
+	default: ret = 1;
+	}
+
+	return ret;
+}
+
+int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+{
+	unsigned int rst, flt, wait, pse, irq, pccr_mask;
+	unsigned long flags;
+
+	switch (conf->sock) {
+	case 0:
+		rst = PCCR_S0_RST;
+		flt = PCCR_S0_FLT;
+		wait = PCCR_S0_PWAITEN;
+		pse = PCCR_S0_PSE;
+		irq = S0_READY_NINT;
+		break;
+
+	case 1:
+		rst = PCCR_S1_RST;
+		flt = PCCR_S1_FLT;
+		wait = PCCR_S1_PWAITEN;
+		pse = PCCR_S1_PSE;
+		irq = S1_READY_NINT;
+		break;
+
+	default:
+		return -1;
+	}
+
+	switch (conf->vcc) {
+	case 0:
+		pccr_mask = 0;
+		break;
+
+	case 33:
+		pccr_mask = wait;
+		break;
+
+	case 50:
+		pccr_mask = pse | wait;
+		break;
+
+	default:
+		printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n",
+			conf->vcc);
+		return -1;
+	}
+
+	if (conf->reset)
+		pccr_mask |= rst;
+
+	if (conf->output)
+		pccr_mask |= flt;
+
+	local_irq_save(flags);
+	PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask;
+	local_irq_restore(flags);
+
+	if (conf->irq)
+		enable_irq(irq);
+	else
+		disable_irq(irq);
+
+	return 0;
+}
+
+int sa1111_pcmcia_socket_init(int sock)
+{
+	return 0;
+}
+
+int sa1111_pcmcia_socket_suspend(int sock)
+{
+	return 0;
+}
diff -urN linux-2.5.6-pre2/drivers/pcmcia/sa1111_generic.h linux-2.5.6-pre3/drivers/pcmcia/sa1111_generic.h
--- linux-2.5.6-pre2/drivers/pcmcia/sa1111_generic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre3/drivers/pcmcia/sa1111_generic.h	Wed Mar  6 17:17:51 2002
@@ -0,0 +1,7 @@
+extern int sa1111_pcmcia_init(struct pcmcia_init *);
+extern int sa1111_pcmcia_shutdown(void);
+extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *);
+extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *);
+extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *);
+extern int sa1111_pcmcia_socket_init(int);
+extern int sa1111_pcmcia_socket_suspend(int);
diff -urN linux-2.5.6-pre2/drivers/pnp/quirks.c linux-2.5.6-pre3/drivers/pnp/quirks.c
--- linux-2.5.6-pre2/drivers/pnp/quirks.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/drivers/pnp/quirks.c	Wed Mar  6 17:17:51 2002
@@ -18,6 +18,10 @@
 #include <linux/isapnp.h>
 #include <linux/string.h>
 
+#if 0
+#define ISAPNP_DEBUG
+#endif
+
 static void __init quirk_awe32_resources(struct pci_dev *dev)
 {
 	struct isapnp_port *port, *port2, *port3;
@@ -139,8 +143,10 @@
 	while (isapnp_fixups[i].vendor != 0) {
 		if ((isapnp_fixups[i].vendor == dev->vendor) &&
 		    (isapnp_fixups[i].device == dev->device)) {
+#ifdef ISAPNP_DEBUG
 			printk(KERN_DEBUG "isapnp: Calling quirk for %02x:%02x\n",
 			       dev->bus->number, dev->devfn);
+#endif
 			isapnp_fixups[i].quirk_function(dev);
 		}
 		i++;
diff -urN linux-2.5.6-pre2/drivers/s390/block/dasd.c linux-2.5.6-pre3/drivers/s390/block/dasd.c
--- linux-2.5.6-pre2/drivers/s390/block/dasd.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/s390/block/dasd.c	Wed Mar  6 17:17:51 2002
@@ -2477,7 +2477,7 @@
 			rc = -EFAULT;
 		} else {
 			if ( bsz >= device->sizes.bp_block )
-				rc = blk_ioctl (inp->i_rdev, no, data);
+				rc = blk_ioctl (inp->i_bdev, no, data);
 			else
 				rc = -EINVAL; 
 		}
@@ -2493,7 +2493,7 @@
 	case BLKPG:
 	case BLKELVGET:
 	case BLKELVSET:
-		return blk_ioctl (inp->i_rdev, no, data);
+		return blk_ioctl (inp->i_bdev, no, data);
 		break;
 	default:{
 
diff -urN linux-2.5.6-pre2/drivers/s390/char/tape34xx.c linux-2.5.6-pre3/drivers/s390/char/tape34xx.c
--- linux-2.5.6-pre2/drivers/s390/char/tape34xx.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/drivers/s390/char/tape34xx.c	Wed Mar  6 17:17:51 2002
@@ -2152,7 +2152,7 @@
       	    tape34xx_error_recovery_HWBUG(ti,21);
 	    return;
 	case 0x3490:
-	    // Resetting event recieved. Since the driver does not support resetting event recovery
+	    // Resetting event received. Since the driver does not support resetting event recovery
 	    // (which has to be handled by the I/O Layer), we'll report and retry our command.
 	    tape34xx_error_recovery_do_retry(ti);
 	    return;
@@ -2219,7 +2219,7 @@
 	    return;
 	case 0x3490:
 	    // Global status intercept. We have to reissue the command.
-	    PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
+	    PRINT_WARN("An global status intercept was received, which will be recovered.\n");
 	    tape34xx_error_recovery_do_retry(ti);
 	    return;
 	}
diff -urN linux-2.5.6-pre2/drivers/s390/misc/chandev.c linux-2.5.6-pre3/drivers/s390/misc/chandev.c
--- linux-2.5.6-pre2/drivers/s390/misc/chandev.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/s390/misc/chandev.c	Wed Mar  6 17:17:51 2002
@@ -2021,7 +2021,7 @@
 		/* This is required because the device can go & come back */
                 /* even before we realize it is gone owing to the waits in our kernel threads */
 		/* & the device will be marked as not owned but its status will be good */
-                /* & an attempt to accidently reprobe it may be done. */ 
+                /* & an attempt to accidentally reprobe it may be done. */ 
 		remove:
 		chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
 		
diff -urN linux-2.5.6-pre2/drivers/sbus/char/jsflash.c linux-2.5.6-pre3/drivers/sbus/char/jsflash.c
--- linux-2.5.6-pre2/drivers/sbus/char/jsflash.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/sbus/char/jsflash.c	Wed Mar  6 17:17:51 2002
@@ -468,7 +468,7 @@
 	case BLKROSET:
 	case BLKROGET:
 	case BLKSSZGET:
-		return blk_ioctl(inode->i_rdev, cmd, arg);
+		return blk_ioctl(inode->i_bdev, cmd, arg);
 #endif
 
 	/* case BLKFLSBUF: */	/* Program, then read, what happens? Stale? */
diff -urN linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c linux-2.5.6-pre3/drivers/scsi/3w-xxxx.c
--- linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/scsi/3w-xxxx.c	Wed Mar  6 17:17:51 2002
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2001 3ware Inc.
+   Copyright (C) 1999-2002 3ware Inc.
 
    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -106,17 +106,41 @@
                  Add entire aen code string list.
    1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
                  Fix get_param for specific units.
+   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
+                 Fix tw_aen_drain_queue() to display useful info at init.
+                 Set tw_host->max_id for 12 port cards.
+                 Add ioctl support for raw command packet post from userspace
+                 with sglist fragments (parameter and io).
+   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
+                 last sector ioctl.
+   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
+                 driver initialization.
+                 Improved handling of PCI aborts.
+   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
+                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
+   1.02.00.015 - Re-write raw command post with data ioctl method.
+                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
+                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
+                 Replace io_request_lock with host_lock for kernel 2.5
+                 Set max_cmd_len to 16 for 3dm for kernel 2.5
+   1.02.00.016 - Set host->max_sectors back up to 256.
+   1.02.00.017 - Modified pci parity error handling/clearing from config space
+                 during initialization.
+   1.02.00.018 - Better handling of request sense opcode and sense information
+                 for failed commands.  Add tw_decode_sense().
+                 Replace all mdelay()'s with scsi_sleep().
+   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
+                 some SMP systems.
+   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
+                 pci_alloc/free_consistent().
 */
 
-#error Please convert me to Documentation/DMA-mapping.txt
-
 #include <linux/module.h>
 
 MODULE_AUTHOR ("3ware Inc.");
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/time.h>
@@ -148,14 +172,17 @@
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
 
 /* Notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block tw_notifier = {
-  tw_halt, NULL, 0
+	tw_halt, NULL, 0
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.010";
+char *tw_driver_version="1.02.00.020";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -166,6 +193,7 @@
 {
 	TW_Param *param;
 	unsigned short aen;
+	int error = 0;
 
 	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
@@ -184,12 +212,15 @@
 			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
 				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
 			} else {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
+				if (aen != 0x0) 
+					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
 			}
-		} else
+		} else {
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
+		}
 	}
-	tw_dev->aen_count++;
+	if (aen != 0x0) 
+		tw_dev->aen_count++;
 
 	/* Now queue the code */
 	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
@@ -205,8 +236,18 @@
 			tw_dev->aen_head = tw_dev->aen_head + 1;
 		}
 	}
-	tw_dev->state[request_id] = TW_S_COMPLETED;
-	tw_state_request_finish(tw_dev, request_id);
+
+	if (aen != TW_AEN_QUEUE_EMPTY) {
+		error = tw_aen_read_queue(tw_dev, request_id);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+		}
+	} else {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+	}
 
 	return 0;
 } /* End tw_aen_complete() */
@@ -237,10 +278,11 @@
 	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
-	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
+	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
 		return 1;
 	}
+	tw_clear_attention_interrupt(tw_dev);
 
 	/* Initialize command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -288,7 +330,7 @@
 	do {
 		/* Post command packet */
 		outl(command_que_value, command_que_addr);
-    
+
 		/* Now poll for completion */
 		for (i=0;i<imax;i++) {
 			mdelay(5);
@@ -311,8 +353,7 @@
 				if (command_packet->status != 0) {
 					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
 						/* Bad response */
-						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+						tw_decode_sense(tw_dev, request_id, 0);
 						return 1;
 					} else {
 						/* We know this is a 3w-1x00, and doesn't support aen's */
@@ -326,7 +367,7 @@
 				queue = 0;
 				switch (aen_code) {
 					case TW_AEN_QUEUE_EMPTY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");
+						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
 						if (first_reset != 1) {
 							continue;
 						} else {
@@ -334,51 +375,28 @@
 						}
 						break;
 					case TW_AEN_SOFT_RESET:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");
 						if (first_reset == 0) {
 							first_reset = 1;
 						} else {
+							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+							tw_dev->aen_count++;
 							queue = 1;
 						}
 						break;
-					case TW_AEN_DEGRADED_MIRROR:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");
-						queue = 1;
-						break;
-					case TW_AEN_CONTROLLER_ERROR:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");
-						queue = 1;
-						break;
-					case TW_AEN_REBUILD_FAIL:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");
-						queue = 1;
-						break;
-					case TW_AEN_REBUILD_DONE:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");
-						queue = 1;
-						break;
-					case TW_AEN_QUEUE_FULL:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");
-						queue = 1;
-						break;
-					case TW_AEN_APORT_TIMEOUT:
-						printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_DRIVE_ERROR:
-						printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_SMART_FAIL:
-						printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_SBUF_FAIL:
-						printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n");
-						queue = 1;
-						break;
 					default:
-						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);
+						if (aen == 0x0ff) {
+							printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
+						} else {
+							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
+								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
+								} else {
+									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+								}
+							} else
+								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
+						}
+						tw_dev->aen_count++;
 						queue = 1;
 				}
 
@@ -488,40 +506,44 @@
 	return 0;
 } /* End tw_aen_read_queue() */
 
-/* This function will allocate memory and check if it is 16 d-word aligned */
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
+/* This function will allocate memory */
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
 {
-	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
+	int i;
+	dma_addr_t dma_handle;
+	u32 *cpu_addr = NULL;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
 
-	if (!virt_addr) {
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-		return 1;
-	}
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
+		if (cpu_addr == NULL) {
+			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+			return 1;
+		}
 
-	if ((u32)virt_addr % TW_ALIGNMENT) {
-		kfree(virt_addr);
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
-		return 1;
-	}
+		if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+			return 1;
+		}
 
-	switch(which) {
-	case 0:
-		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 1:
-		tw_dev->alignment_virtual_address[request_id] = virt_addr;
-		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 2:
-		tw_dev->bounce_buffer[request_id] = virt_addr;
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
-		return 1;
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_virtual_address[i] = cpu_addr;
+			tw_dev->command_packet_physical_address[i] = dma_handle;
+			memset(tw_dev->command_packet_virtual_address[i], 0, size);
+			break;
+		case 1:
+			tw_dev->alignment_virtual_address[i] = cpu_addr;
+			tw_dev->alignment_physical_address[i] = dma_handle;
+			memset(tw_dev->alignment_virtual_address[i], 0, size);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+			return 1;
+		}
 	}
+
 	return 0;
 } /* End tw_allocate_memory() */
 
@@ -548,8 +570,10 @@
 	status_reg_addr = tw_dev->registers.status_reg_addr;
 	status_reg_value = inl(status_reg_addr);
 
-	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
+	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
+		tw_decode_bits(tw_dev, status_reg_value);
 		return 1;
+	}
 
 	return 0;
 } /* End tw_check_errors() */
@@ -614,37 +638,62 @@
 	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
 	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
 	case TW_STATUS_PCI_PARITY_ERROR:
-		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
+		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
-		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
 		break;
 	case TW_STATUS_MICROCONTROLLER_ERROR:
 		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
 		break;
+	case TW_STATUS_PCI_ABORT:
+		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+		break;
   }
 } /* End tw_decode_bits() */
 
-/* This function will print readable messages from flags and status values */
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
+/* This function will return valid sense buffer information for failed cmds */
+void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
 {
-	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
-	switch (status) {
-	case 0xc7:
-		switch (flags) {
-		case 0x1b: 
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
-			break;
-		case 0x51:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
-			break;
-		default:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+	int i, found=0;
+	TW_Command *command;
+
+        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
+	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
+
+	/* Attempt to return intelligent sense information */
+	if (fill_sense) {
+		if ((command->status == 0xc7) || (command->status == 0xcb)) {
+			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
+				if (command->flags == tw_sense_table[i][0]) {
+					found=1;
+
+					/* Valid bit and 'current errors' */
+					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
+
+					/* Sense key */
+					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
+
+					/* Additional sense length */
+					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
+
+					/* Additional sense code */
+					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
+
+					/* Additional sense code qualifier */
+					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
+
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
+			}
 		}
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+		/* If no table match, error so we get a reset */
+		if (found == 0)
+			tw_dev->srb[request_id]->result = (DID_RESET << 16);
 	}
-} /* End tw_decode_error() */
+} /* End tw_decode_sense() */
 
 /* This function will disable interrupts on the controller */  
 void tw_disable_interrupts(TW_Device_Extension *tw_dev) 
@@ -691,11 +740,22 @@
 	u32 control_reg_value, control_reg_addr;
 
 	control_reg_addr = tw_dev->registers.control_reg_addr;
+	control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS |
+			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT);
+	outl(control_reg_value, control_reg_addr);
+} /* End tw_enable_interrupts() */
+
+/* This function will enable interrupts on the controller */
+void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev)
+{
+	u32 control_reg_value, control_reg_addr;
+
+	control_reg_addr = tw_dev->registers.control_reg_addr;
 	control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
 			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
 			     TW_CONTROL_ENABLE_INTERRUPTS);
 	outl(control_reg_value, control_reg_addr);
-} /* End tw_enable_interrupts() */
+} /* End tw_enable_and_clear_interrupts() */
 
 /* This function will find and initialize all cards */
 int tw_findcards(Scsi_Host_Template *tw_host) 
@@ -716,6 +776,13 @@
 		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
 			if (pci_enable_device(tw_pci_dev))
 				continue;
+
+			/* We only need 32-bit addressing for 5,6,7xxx cards */
+			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
+				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
+				continue;
+			}
+
 			/* Prepare temporary device extension */
 			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
 			if (tw_dev == NULL) {
@@ -724,6 +791,9 @@
 			}
 			memset(tw_dev, 0, sizeof(TW_Device_Extension));
 
+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+
 			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
@@ -738,8 +808,6 @@
 			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
 			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
 			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
-			/* Save pci_dev struct to device extension */
-			tw_dev->tw_pci_dev = tw_pci_dev;
 
 			/* Check for errors and clear them */
 			status_reg_value = inl(tw_dev->registers.status_reg_addr);
@@ -763,14 +831,14 @@
 			  
 				error = tw_aen_drain_queue(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
 					tries++;
 					continue;
 				}
 
 				/* Check for controller errors */
 				if (tw_check_errors(tw_dev)) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
 					tries++;
 					continue;
 				}
@@ -778,7 +846,7 @@
 				/* Empty the response queue */
 				error = tw_empty_response_que(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
 					tries++;
 					continue;
 				}
@@ -788,7 +856,7 @@
 			}
 
 			if (tries >= TW_MAX_RESET_TRIES) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -818,7 +886,7 @@
 
 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -827,29 +895,28 @@
 
 			/* Calculate max cmds per lun, and setup queues */
 			if (tw_dev->num_units > 0) {
-				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
-					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
-				} else {
-					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_LENGTH - 1;
-					tw_dev->free_wrap = TW_Q_LENGTH - 1;
-				}
+				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_LENGTH - 1;
+				tw_dev->free_wrap = TW_Q_LENGTH - 1;
 			}
 
-		/* Register the card with the kernel SCSI layer */
+			/* Register the card with the kernel SCSI layer */
 			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
 			if (host == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
 			}
 
+			/* Set max target id's */
+			host->max_id = TW_MAX_UNITS;
+
+			/* Set max cdb size in bytes */
+			host->max_cmd_len = 16;
+
 			/* Set max sectors per io */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
 			host->max_sectors = TW_MAX_SECTORS;
@@ -874,7 +941,7 @@
 				tw_device_extension_count = numcards;
 				tw_dev2->host = host;
 			} else { 
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
@@ -924,15 +991,10 @@
 	/* Free command packet and generic buffer memory */
 	for (i=0;i<TW_Q_LENGTH;i++) {
 		if (tw_dev->command_packet_virtual_address[i]) 
-			kfree(tw_dev->command_packet_virtual_address[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
 
 		if (tw_dev->alignment_virtual_address[i])
-			kfree(tw_dev->alignment_virtual_address[i]);
-
-	}
-	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-		if (tw_dev->bounce_buffer[i])
-			kfree(tw_dev->bounce_buffer[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
 	}
 } /* End tw_free_device_extension() */
 
@@ -1015,8 +1077,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break;	/* Response was okay, so we exit */
@@ -1028,57 +1089,33 @@
 /* This function will initialize the fields of a device extension */
 int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i, imax;
+	int i, error=0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
-	imax = TW_Q_LENGTH;
 
-	for (i=0; i<imax; i++) {
-		/* Initialize command packet buffers */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
-		if (tw_dev->command_packet_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
-    
-		/* Initialize generic buffer */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
-		if (tw_dev->alignment_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
+	/* Initialize command packet buffers */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
+		return 1;
+	}
 
-		tw_dev->free_queue[i] = i;
-		tw_dev->state[i] = TW_S_INITIAL;
-		tw_dev->ioctl_size[i] = 0;
-		tw_dev->aen_queue[i] = 0;
+	/* Initialize generic buffer */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
+		return 1;
 	}
 
-	for (i=0;i<TW_MAX_UNITS;i++) {
-		tw_dev->is_unit_present[i] = 0;
-		tw_dev->is_raid_five[i] = 0;
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
 	}
 
-	tw_dev->num_units = 0;
-	tw_dev->num_aborts = 0;
-	tw_dev->num_resets = 0;
-	tw_dev->posted_request_count = 0;
-	tw_dev->max_posted_request_count = 0;
-	tw_dev->max_sgl_entries = 0;
-	tw_dev->sgl_entries = 0;
-	tw_dev->host = NULL;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
-	tw_dev->aen_head = 0;
-	tw_dev->aen_tail = 0;
-	tw_dev->sector_count = 0;
-	tw_dev->max_sector_count = 0;
-	tw_dev->aen_count = 0;
-	tw_dev->num_raid_five = 0;
 	spin_lock_init(&tw_dev->tw_lock);
-	tw_dev->flags = 0;
+
 	return 0;
 } /* End tw_initialize_device_extension() */
 
@@ -1089,14 +1126,13 @@
 	unsigned char request_id = 0;
 	TW_Command *command_packet;
 	TW_Param *param;
-	int i, j, imax, num_units = 0, num_raid_five = 0;
+	int i, imax, num_units = 0;
 	u32 status_reg_addr, status_reg_value;
 	u32 command_que_addr, command_que_value;
 	u32 response_que_addr;
 	TW_Response_Queue response_queue;
 	u32 param_value;
 	unsigned char *is_unit_present;
-	unsigned char *raid_level;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
 
@@ -1168,8 +1204,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			found = 1;
@@ -1205,109 +1240,6 @@
 		return 1;
 	}
 
-	/* Find raid 5 arrays */
-	for (j=0;j<TW_MAX_UNITS;j++) {
-		if (tw_dev->is_unit_present[j] == 0)
-			continue;
-		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-		if (command_packet == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(command_packet, 0, sizeof(TW_Sector));
-		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
-		command_packet->byte0.sgl_offset  = 2;
-		command_packet->size              = 4;
-		command_packet->request_id        = request_id;
-		command_packet->byte3.unit        = 0;
-		command_packet->byte3.host_id     = 0;
-		command_packet->status            = 0;
-		command_packet->flags             = 0;
-		command_packet->byte6.block_count = 1;
-
-		/* Now setup the param */
-		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-		memset(param, 0, sizeof(TW_Sector));
-		param->table_id = 0x300+j; /* unit summary table */
-		param->parameter_id = 0x6; /* unit descriptor */
-		param->parameter_size_bytes = 0xc;
-		param_value = tw_dev->alignment_physical_address[request_id];
-		if (param_value == 0) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
-			return 1;
-		}
-
-		command_packet->byte8.param.sgl[0].address = param_value;
-		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-		/* Post the command packet to the board */
-		command_que_value = tw_dev->command_packet_physical_address[request_id];
-		if (command_que_value == 0) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
-			return 1;
-		}
-		outl(command_que_value, command_que_addr);
-
-		/* Poll for completion */
-		imax = TW_POLL_MAX_RETRIES;
-		for(i=0; i<imax; i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value);
-				return 1;
-			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-				if (request_id != 0) {
-					/* unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-					return 1;
-				}
-				if (command_packet->status != 0) {
-					/* bad response */
-					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					return 1;
-				}
-				found = 1;
-				break;
-			}
-		}
-		if (found == 0) {
-			/* response never received */
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
-			return 1;
-		}
-
-		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-		raid_level = (unsigned char *)&(param->data[1]);
-		if (*raid_level == 5) {
-			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
-			tw_dev->is_raid_five[j] = 1;
-			num_raid_five++;
-		}
-	}
-	tw_dev->num_raid_five = num_raid_five;
-
-	/* Now allocate raid5 bounce buffers */
-	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2);
-			if (tw_dev->bounce_buffer[i] == NULL) {
-				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
-				return 1;
-			}
-			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS);
-		}
-	}
-  
 	return 0;
 } /* End tw_initialize_units() */
 
@@ -1332,13 +1264,18 @@
 
 	if (tw_dev->tw_pci_dev->irq == irq) {
 		spin_lock(&tw_dev->tw_lock);
-		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
 
 		/* Read the registers */
 		status_reg_addr = tw_dev->registers.status_reg_addr;
 		response_que_addr = tw_dev->registers.response_que_addr;
 		status_reg_value = inl(status_reg_addr);
 
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value);
+		}
+
 		/* Check which interrupt */
 		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
 			do_host_interrupt=1;
@@ -1403,17 +1340,18 @@
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 				error = 0;
 				if (command_packet->status != 0) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					error = 1;
+					/* Bad response */
+					if (tw_dev->srb[request_id] != 0)
+						tw_decode_sense(tw_dev, request_id, 1);
+					error = 3;
 				}
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
 					error = 1;
 				}
 				if (TW_STATUS_ERRORS(status_reg_value)) {
-				  tw_decode_bits(tw_dev, status_reg_value);
-				  error = 1;
+					tw_decode_bits(tw_dev, status_reg_value);
+					error = 1;
 				}
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 				/* Check for internal command */
@@ -1428,7 +1366,7 @@
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
 						tw_decode_bits(tw_dev, status_reg_value);
 					}
-		} else {
+				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
 					case READ_10:
 					case READ_6:
@@ -1455,18 +1393,23 @@
 						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
 						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
 					}
-					if (error) {
+					if (error == 1) {
 						/* Tell scsi layer there was an error */
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
 						tw_dev->srb[request_id]->result = (DID_RESET << 16);
-					} else {
+					}
+					if (error == 0) {
 						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
 					}
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					tw_state_request_finish(tw_dev, request_id);
-					tw_dev->posted_request_count--;
-					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+					if (error != 2) {
+						tw_dev->state[request_id] = TW_S_COMPLETED;
+						tw_state_request_finish(tw_dev, request_id);
+						tw_dev->posted_request_count--;
+						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+					}
 					status_reg_value = inl(status_reg_addr);
 					if (tw_check_bits(status_reg_value)) {
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
@@ -1479,19 +1422,22 @@
 	}
 	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 	clear_bit(TW_IN_INTR, &tw_dev->flags);
-}	/* End tw_interrupt() */
+} /* End tw_interrupt() */
 
 /* This function handles ioctls from userspace to the driver */
 int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
 {
 	unsigned char opcode;
-	int bufflen;
+	int bufflen, error = 0;
 	TW_Param *param;
-	TW_Command *command_packet;
+	TW_Command *command_packet, *command_save;
 	u32 param_value;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
-	int tw_aen_code;
+	int tw_aen_code, i, use_sg;
+	char *data_ptr;
+	int total_bytes = 0;
+	dma_addr_t dma_handle;
 
 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
 	if (ioctl == NULL) {
@@ -1598,7 +1544,7 @@
 				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
 				return 1;
 			}
-			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
+			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			tw_post_command_packet(tw_dev, request_id);
 			return 0;
 		case TW_CMD_PACKET:
@@ -1612,6 +1558,161 @@
 				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
 				return 1;
 			}
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
+			if (command_save == NULL) {
+				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
+				return 1;
+			}
+			if (ioctl->data != NULL) {
+				/* Copy down the command packet */
+				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
+				memcpy(command_save, ioctl->data, sizeof(TW_Command));
+				command_packet->request_id = request_id;
+
+				/* Now deal with the two possible sglists */
+				if (command_packet->byte0.sgl_offset == 2) {
+					use_sg = command_packet->size - 3;
+					for (i=0;i<use_sg;i++)
+						total_bytes+=command_packet->byte8.param.sgl[i].length;
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
+					if (!tw_dev->ioctl_data[request_id]) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						return 1;
+					}
+
+					/* Copy param sglist into the kernel */
+					data_ptr = tw_dev->ioctl_data[request_id];
+					for (i=0;i<use_sg;i++) {
+						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
+							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
+							if (error) {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
+								goto tw_ioctl_bail;
+							}
+						} else {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
+							tw_dev->srb[request_id]->result = (DID_RESET << 16);
+							goto tw_ioctl_bail;
+						}
+						data_ptr+=command_packet->byte8.param.sgl[i].length;
+					}
+					command_packet->size = 4;
+					command_packet->byte8.param.sgl[0].address = dma_handle;
+					command_packet->byte8.param.sgl[0].length = total_bytes;
+				}
+				if (command_packet->byte0.sgl_offset == 3) {
+					use_sg = command_packet->size - 4;
+					for (i=0;i<use_sg;i++)
+						total_bytes+=command_packet->byte8.io.sgl[i].length;
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
+					if (!tw_dev->ioctl_data[request_id]) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						return 1;
+					}
+					if (command_packet->byte0.opcode == TW_OP_WRITE) {
+						/* Copy io sglist into the kernel */
+						data_ptr = tw_dev->ioctl_data[request_id];
+						for (i=0;i<use_sg;i++) {
+							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
+								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
+								if (error) {
+									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
+									goto tw_ioctl_bail;
+								}
+							} else {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
+								tw_dev->srb[request_id]->result = (DID_RESET << 16);
+								goto tw_ioctl_bail;
+							}
+							data_ptr+=command_packet->byte8.io.sgl[i].length;
+						}
+					}
+					command_packet->size = 5;
+					command_packet->byte8.io.sgl[0].address = dma_handle;
+					command_packet->byte8.io.sgl[0].length = total_bytes;
+				}
+
+				spin_unlock_irq(tw_dev->host->host_lock);
+				spin_unlock_irq(&tw_dev->tw_lock);
+
+				/* Finally post the command packet */
+				tw_post_command_packet(tw_dev, request_id);
+
+				mdelay(TW_IOCTL_WAIT_TIME);
+				spin_lock_irq(&tw_dev->tw_lock);
+				spin_lock_irq(tw_dev->host->host_lock);
+
+				if (signal_pending(current)) {
+					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
+					goto tw_ioctl_bail;
+				}
+
+				tw_dev->srb[request_id]->result = (DID_OK << 16);
+				/* Now copy up the param or io sglist to userspace */
+				if (command_packet->byte0.sgl_offset == 2) {
+					use_sg = command_save->size - 3;
+					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
+					for (i=0;i<use_sg;i++) {
+						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
+							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
+							if (error) {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
+								goto tw_ioctl_bail;
+							}
+							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
+							data_ptr+=command_save->byte8.param.sgl[i].length;
+						} else {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
+							tw_dev->srb[request_id]->result = (DID_RESET << 16);
+							goto tw_ioctl_bail;
+						}
+					}
+				}
+				if (command_packet->byte0.sgl_offset == 3) {
+					use_sg = command_save->size - 4;
+					if (command_packet->byte0.opcode == TW_OP_READ) {
+						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
+						for(i=0;i<use_sg;i++) {
+							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
+								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
+								if (error) {
+									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
+									goto tw_ioctl_bail;
+								}
+								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
+								data_ptr+=command_save->byte8.io.sgl[i].length;
+							} else {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
+								tw_dev->srb[request_id]->result = (DID_RESET << 16);
+								goto tw_ioctl_bail;
+							}
+						}
+					}
+				}
+				
+			tw_ioctl_bail:
+
+				/* Free up sglist memory */
+				if (tw_dev->ioctl_data[request_id])
+					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
+				else
+					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
+				
+				/* Now complete the io */
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				tw_state_request_finish(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+				return 0;
+			} else {
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+				return 1;
+			}
 		default:
 			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
 			tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1655,6 +1756,7 @@
 	TW_Param *param;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
+	TW_Command *command_packet;
 
 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
 	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
@@ -1663,6 +1765,13 @@
 		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
 		return 1;
 	}
+
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
+		return 1;
+	}
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
 
 	ioctl = (TW_Ioctl *)buff;
@@ -1671,6 +1780,9 @@
 			passthru = (TW_Passthru *)ioctl->data;
 			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
 			break;
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			return 2; /* Special case for isr to not complete io */
 		default:
 			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
 			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1684,6 +1796,40 @@
 	return 0;
 } /* End tw_ioctl_complete() */
 
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+	
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = use_sg;
+	
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
 /* This function will mask the command interrupt */
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -1704,14 +1850,25 @@
 	do_gettimeofday(&before);
 	status_reg_value = inl(status_reg_addr);
 
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value);
+	}
+		
 	while ((status_reg_value & flag) != flag) {
 		status_reg_value = inl(status_reg_addr);
+
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value);
+		}
+
 		do_gettimeofday(&timeout);
 		if (before.tv_sec + seconds < timeout.tv_sec) { 
 			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
 			return 1;
 		}
-		mdelay(1);
+		mdelay(5);
 	}
 	return 0;
 } /* End tw_poll_status() */
@@ -1787,6 +1944,7 @@
 				srb = tw_dev->srb[i];
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
 			}
 		}
 	}
@@ -1821,7 +1979,7 @@
 
 		error = tw_aen_drain_queue(tw_dev);
 		if (error) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no);
+			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
 			tries++;
 			continue;
 		}
@@ -1857,7 +2015,7 @@
 	}
 
 	/* Re-enable interrupts */
-	tw_enable_interrupts(tw_dev);
+	tw_enable_and_clear_interrupts(tw_dev);
 
 	return 0;
 } /* End tw_reset_sequence() */
@@ -2381,6 +2539,9 @@
 	capacity = (param_data[3] << 24) | (param_data[2] << 16) | 
 		   (param_data[1] << 8) | param_data[0];
 
+	/* Subtract one sector to fix get last sector ioctl */
+	capacity -= 1;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
 
 	/* Number of LBA's */
@@ -2403,8 +2564,8 @@
 {
 	TW_Command *command_packet;
 	u32 command_que_addr, command_que_value = 0;
-	u32 lba = 0x0, num_sectors = 0x0;
-	int i, count = 0;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg;
 	Scsi_Cmnd *srb;
 	struct scatterlist *sglist;
 
@@ -2461,45 +2622,25 @@
 	command_packet->byte8.io.lba = lba;
 	command_packet->byte6.block_count = num_sectors;
 
-	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
-		/* Do this if there are no sg list entries */
-		if (tw_dev->srb[request_id]->use_sg == 0) {    
-			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
-			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-		}
-
-		/* Do this if we have multiple sg list entries */
-		if (tw_dev->srb[request_id]->use_sg > 0) {
-			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-				command_packet->byte8.io.sgl[i].length = sglist[i].length;
-				command_packet->size+=2;
-			}
-			if (tw_dev->srb[request_id]->use_sg >= 1)
-				command_packet->size-=2;
+	/* Do this if there are no sg list entries */
+	if (tw_dev->srb[request_id]->use_sg == 0) {    
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		command_packet->byte8.io.sgl[0].address = buffaddr;
+		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+	}
+
+	/* Do this if we have multiple sg list entries */
+	if (tw_dev->srb[request_id]->use_sg > 0) {
+		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);;
+		for (i=0;i<use_sg; i++) {
+			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
+			command_packet->size+=2;
 		}
-	} else {
-                /* Do this if there are no sg list entries for raid 5 */
-                if (tw_dev->srb[request_id]->use_sg == 0) {
-			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
-			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
-			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-                }
-
-                /* Do this if we have multiple sg list entries for raid 5 */
-                if (tw_dev->srb[request_id]->use_sg > 0) {
-                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
-                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
-				count+=sglist[i].length;
-                        }
-                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
-                        command_packet->byte8.io.sgl[0].length = count;
-                        command_packet->size = 5; /* single sgl */
-                }
-        }
+		if (tw_dev->srb[request_id]->use_sg >= 1)
+			command_packet->size-=2;
+	}
 
 	/* Update SG statistics */
 	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
@@ -2521,18 +2662,18 @@
 /* This function will handle the request sense scsi command */
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
-  
-       /* For now we just zero the sense buffer */
-       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-       tw_dev->state[request_id] = TW_S_COMPLETED;
-       tw_state_request_finish(tw_dev, request_id);
-  
-       /* If we got a request_sense, we probably want a reset, return error */
-       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
-       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-  
-       return 0;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+
+	/* For now we just zero the request buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+	return 0;
 } /* End tw_scsiop_request_sense() */
 
 /* This function will handle test unit ready scsi command */
@@ -2626,8 +2767,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break; /* Response was okay, so we exit */
@@ -2671,7 +2811,7 @@
 	}
 
 	/* Re-enable interrupts */
-	tw_enable_interrupts(tw_dev);
+	tw_enable_and_clear_interrupts(tw_dev);
 
 	return 0;
 } /* End tw_shutdown_device() */
@@ -2719,7 +2859,7 @@
 	int id = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
-
+	
 	/* Obtain next free request_id */
 	do {
 		if (tw_dev->free_head == tw_dev->free_wrap) {
@@ -2738,6 +2878,19 @@
 	return 0;
 } /* End tw_state_request_start() */
 
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+
+	if (cmd->use_sg) {
+		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+	} else {
+		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+	}
+} /* End tw_unmap_scsi_data() */
+
 /* This function will unmask the command interrupt on the controller */
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -2749,7 +2902,6 @@
 } /* End tw_unmask_command_interrupt() */
 
 /* Now get things going */
-
 static Scsi_Host_Template driver_template = TWXXXX;
 #include "scsi_module.c"
 
diff -urN linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h linux-2.5.6-pre3/drivers/scsi/3w-xxxx.h
--- linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/scsi/3w-xxxx.h	Wed Mar  6 17:17:51 2002
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2001 3ware Inc.
+   Copyright (C) 1999-2002 3ware Inc.
 
    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -62,7 +62,7 @@
 static char *tw_aen_string[] = {
 	"AEN queue empty",                      // 0x000
 	"Soft reset occurred",                  // 0x001
-	"Mirorr degraded: Unit #",              // 0x002
+	"Unit degraded: Unit #",                // 0x002
 	"Controller error",                     // 0x003 
 	"Rebuild failed: Unit #",               // 0x004
 	"Rebuild complete: Unit #",             // 0x005
@@ -90,10 +90,36 @@
 	"DCB unsupported version: Port #",      // 0x028
 	"Verify started: Unit #",               // 0x029
 	"Verify failed: Port #",                // 0x02A
-	"Verify complete: Unit #"               // 0x02B
+	"Verify complete: Unit #",              // 0x02B
+	"Overwrote bad sector during rebuild: Port #",  //0x2C
+	"Encountered bad sector during rebuild: Port #" //0x2D
 };
 
-#define TW_AEN_STRING_MAX                      0x02C
+#define TW_AEN_STRING_MAX                      0x02E
+
+/*
+   Sense key lookup table
+   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
+*/
+static unsigned char tw_sense_table[][4] =
+{
+  /* Codes for newer firmware */
+                            // ATA Error                    SCSI Error
+  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
+  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
+  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
+  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
+  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
+  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
+  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+
+  /* Codes for older firmware */
+                            // 3ware Error                  SCSI Error
+  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
+  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
+  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
+};
 
 /* Control register bit definitions */
 #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
@@ -108,6 +134,7 @@
 #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
 #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
 #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
 
 /* Status register bit definitions */
 #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
@@ -140,6 +167,7 @@
 #define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
 #define TW_NUMDEVICES 2
 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000
 
 /* Command packet opcodes */
 #define TW_OP_NOP	      0x0
@@ -153,6 +181,7 @@
 #define TW_OP_AEN_LISTEN      0x1c
 #define TW_CMD_PACKET         0x1d
 #define TW_ATA_PASSTHRU       0x1e
+#define TW_CMD_PACKET_WITH_DATA 0x1f
 
 /* Asynchronous Event Notification (AEN) Codes */
 #define TW_AEN_QUEUE_EMPTY       0x0000
@@ -169,7 +198,8 @@
 #define TW_AEN_SBUF_FAIL         0x0024
 
 /* Misc defines */
-#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
+#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
+#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
 #define TW_MAX_UNITS			      16
 #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
 #define TW_INIT_MESSAGE_CREDITS		      0x100
@@ -179,7 +209,6 @@
 #define TW_ATA_PASS_SGL_MAX                   60
 #define TW_MAX_PASSTHRU_BYTES                 4096
 #define TW_Q_LENGTH			      256
-#define TW_MAX_BOUNCEBUF                      16
 #define TW_Q_START			      0
 #define TW_MAX_SLOT			      32
 #define TW_MAX_PCI_BUSES		      255
@@ -191,12 +220,9 @@
 #define TW_MAX_AEN_TRIES                      100
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
 #define TW_MAX_SECTORS                        256
-#else
-#define TW_MAX_SECTORS                        128
-#endif 
 #define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -262,7 +288,6 @@
 } TW_Command;
 
 typedef struct TAG_TW_Ioctl {
-	int buffer;
 	unsigned char opcode;
 	unsigned short table_id;
 	unsigned char parameter_id;
@@ -345,11 +370,8 @@
 	TW_Registers		registers;
 	u32			*alignment_virtual_address[TW_Q_LENGTH];
 	u32			alignment_physical_address[TW_Q_LENGTH];
-	u32			*bounce_buffer[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
-	int			is_raid_five[TW_MAX_UNITS];
 	int			num_units;
-	int			num_raid_five;
 	u32			*command_packet_virtual_address[TW_Q_LENGTH];
 	u32			command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
@@ -381,22 +403,24 @@
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
 	long			flags; /* long req'd for set_bit --RR */
+	char			*ioctl_data[TW_Q_LENGTH];
 } TW_Device_Extension;
 
 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
 int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
 void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
 void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
+void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
 void tw_disable_interrupts(TW_Device_Extension *tw_dev);
 int tw_empty_response_que(TW_Device_Extension *tw_dev);
 void tw_enable_interrupts(TW_Device_Extension *tw_dev);
+void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
 int tw_findcards(Scsi_Host_Template *tw_host);
 void tw_free_device_extension(TW_Device_Extension *tw_dev);
 int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits);
diff -urN linux-2.5.6-pre2/drivers/scsi/aic7xxx/aic7xxx.c linux-2.5.6-pre3/drivers/scsi/aic7xxx/aic7xxx.c
--- linux-2.5.6-pre2/drivers/scsi/aic7xxx/aic7xxx.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/drivers/scsi/aic7xxx/aic7xxx.c	Wed Mar  6 17:17:52 2002
@@ -2584,7 +2584,7 @@
 
 		/*
 		 * Read the latched byte, but turn off SPIOEN first
-		 * so that we don't inadvertantly cause a REQ for the
+		 * so that we don't inadvertently cause a REQ for the
 		 * next byte.
 		 */
 		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
diff -urN linux-2.5.6-pre2/drivers/scsi/ide-scsi.c linux-2.5.6-pre3/drivers/scsi/ide-scsi.c
--- linux-2.5.6-pre2/drivers/scsi/ide-scsi.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/scsi/ide-scsi.c	Wed Mar  6 17:17:52 2002
@@ -138,7 +138,7 @@
 			idescsi_discard_data (drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		count = min(pc->sg->length - pc->b_count, bcount);
 		buf = page_address(pc->sg->page) + pc->sg->offset;
 		atapi_input_bytes (drive, buf + pc->b_count, count);
 		bcount -= count; pc->b_count += count;
@@ -160,7 +160,7 @@
 			idescsi_output_zeros (drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
+		count = min(pc->sg->length - pc->b_count, bcount);
 		buf = page_address(pc->sg->page) + pc->sg->offset;
 		atapi_output_bytes (drive, buf + pc->b_count, count);
 		bcount -= count; pc->b_count += count;
@@ -290,7 +290,7 @@
 			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
 				printk(", rst = ");
 				scsi_buf = pc->scsi_cmd->request_buffer;
-				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
+				hexdump(scsi_buf, min(16, pc->scsi_cmd->request_bufflen));
 			} else printk("\n");
 		}
 	}
@@ -307,7 +307,7 @@
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
 {
-	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+	return max(WAIT_CMD, pc->timeout - jiffies);
 }
 
 /*
@@ -431,7 +431,7 @@
 	scsi->pc=pc;							/* Set the current packet command */
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+	bcount = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
 	if (drive->using_dma && rq->bio)
 		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -536,7 +536,11 @@
 	return 0;
 }
 
-static int idescsi_reinit(ide_drive_t *drive);
+static void idescsi_revalidate(ide_drive_t *_dummy)
+{
+	/* The partition information will be handled by the SCSI layer.
+	 */
+}
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -545,26 +549,19 @@
 	owner:			THIS_MODULE,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
-	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
 	ioctl:			NULL,
 	open:			idescsi_open,
 	release:		idescsi_ide_release,
-	media_change:		NULL,
-	revalidate:		NULL,
+	check_media_change:	NULL,
+	revalidate:		idescsi_revalidate,
 	pre_reset:		NULL,
 	capacity:		NULL,
 	special:		NULL,
-	proc:			NULL,
-	driver_reinit:		idescsi_reinit,
+	proc:			NULL
 };
 
-static int idescsi_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
-
 /*
  *	idescsi_init will register the driver for each scsi.
  */
@@ -616,9 +613,9 @@
 	host = scsi_register(host_template, 0);
 	if(host == NULL)
 		return 0;
-		
+
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
-		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);
+		last_lun = max(last_lun, idescsi_drives[id]->last_lun);
 	host->max_id = id;
 	host->max_lun = last_lun + 1;
 	host->can_queue = host->cmd_per_lun * id;
diff -urN linux-2.5.6-pre2/drivers/scsi/scsi.c linux-2.5.6-pre3/drivers/scsi/scsi.c
--- linux-2.5.6-pre2/drivers/scsi/scsi.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/scsi/scsi.c	Wed Mar  6 17:17:52 2002
@@ -165,6 +165,11 @@
 void scsi_build_commandblocks(Scsi_Device * SDpnt);
 
 /*
+ * Private interface into the new error handling code.
+ */
+extern int scsi_new_reset(Scsi_Cmnd *SCpnt, unsigned int flag);
+
+/*
  * Function:    scsi_initialize_queue()
  *
  * Purpose:     Selects queue handler function for a device.
@@ -2663,6 +2668,94 @@
 }
 
 /*
+ * Function:	scsi_reset_provider_done_command
+ *
+ * Purpose:	Dummy done routine.
+ *
+ * Notes:	Some low level drivers will call scsi_done and end up here,
+ *		others won't bother.
+ *		We don't want the bogus command used for the bus/device
+ *		reset to find its way into the mid-layer so we intercept
+ *		it here.
+ */
+static void
+scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
+{
+}
+
+/*
+ * Function:	scsi_reset_provider
+ *
+ * Purpose:	Send requested reset to a bus or device at any phase.
+ *
+ * Arguments:	device	- device to send reset to
+ *		flag - reset type (see scsi.h)
+ *
+ * Returns:	SUCCESS/FAILURE.
+ *
+ * Notes:	This is used by the SCSI Generic driver to provide
+ *		Bus/Device reset capability.
+ */
+int
+scsi_reset_provider(Scsi_Device *dev, int flag)
+{
+	Scsi_Cmnd SC, *SCpnt = &SC;
+	int rtn;
+
+	memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
+	SCpnt->host                    	= dev->host;
+	SCpnt->device                  	= dev;
+	SCpnt->target                  	= dev->id;
+	SCpnt->lun                     	= dev->lun;
+	SCpnt->channel                 	= dev->channel;
+	SCpnt->request.rq_status       	= RQ_SCSI_BUSY;
+	SCpnt->request.waiting        	= NULL;
+	SCpnt->use_sg                  	= 0;
+	SCpnt->old_use_sg              	= 0;
+	SCpnt->old_cmd_len             	= 0;
+	SCpnt->underflow               	= 0;
+	SCpnt->transfersize            	= 0;
+	SCpnt->resid			= 0;
+	SCpnt->serial_number           	= 0;
+	SCpnt->serial_number_at_timeout	= 0;
+	SCpnt->host_scribble           	= NULL;
+	SCpnt->next                    	= NULL;
+	SCpnt->state                   	= SCSI_STATE_INITIALIZING;
+	SCpnt->owner	     		= SCSI_OWNER_MIDLEVEL;
+    
+	memset(&SCpnt->cmnd, '\0', sizeof(SCpnt->cmnd));
+    
+	SCpnt->scsi_done		= scsi_reset_provider_done_command;
+	SCpnt->done			= NULL;
+	SCpnt->reset_chain		= NULL;
+        
+	SCpnt->buffer			= NULL;
+	SCpnt->bufflen			= 0;
+	SCpnt->request_buffer		= NULL;
+	SCpnt->request_bufflen		= 0;
+
+	SCpnt->internal_timeout		= NORMAL_TIMEOUT;
+	SCpnt->abort_reason		= DID_ABORT;
+
+	SCpnt->cmd_len			= 0;
+
+	SCpnt->sc_data_direction	= SCSI_DATA_UNKNOWN;
+	SCpnt->sc_request		= NULL;
+	SCpnt->sc_magic			= SCSI_CMND_MAGIC;
+
+	/*
+	 * Sometimes the command can get back into the timer chain,
+	 * so use the pid as an identifier.
+	 */
+	SCpnt->pid			= 0;
+
+        rtn = scsi_new_reset(SCpnt, flag);
+
+	scsi_delete_timer(SCpnt);
+	return rtn;
+}
+
+/*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
  * adjust the settings for this buffer only.  This must remain at the end
diff -urN linux-2.5.6-pre2/drivers/scsi/scsi.h linux-2.5.6-pre3/drivers/scsi/scsi.h
--- linux-2.5.6-pre2/drivers/scsi/scsi.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/drivers/scsi/scsi.h	Wed Mar  6 17:17:52 2002
@@ -834,6 +834,16 @@
 	current->state = TASK_RUNNING;	\
     }; }
 
+/*
+ * old style reset request from external source
+ * (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c)
+ */
+#define SCSI_TRY_RESET_DEVICE	1
+#define SCSI_TRY_RESET_BUS	2
+#define SCSI_TRY_RESET_HOST	3
+
+extern int scsi_reset_provider(Scsi_Device *, int);
+
 #endif
 
 /*
diff -urN linux-2.5.6-pre2/drivers/scsi/scsi_error.c linux-2.5.6-pre3/drivers/scsi/scsi_error.c
--- linux-2.5.6-pre2/drivers/scsi/scsi_error.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/drivers/scsi/scsi_error.c	Wed Mar  6 17:17:52 2002
@@ -979,15 +979,24 @@
 	case DID_SOFT_ERROR:
 		goto maybe_retry;
 
+	case DID_ERROR:
+		if (msg_byte(SCpnt->result) == COMMAND_COMPLETE &&
+		    status_byte(SCpnt->result) == RESERVATION_CONFLICT)
+			/*
+			 * execute reservation conflict processing code
+			 * lower down
+			 */
+			break;
+		/* FALLTHROUGH */
+
 	case DID_BUS_BUSY:
 	case DID_PARITY:
-	case DID_ERROR:
 		goto maybe_retry;
 	case DID_TIME_OUT:
 		/*
-		   * When we scan the bus, we get timeout messages for
-		   * these commands if there is no device available.
-		   * Other hosts report DID_NO_CONNECT for the same thing.
+		 * When we scan the bus, we get timeout messages for
+		 * these commands if there is no device available.
+		 * Other hosts report DID_NO_CONNECT for the same thing.
 		 */
 		if ((SCpnt->cmnd[0] == TEST_UNIT_READY ||
 		     SCpnt->cmnd[0] == INQUIRY)) {
@@ -1048,8 +1057,13 @@
 		 */
 		return SUCCESS;
 	case BUSY:
-	case RESERVATION_CONFLICT:
 		goto maybe_retry;
+
+	case RESERVATION_CONFLICT:
+		printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", 
+		       SCpnt->host->host_no, SCpnt->channel,
+		       SCpnt->device->id, SCpnt->device->lun);
+		return SUCCESS; /* causes immediate I/O error */
 	default:
 		return FAILED;
 	}
@@ -1950,6 +1964,45 @@
 }
 
 /*
+ * Function:	scsi_new_reset
+ *
+ * Purpose:	Send requested reset to a bus or device at any phase.
+ *
+ * Arguments:	SCpnt	- command ptr to send reset with (usually a dummy)
+ *		flag - reset type (see scsi.h)
+ *
+ * Returns:	SUCCESS/FAILURE.
+ *
+ * Notes:	This is used by the SCSI Generic driver to provide
+ *		Bus/Device reset capability.
+ */
+int
+scsi_new_reset(Scsi_Cmnd *SCpnt, int flag)
+{
+	int rtn;
+
+	switch(flag) {
+	case SCSI_TRY_RESET_DEVICE:
+		rtn = scsi_try_bus_device_reset(SCpnt, 0);
+		if (rtn == SUCCESS)
+			break;
+		/* FALLTHROUGH */
+	case SCSI_TRY_RESET_BUS:
+		rtn = scsi_try_bus_reset(SCpnt);
+		if (rtn == SUCCESS)
+			break;
+		/* FALLTHROUGH */
+	case SCSI_TRY_RESET_HOST:
+		rtn = scsi_try_host_reset(SCpnt);
+		break;
+	default:
+		rtn = FAILED;
+	}
+
+	return rtn;
+}
+
+/*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
  * adjust the settings for this buffer only.  This must remain at the end
diff -urN linux-2.5.6-pre2/drivers/scsi/scsi_syms.c linux-2.5.6-pre3/drivers/scsi/scsi_syms.c
--- linux-2.5.6-pre2/drivers/scsi/scsi_syms.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/scsi/scsi_syms.c	Wed Mar  6 17:17:52 2002
@@ -81,6 +81,11 @@
 EXPORT_SYMBOL(scsi_deregister_blocked_host);
 
 /*
+ * This symbol is for the highlevel drivers (e.g. sg) only.
+ */
+EXPORT_SYMBOL(scsi_reset_provider);
+
+/*
  * These are here only while I debug the rest of the scsi stuff.
  */
 EXPORT_SYMBOL(scsi_hostlist);
diff -urN linux-2.5.6-pre2/drivers/scsi/sd.c linux-2.5.6-pre3/drivers/scsi/sd.c
--- linux-2.5.6-pre2/drivers/scsi/sd.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/drivers/scsi/sd.c	Wed Mar  6 17:17:52 2002
@@ -235,7 +235,7 @@
                 case BLKELVSET:
 		case BLKBSZGET:
 		case BLKBSZSET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
+			return blk_ioctl(inode->i_bdev, cmd, arg);
 
 		case BLKRRPART: /* Re-read partition tables */
 		        if (!capable(CAP_SYS_ADMIN))
diff -urN linux-2.5.6-pre2/drivers/scsi/sr_ioctl.c linux-2.5.6-pre3/drivers/scsi/sr_ioctl.c
--- linux-2.5.6-pre2/drivers/scsi/sr_ioctl.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/drivers/scsi/sr_ioctl.c	Wed Mar  6 17:17:52 2002
@@ -48,7 +48,7 @@
 	
 	if (ti->cdti_trk1 == ntracks) 
 		ti->cdti_trk1 = CDROM_LEADOUT;
-	else 
+	else if (ti->cdti_trk1 != CDROM_LEADOUT)
 		ti->cdti_trk1 ++;
 
 	trk0_te.cdte_track = ti->cdti_trk0;
@@ -548,11 +548,6 @@
 		return put_user(scsi_CDs[target].capacity, (unsigned long *) arg);
 	case BLKGETSIZE64:
 		return put_user((u64)scsi_CDs[target].capacity << 9, (u64 *)arg);
-	case BLKROSET:
-	case BLKROGET:
-	case BLKFLSBUF:
-	case BLKSSZGET:
-		return blk_ioctl(cdi->dev, cmd, arg);
 
 	default:
 		return scsi_ioctl(scsi_CDs[target].device, cmd, (void *) arg);
diff -urN linux-2.5.6-pre2/drivers/telephony/Config.help linux-2.5.6-pre3/drivers/telephony/Config.help
--- linux-2.5.6-pre2/drivers/telephony/Config.help	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/drivers/telephony/Config.help	Wed Mar  6 17:17:52 2002
@@ -26,3 +26,8 @@
   If you do not have any Quicknet telephony cards, you can safely
   say N here.
 
+CONFIG_PHONE_IXJ_PCMCIA
+  Say Y here to configure in PCMCIA service support for the Quicknet
+  cards manufactured by Quicknet Technologies, Inc.  This changes the
+  card initialization code to work with the card manager daemon.
+
diff -urN linux-2.5.6-pre2/drivers/telephony/ixj.c linux-2.5.6-pre3/drivers/telephony/ixj.c
--- linux-2.5.6-pre2/drivers/telephony/ixj.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/drivers/telephony/ixj.c	Wed Mar  6 17:17:52 2002
@@ -3450,7 +3450,7 @@
 	j->cidcw_wait = 0;
 	if(!j->flags.cidcw_ack) {
 		if(ixjdebug & 0x0200) {
-			printk("IXJ cidcw phone%d did not recieve ACK from display %ld\n", j->board, jiffies);
+			printk("IXJ cidcw phone%d did not receive ACK from display %ld\n", j->board, jiffies);
 		}
 		ixj_post_cid(j);
 		if(j->cid_play_flag) {
diff -urN linux-2.5.6-pre2/drivers/usb/hid-core.c linux-2.5.6-pre3/drivers/usb/hid-core.c
--- linux-2.5.6-pre2/drivers/usb/hid-core.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/usb/hid-core.c	Wed Mar  6 17:17:53 2002
@@ -1048,6 +1048,7 @@
 
 	if (hid->outhead != hid->outtail) {
 		hid_submit_out(hid);
+		spin_unlock_irqrestore(&hid->outlock, flags);
 		return;
 	}
 
@@ -1079,6 +1080,7 @@
 
 	if (hid->ctrlhead != hid->ctrltail) {
 		hid_submit_ctrl(hid);
+		spin_unlock_irqrestore(&hid->ctrllock, flags);
 		return;
 	}
 
diff -urN linux-2.5.6-pre2/drivers/usb/ov511.c linux-2.5.6-pre3/drivers/usb/ov511.c
--- linux-2.5.6-pre2/drivers/usb/ov511.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/usb/ov511.c	Wed Mar  6 17:17:53 2002
@@ -1,7 +1,7 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
  *
- * Copyright (c) 1999-2001 Mark W. McClelland
+ * Copyright (c) 1999-2002 Mark W. McClelland
  * Original decompression code Copyright 1998-2000 OmniVision Technologies
  * Many improvements by Bret Wallach <bwallac1@san.rr.com>
  * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
@@ -10,6 +10,8 @@
  * Changes by Claudio Matsuoka <claudio@conectiva.com>
  * Original SAA7111A code by Dave Perks <dperks@ibm.net>
  * Kernel I2C interface adapted from nt1003 driver
+ * URB error messages from pwc driver by Nemosoft
+ * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
  *
  * Based on the Linux CPiA driver written by Peter Pregler,
  * Scott J. Bertin and Johannes Erdfelt.
@@ -53,22 +55,35 @@
 	#include <asm/cpufeature.h>
 #endif
 
+/* A new implementation of the V4L 1 API exists that gives drivers direct
+ * access to file_operations. The old API is compatible with all 2.2 and 2.4
+ * kernels, and all 2.5 kernels through 2.5.5 (at least).
+ *
+ * Remove this #define to enable the new API
+ *
+ * Note: This has nothing to do with the V4L 2 API.
+ */
+#define OV511_OLD_V4L
+
 #include "ov511.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.49 for Linux 2.5"
+#define DRIVER_VERSION "v1.53 for Linux 2.5"
 #define EMAIL "mmcclell@bigfoot.com"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
 	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "OV511 USB Camera Driver"
+#define DRIVER_DESC "ov511 USB Camera Driver"
 
 #define OV511_I2C_RETRIES 3
 #define ENABLE_Y_QUANTABLE 1
 #define ENABLE_UV_QUANTABLE 1
 
+/* If you change this, you must also change the MODULE_PARM definition */
+#define OV511_MAX_UNIT_VIDEO 16
+
 /* Pixel count * 3 bytes for RGB */
 #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3)
 #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
@@ -78,128 +93,55 @@
 
 #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
 
-/* PARAMETER VARIABLES: */
-/* (See ov511.txt for detailed descriptions of these.) */
-
-/* Sensor automatically changes brightness */
-static int autobright = 1;
-
-/* Sensor automatically changes gain */
-static int autogain = 1;
-
-/* Sensor automatically changes exposure */
-static int autoexp = 1;
-
-/* 0=no debug messages
- * 1=init/detection/unload and other significant messages,
- * 2=some warning messages
- * 3=config/control function calls
- * 4=most function calls and data parsing messages
- * 5=highly repetitive mesgs
- * NOTE: This should be changed to 0, 1, or 2 for production kernels
- */
-static int debug; /* = 0 */
-
-/* Fix vertical misalignment of red and blue at 640x480 */
-static int fix_rgb_offset; /* = 0 */
-
-/* Snapshot mode enabled flag */
-static int snapshot; /* = 0 */
-
-/* Force image to be read in RGB instead of BGR. This option allow
- * programs that expect RGB data (e.g. gqcam) to work with this driver. */
-static int force_rgb; /* = 0 */
-
-/* Number of seconds before inactive buffers are deallocated */
-static int buf_timeout = 5;
-
-/* Number of cameras to stream from simultaneously */
-static int cams = 1;
-
-/* Enable compression. Needs a fast (>300 MHz) CPU. */
-static int compress; /* = 0 */
-
-/* Display test pattern - doesn't work yet either */
-static int testpat; /* = 0 */
-
-/* Setting this to 1 will make the sensor output GBR422 instead of YUV420. Only
- * affects RGB24 mode. */
-static int sensor_gbr; /* = 0 */
-
-/* Dump raw pixel data. */
-static int dumppix; /* = 0 */
-
-/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto
- * (on when open) */
-static int led = 1;
-
-/* Set this to 1 to dump the bridge register contents after initialization */
-static int dump_bridge; /* = 0 */
-
-/* Set this to 1 to dump the sensor register contents after initialization */
-static int dump_sensor; /* = 0 */
-
-/* Temporary option for debugging "works, but no image" problem. Prints the
- * first 12 bytes of data (potentially a packet header) in each isochronous
- * data frame. */
-static int printph; /* = 0 */
-
-/* Compression parameters - I'm not exactly sure what these do yet */
-static int phy = 0x1f;
-static int phuv = 0x05;
-static int pvy = 0x06;
-static int pvuv = 0x06;
-static int qhy = 0x14;
-static int qhuv = 0x03;
-static int qvy = 0x04;
-static int qvuv = 0x04;
-
-/* Light frequency. Set to 50 or 60 (Hz), or zero for default settings */
-static int lightfreq; /* = 0 */
+/**********************************************************************
+ * Module Parameters
+ * (See ov511.txt for detailed descriptions of these)
+ **********************************************************************/
 
-/* Set this to 1 to enable banding filter by default. Compensates for
- * alternating horizontal light/dark bands caused by (usually fluorescent)
- * lights */
-static int bandingfilter; /* = 0 */
+/* These variables (and all static globals) default to zero */
+static int autobright		= 1;
+static int autogain		= 1;
+static int autoexp		= 1;
+static int debug;
+static int fix_rgb_offset;
+static int snapshot;
+static int force_rgb;
+static int buf_timeout		= 5;
+static int cams			= 1;
+static int compress;
+static int testpat;
+static int sensor_gbr;
+static int dumppix;
+static int led 			= 1;
+static int dump_bridge;
+static int dump_sensor;
+static int printph;
+static int phy			= 0x1f;
+static int phuv			= 0x05;
+static int pvy			= 0x06;
+static int pvuv			= 0x06;
+static int qhy			= 0x14;
+static int qhuv			= 0x03;
+static int qvy			= 0x04;
+static int qvuv			= 0x04;
+static int lightfreq;
+static int bandingfilter;
 
 /* Pixel clock divisor */
-static int clockdiv = -1;
+static int clockdiv		= -1;
 
 /* Isoc packet size */
-static int packetsize = -1;
+static int packetsize		= -1;
 
 /* Frame drop register (16h) */
-static int framedrop = -1;
-
-/* Allows picture settings (brightness, hue, etc...) to take effect immediately,
- * even in the middle of a frame. This reduces the time to change settings, but
- * can ruin frames during the change. Only affects OmniVision sensors. */
-static int fastset; /* = 0 */
-
-/* Forces the palette to a specific value. If an application requests a
- * different palette, it will be rejected. */
-static int force_palette; /* = 0 */
-
-/* Set tuner type, if not autodetected */
-static int tuner = -1;
-
-/* Allows proper exposure of objects that are illuminated from behind. Only
- * affects OmniVision sensors. */
-static int backlight; /* = 0 */
-
-/* If you change this, you must also change the MODULE_PARM definition */
-#define OV511_MAX_UNIT_VIDEO 16
+static int framedrop		= -1;
 
-/* Allows specified minor numbers to be forced. They will be assigned in the
- * order that devices are detected. Note that you cannot specify 0 as a minor
- * number. If you do not specify any, the next available one will be used. This
- * requires kernel 2.4.5 or later. */
+static int fastset;
+static int force_palette;
+static int tuner		= -1;
+static int backlight;
 static int unit_video[OV511_MAX_UNIT_VIDEO];
-
-/* Remove zero-padding from uncompressed incoming data. This will compensate for
- * the blocks of corruption that appear when the camera cannot keep up with the
- * speed of the USB bus (eg. at low frame resolutions) */
-static int remove_zeros; /* = 0 */
+static int remove_zeros;
 
 MODULE_PARM(autobright, "i");
 MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
@@ -289,6 +231,10 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+/**********************************************************************
+ * Miscellaneous Globals
+ **********************************************************************/
+
 static struct usb_driver ov511_driver;
 
 static struct ov51x_decomp_ops *ov511_decomp_ops;
@@ -303,20 +249,28 @@
 /* MMX support is present in kernel and CPU. Checked upon decomp module load. */
 static int ov51x_mmx_available;
 
-/* Function prototypes */
-static void ov51x_clear_snapshot(struct usb_ov511 *);
-static int ov51x_check_snapshot(struct usb_ov511 *);
-static inline int sensor_get_picture(struct usb_ov511 *, 
-				     struct video_picture *);
-static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
-static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
-			       unsigned long);
+static __devinitdata struct usb_device_id device_table [] = {
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
+	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
+	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
+	{ }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
+static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
+static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
+static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
+static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
 
 /**********************************************************************
- * List of known OV511-based cameras
+ * Symbolic Names
  **********************************************************************/
 
-static struct cam_list clist[] = {
+/* Known OV511-based cameras */
+static struct symbolic_list camlist[] = {
 	{   0, "Generic Camera (no ID)" },
 	{   1, "Mustek WCam 3X" },
 	{   3, "D-Link DSB-C300" },
@@ -336,46 +290,78 @@
 	{  -1, NULL }
 };
 
-static __devinitdata struct usb_device_id device_table [] = {
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
-	{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-	{ }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-static struct palette_list plist[] = {
+/* Video4Linux1 Palettes */
+static struct symbolic_list v4l1_plist[] = {
 	{ VIDEO_PALETTE_GREY,	"GREY" },
-	{ VIDEO_PALETTE_HI240,  "HI240" },
-	{ VIDEO_PALETTE_RGB565, "RGB565" },
+	{ VIDEO_PALETTE_HI240,	"HI240" },
+	{ VIDEO_PALETTE_RGB565,	"RGB565" },
 	{ VIDEO_PALETTE_RGB24,	"RGB24" },
 	{ VIDEO_PALETTE_RGB32,	"RGB32" },
-	{ VIDEO_PALETTE_RGB555, "RGB555" },
-	{ VIDEO_PALETTE_YUV422, "YUV422" },
-	{ VIDEO_PALETTE_YUYV,   "YUYV" },
-	{ VIDEO_PALETTE_UYVY,   "UYVY" },
-	{ VIDEO_PALETTE_YUV420, "YUV420" },
-	{ VIDEO_PALETTE_YUV411, "YUV411" },
-	{ VIDEO_PALETTE_RAW,    "RAW" },
+	{ VIDEO_PALETTE_RGB555,	"RGB555" },
+	{ VIDEO_PALETTE_YUV422,	"YUV422" },
+	{ VIDEO_PALETTE_YUYV,	"YUYV" },
+	{ VIDEO_PALETTE_UYVY,	"UYVY" },
+	{ VIDEO_PALETTE_YUV420,	"YUV420" },
+	{ VIDEO_PALETTE_YUV411,	"YUV411" },
+	{ VIDEO_PALETTE_RAW,	"RAW" },
 	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
 	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
 	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
 	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
 	{ -1, NULL }
 };
-#endif
 
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
+static struct symbolic_list brglist[] = {
+	{ BRG_OV511,		"OV511" },
+	{ BRG_OV511PLUS,	"OV511+" },
+	{ BRG_OV518,		"OV518" },
+	{ BRG_OV518PLUS,	"OV518+" },
+	{ -1, NULL }
+};
+
+static struct symbolic_list senlist[] = {
+	{ SEN_OV76BE,	"OV76BE" },
+	{ SEN_OV7610,	"OV7610" },
+	{ SEN_OV7620,	"OV7620" },
+	{ SEN_OV7620AE,	"OV7620AE" },
+	{ SEN_OV6620,	"OV6620" },
+	{ SEN_OV6630,	"OV6630" },
+	{ SEN_OV6630AE,	"OV6630AE" },
+	{ SEN_OV6630AF,	"OV6630AF" },
+	{ SEN_OV8600,	"OV8600" },
+	{ SEN_KS0127,	"KS0127" },
+	{ SEN_KS0127B,	"KS0127B" },
+	{ SEN_SAA7111A,	"SAA7111A" },
+	{ -1, NULL }
+};
+
+/* URB error codes: */
+static struct symbolic_list urb_errlist[] = {
+	{ -ENOSR,	"Buffer error (overrun)" },
+	{ -EPIPE,	"Stalled (device not responding)" },
+	{ -EOVERFLOW,	"Babble (bad cable?)" },
+	{ -EPROTO,	"Bit-stuff error (bad cable?)" },
+	{ -EILSEQ,	"CRC/Timeout" },
+	{ -ETIMEDOUT,	"NAK (device does not respond)" },
+	{ -1, NULL }
+};
+
+/**********************************************************************
+ * Prototypes
+ **********************************************************************/
+
+static void ov51x_clear_snapshot(struct usb_ov511 *);
+static int ov51x_check_snapshot(struct usb_ov511 *);
+static inline int sensor_get_picture(struct usb_ov511 *, 
+				     struct video_picture *);
+static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
+static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
+			       unsigned long);
 
 /**********************************************************************
+ *
  * Memory management
+ *
  **********************************************************************/
 
 /* Here we want the physical address of the memory.
@@ -453,7 +439,7 @@
 		     void *data)
 {
 	char *out = page;
-	int i, j, len;
+	int i, len;
 	struct usb_ov511 *ov = data;
 	struct video_picture p;
 	unsigned char exp;
@@ -469,8 +455,7 @@
 
 	out += sprintf(out, "driver_version  : %s\n", DRIVER_VERSION);
 	out += sprintf(out, "custom_id       : %d\n", ov->customid);
-	out += sprintf(out, "model           : %s\n", ov->desc ?
-		       clist[ov->desc].description : "unknown");
+	out += sprintf(out, "model           : %s\n", ov->desc);
 	out += sprintf(out, "streaming       : %s\n", YES_NO(ov->streaming));
 	out += sprintf(out, "grabbing        : %s\n", YES_NO(ov->grabbing));
 	out += sprintf(out, "compress        : %s\n", YES_NO(ov->compress));
@@ -491,36 +476,16 @@
 			       ov->frame[i].depth);
 		out += sprintf(out, "  size          : %d %d\n",
 			       ov->frame[i].width, ov->frame[i].height);
-		out += sprintf(out, "  format        : ");
-		for (j = 0; plist[j].num >= 0; j++) {
-			if (plist[j].num == ov->frame[i].format) {
-				out += sprintf(out, "%s\n", plist[j].name);
-				break;
-			}
-		}
-		if (plist[j].num < 0)
-			out += sprintf(out, "unknown\n");
+		out += sprintf(out, "  format        : %s\n",
+			       symbolic(v4l1_plist, ov->frame[i].format));
 		out += sprintf(out, "  data_buffer   : 0x%p\n",
 			       ov->frame[i].data);
 	}
 	out += sprintf(out, "snap_enabled    : %s\n", YES_NO(ov->snap_enabled));
 	out += sprintf(out, "bridge          : %s\n",
-		       ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
+		       symbolic(brglist, ov->bridge));
 	out += sprintf(out, "sensor          : %s\n",
-		       ov->sensor == SEN_OV6620 ? "OV6620" :
-			ov->sensor == SEN_OV6630 ? "OV6630" :
-			ov->sensor == SEN_OV7610 ? "OV7610" :
-			ov->sensor == SEN_OV7620 ? "OV7620" :
-			ov->sensor == SEN_OV7620AE ? "OV7620AE" :
-			ov->sensor == SEN_OV8600 ? "OV8600" :
-			ov->sensor == SEN_KS0127 ? "KS0127" :
-			ov->sensor == SEN_KS0127B ? "KS0127B" :
-			ov->sensor == SEN_SAA7111A ? "SAA7111A" :
-			"unknown");
+		       symbolic(senlist, ov->sensor));
 	out += sprintf(out, "packet_size     : %d\n", ov->packet_size);
 	out += sprintf(out, "framebuffer     : 0x%p\n", ov->fbuf);
 
@@ -582,89 +547,91 @@
 }
 
 static void 
-create_proc_ov511_cam(struct usb_ov511 *ov511)
+create_proc_ov511_cam(struct usb_ov511 *ov)
 {
-	char dirname[4];
+	char dirname[10];
 
-	if (!ov511_proc_entry || !ov511)
+	if (!ov511_proc_entry || !ov)
 		return;
 
 	/* Create per-device directory */
-	sprintf(dirname, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 	PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);
-	ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR,
-		ov511_proc_entry);
-	if (!ov511->proc_devdir)
+	ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry);
+	if (!ov->proc_devdir)
 		return;
+	ov->proc_devdir->owner = THIS_MODULE;
 
 	/* Create "info" entry (human readable device information) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);
-	ov511->proc_info = create_proc_read_entry("info",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-		ov511_read_proc_info, ov511);
-	if (!ov511->proc_info)
+	ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir, ov511_read_proc_info, ov);
+	if (!ov->proc_info)
 		return;
+	ov->proc_info->owner = THIS_MODULE;
 
 	/* Don't create it if old snapshot mode on (would cause race cond.) */
 	if (!snapshot) {
 		/* Create "button" entry (snapshot button status) */
 		PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname);
-		ov511->proc_button = create_proc_read_entry("button",
-			S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir,
-			ov511_read_proc_button, ov511);
-		if (!ov511->proc_button)
+		ov->proc_button = create_proc_read_entry("button",
+			S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir,
+			ov511_read_proc_button, ov);
+		if (!ov->proc_button)
 			return;
 	}
+	ov->proc_button->owner = THIS_MODULE;
 
 	/* Create "control" entry (ioctl() interface) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
 	lock_kernel();
-	ov511->proc_control = create_proc_entry("control",
-		S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir);
-	if (!ov511->proc_control) {
+	ov->proc_control = create_proc_entry("control",	S_IFREG|S_IRUGO|S_IWUSR,
+		ov->proc_devdir);
+	if (!ov->proc_control) {
 		unlock_kernel();
 		return;
 	}
-	ov511->proc_control->data = ov511;
-	ov511->proc_control->proc_fops = &ov511_control_fops;
+	ov->proc_control->owner = THIS_MODULE;
+	ov->proc_control->data = ov;
+	ov->proc_control->proc_fops = &ov511_control_fops;
 	unlock_kernel();
 }
 
 static void 
-destroy_proc_ov511_cam(struct usb_ov511 *ov511)
+destroy_proc_ov511_cam(struct usb_ov511 *ov)
 {
-	char dirname[4];
+	char dirname[10];
 	
-	if (!ov511 || !ov511->proc_devdir)
+	if (!ov || !ov->proc_devdir)
 		return;
 
-	sprintf(dirname, "%d", ov511->vdev.minor);
+	snprintf(dirname, 10, "%d", ov->vdev.minor);
 
 	/* Destroy "control" entry */
-	if (ov511->proc_control) {
+	if (ov->proc_control) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname);
-		remove_proc_entry("control", ov511->proc_devdir);
-		ov511->proc_control = NULL;
+		remove_proc_entry("control", ov->proc_devdir);
+		ov->proc_control = NULL;
 	}
 
 	/* Destroy "button" entry */
-	if (ov511->proc_button) {
+	if (ov->proc_button) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname);
-		remove_proc_entry("button", ov511->proc_devdir);
-		ov511->proc_button = NULL;
+		remove_proc_entry("button", ov->proc_devdir);
+		ov->proc_button = NULL;
 	}
 
 	/* Destroy "info" entry */
-	if (ov511->proc_info) {
+	if (ov->proc_info) {
 		PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname);
-		remove_proc_entry("info", ov511->proc_devdir);
-		ov511->proc_info = NULL;
+		remove_proc_entry("info", ov->proc_devdir);
+		ov->proc_info = NULL;
 	}
 
 	/* Destroy per-device directory */
 	PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname);
 	remove_proc_entry(dirname, ov511_proc_entry);
-	ov511->proc_devdir = NULL;
+	ov->proc_devdir = NULL;
 }
 
 static void 
@@ -724,7 +691,7 @@
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write: error %d", rc);
+		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
 
 	return rc;
 }
@@ -746,7 +713,7 @@
 	PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
 	
 	if (rc < 0)
-		err("reg read: error %d", rc);
+		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
 	else
 		rc = ov->cbuf[0];	
 
@@ -805,7 +772,8 @@
 	up(&ov->cbuf_lock);
 
 	if (rc < 0)
-		err("reg write multiple: error %d", rc);
+		err("reg write multiple: error %d: %s", rc,
+		    symbolic(urb_errlist, rc));
 
 	return rc;
 }
@@ -937,21 +905,17 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Write "value" to I2C data port of OV511 */
 	rc = reg_w(ov, R51x_I2C_DATA, value);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 3-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x01);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	return 0;
-
-error:
-	err("ov518 i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly! */
@@ -968,19 +932,19 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Write "value" to I2C data port of OV511 */
 		rc = reg_w(ov, R51x_I2C_DATA, value);	
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Initiate 3-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x01);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
@@ -990,16 +954,11 @@
 #endif
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
 	return 0;
-
-error:
-	err("i2c write: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
@@ -1014,25 +973,21 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x03);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	/* Initiate 2-byte read cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x05);
-	if (rc < 0) goto error;
+	if (rc < 0) return rc;
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
 	return value;
-
-error:
-	err("ov518 i2c read: error %d", rc);
-	return rc;
 }
 
 /* NOTE: Do not call this function directly!
@@ -1046,15 +1001,15 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		/* Initiate 2-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x03);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
@@ -1064,8 +1019,7 @@
 
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
@@ -1073,23 +1027,22 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x05);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		do rc = reg_r(ov, R511_I2C_CTL);
 		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */	
 		rc = reg_w(ov, R511_I2C_CTL, 0x10);
-		if (rc < 0) goto error;
+		if (rc < 0) return rc;
 
 		if (--retries < 0) {
 			err("i2c read retries exhausted");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 	}
 
@@ -1100,13 +1053,9 @@
 	/* This is needed to make i2c_w() work */
 	rc = reg_w(ov, R511_I2C_CTL, 0x05);
 	if (rc < 0)
-		goto error;
+		return rc;
 	
 	return value;
-
-error:
-	err("i2c read: error %d", rc);
-	return rc;
 }
 
 /* returns: negative is error, pos or zero is data */
@@ -1311,22 +1260,17 @@
 	while (pRegvals->bus != OV511_DONE_BUS) {
 		if (pRegvals->bus == OV511_REG_BUS) {
 			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else if (pRegvals->bus == OV511_I2C_BUS) {
 			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-				goto error;
+				return rc;
 		} else {
 			err("Bad regval array");
-			rc = -1;
-			goto error;
+			return -1;
 		}
 		pRegvals++;
 	}
 	return 0;
-
-error:
-	err("write regvals: error %d", rc);
-	return rc;
 }
 
 #ifdef OV511_DEBUG 
@@ -2394,13 +2338,13 @@
 {
 	switch (palette) {
 	case VIDEO_PALETTE_GREY:    return 8;
+	case VIDEO_PALETTE_YUV420:  return 12;
+	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	case VIDEO_PALETTE_RGB565:  return 16;
 	case VIDEO_PALETTE_RGB24:   return 24;  
 	case VIDEO_PALETTE_YUV422:  return 16;
 	case VIDEO_PALETTE_YUYV:    return 16;
-	case VIDEO_PALETTE_YUV420:  return 12;
 	case VIDEO_PALETTE_YUV422P: return 16; /* Planar */
-	case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
 	default:		    return 0;  /* Invalid format */
 	}
 }
@@ -2803,11 +2747,11 @@
 //		/* Here I'm assuming that snapshot size == image size.
 //		 * I hope that's always true. --claudio
 //		 */
-//		pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
-//		lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
+//		pxcnt = sub_flag ? (ov->subw >> 3) - 1 : mlist[i].pxcnt;
+//		lncnt = sub_flag ? (ov->subh >> 3) - 1 : mlist[i].lncnt;
 //
-//		reg_w(ov511, 0x12, pxcnt);
-//		reg_w(ov511, 0x13, lncnt);
+//		reg_w(ov, 0x12, pxcnt);
+//		reg_w(ov, 0x13, lncnt);
 
 		/******** Set the mode ********/		
 
@@ -3475,6 +3419,7 @@
 		int ret = ov->decomp_ops->decomp_400(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
@@ -3483,6 +3428,7 @@
 		int ret = ov->decomp_ops->decomp_420(
 			pIn0,
 			pOut0,
+			frame->compbuf,
 			frame->rawwidth,
 			frame->rawheight,
 			frame->bytes_recvd);
@@ -3682,7 +3628,7 @@
 		memset(frame->data, 0, 
 			MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
 		PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-		memmove(frame->data, frame->rawdata, frame->bytes_recvd);
+		memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
 		return;
 	}
 
@@ -3719,7 +3665,7 @@
 
 	/* Deinterlace frame, if necessary */
 	if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
-		memmove(frame->rawdata, frame->tempdata,
+		memcpy(frame->rawdata, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		deinterlace(frame, RAWFMT_YUV420, frame->rawdata,
 		            frame->tempdata);
@@ -3747,18 +3693,19 @@
 		break;
 	case VIDEO_PALETTE_YUV420:
 	case VIDEO_PALETTE_YUV420P:
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 		break;
 	case VIDEO_PALETTE_YUV422P:
 		/* Data is converted in place, so copy it in advance */
-		memmove(frame->data, frame->tempdata,
+		memcpy(frame->data, frame->tempdata,
 			MAX_RAW_DATA_SIZE(frame->width, frame->height));
 
 		yuv420p_to_yuv422p(frame, frame->data);
 		break;
 	default:
-		err("Cannot convert data to this format");
+		err("Cannot convert data to %s",
+		    symbolic(v4l1_plist, frame->format));
 	}
 
 	if (fix_rgb_offset)
@@ -3771,324 +3718,64 @@
  *
  **********************************************************************/
 
-static int 
-ov511_move_data(struct usb_ov511 *ov, struct urb *urb)
+static inline void 
+ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
 {
-	unsigned char *cdata;
-	int data_size, num, offset, i, totlen = 0;
-	int aPackNum[FRAMES_PER_DESC];
-	struct ov511_frame *frame;
+	int num, offset;
+	int pnum = in[ov->packet_size - 1];		/* Get packet number */
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
 	struct timeval *ts;
 
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
-
-	data_size = ov->packet_size - 1;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
-
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1;
-
-		if (!n || ov->curframe == -1)
-			continue;
-
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
-
-		frame = &ov->frame[ov->curframe];
-
-		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-		 * byte non-zero. The EOF packet has image width/height in the
-		 * 10th and 11th bytes. The 9th byte is given as follows:
-		 *
-		 * bit 7: EOF
-		 *     6: compression enabled
-		 *     5: 422/420/400 modes
-		 *     4: 422/420/400 modes
-		 *     3: 1
-		 *     2: snapshot button on
-		 *     1: snapshot frame
-		 *     0: even/odd field
-		 */
-
-		if (printph) {
-			info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[ov->packet_size - 1],
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* Check for SOF/EOF packet */
-		if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
-		     (~cdata[8] & 0x08))
-			goto check_middle;
-
-		/* Frame end */
-		if (cdata[8] & 0x80) {
-			ts = (struct timeval *)(frame->data 
-			      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-			do_gettimeofday(ts);
-
-			/* Get the actual frame size from the EOF header */
-			frame->rawwidth = ((int)(cdata[9]) + 1) * 8;
-			frame->rawheight = ((int)(cdata[10]) + 1) * 8;
-
-	 		PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d",
-				ov->curframe,
-				(int)(cdata[ov->packet_size - 1]),
-				frame->rawwidth,
-				frame->rawheight,
-				frame->bytes_recvd);
-
-			/* Validate the header data */
-			RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-			RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-			/* Don't allow byte count to exceed buffer size */
-			RESTRICT_TO_RANGE(frame->bytes_recvd,
-					  8, 
-					  MAX_RAW_DATA_SIZE(ov->maxwidth,
-					                    ov->maxheight));
-
-			if (frame->scanstate == STATE_LINES) {
-		    		int iFrameNext;
-
-				frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
-
-				if (waitqueue_active(&frame->wq)) {
-					frame->grabstate = FRAME_DONE;
-					wake_up_interruptible(&frame->wq);
-				}
-
-				/* If next frame is ready or grabbing,
-                                 * point to it */
-				iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-				if (ov->frame[iFrameNext].grabstate == FRAME_READY
-				    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-					ov->curframe = iFrameNext;
-					ov->frame[iFrameNext].scanstate = STATE_SCANNING;
-				} else {
-					if (frame->grabstate == FRAME_DONE) {
-						PDEBUG(4, "Frame done! congratulations");
-					} else {
-						PDEBUG(4, "Frame not ready? state = %d",
-							ov->frame[iFrameNext].grabstate);
-					}
-
-					ov->curframe = -1;
-				}
-			} else {
-				PDEBUG(5, "Frame done, but not scanning");
-			}
-			/* Image corruption caused by misplaced frame->segment = 0
-			 * fixed by carlosf@conectiva.com.br
-			 */
-		} else {
-			/* Frame start */
-			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-			/* Check to see if it's a snapshot frame */
-			/* FIXME?? Should the snapshot reset go here? Performance? */
-			if (cdata[8] & 0x02) {
-				frame->snapshot = 1;
-				PDEBUG(3, "snapshot detected");
-			}
-
-			frame->scanstate = STATE_LINES;
-			frame->bytes_recvd = 0;
-			frame->compressed = cdata[8] & 0x40;
-		}
-
-check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(5, "Not in a frame; packet skipped");
-			continue;
-		}
-
-#if 0
-		/* Skip packet if first 9 bytes are zero. These are common, so
-		 * we use a less expensive test here instead of later */
-		if (frame->compressed) {
-			int b, skip = 1;
-
-			for (b = 0; b < 9; b++) { 
-				if (cdata[b])
-					skip=0;
-			}
-
-			if (skip) {
-				PDEBUG(5, "Skipping packet (all zero)");
-				continue;
-			}
-		}
-#endif
-		/* If frame start, skip header */
-		if (frame->bytes_recvd == 0)
-			offset = 9;
-		else
-			offset = 0;
-
-		num = n - offset - 1;
-
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n - 1;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - (n - 1),
-					&cdata[0], n - 1);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else if (!frame->compressed && !remove_zeros) {
-			frame->bytes_recvd += num;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - num,
-					&cdata[offset], num);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-			int b, in = 0, allzero, copied=0;
-			if (offset) {
-				frame->bytes_recvd += 32 - offset;	// Bytes out
-				memmove(frame->rawdata,
-					&cdata[offset], 32 - offset);
-				in += 32;
-			}
-
-			while (in < n - 1) {
-				allzero = 1;
-				for (b = 0; b < 32; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
-				}
-
-				if (allzero) {
-					/* Don't copy it */
-				} else {
-					if (frame->bytes_recvd + copied + 32
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 32);
-						copied += 32;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
-				}
-				in += 32;
-			}
-
-			frame->bytes_recvd += copied;
-		}
+	/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+	 * byte non-zero. The EOF packet has image width/height in the
+	 * 10th and 11th bytes. The 9th byte is given as follows:
+	 *
+	 * bit 7: EOF
+	 *     6: compression enabled
+	 *     5: 422/420/400 modes
+	 *     4: 422/420/400 modes
+	 *     3: 1
+	 *     2: snapshot button on
+	 *     1: snapshot frame
+	 *     0: even/odd field
+	 */
 
+	if (printph) {
+		info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+		     pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+		     in[7], in[8], in[9], in[10], in[11]);
 	}
 
-	PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
-		aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
-		aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
-
-	return totlen;
-}
-
-static int 
-ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
-{
-	unsigned char *cdata;
-	int i, data_size, totlen = 0;
-	struct ov511_frame *frame;
-	struct timeval *ts;
-
-	PDEBUG(5, "Moving %d packets", urb->number_of_packets);
-
-	/* OV518(+) has no packet numbering */
-	data_size = ov->packet_size;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		int n = urb->iso_frame_desc[i].actual_length;
-		int st = urb->iso_frame_desc[i].status;
-
-		urb->iso_frame_desc[i].actual_length = 0;
-		urb->iso_frame_desc[i].status = 0;
-
-		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-		if (!n) {
-			PDEBUG(4, "Zero-length packet");
-			continue;
-		}
-
-		if (ov->curframe == -1) {
-			PDEBUG(4, "No frame currently active");
-			continue;
-		}
-
-		if (st)
-			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
-
-		frame = &ov->frame[ov->curframe];
-
-		if (printph) {
-			info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-				cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
-				cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
-		}
-
-		/* A false positive here is likely, until OVT gives me
-		 * the definitive SOF/EOF format */
-		if ((!(cdata[0] | cdata[1] | cdata[2] | cdata[3] |
-		      cdata[5])) && cdata[6]) {
-			
-			if (frame->scanstate == STATE_LINES) {
-				PDEBUG(4, "Detected frame end/start");
-				goto eof;
-			} else { //scanstate == STATE_SCANNING
-				/* Frame start */
-				PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-				goto sof;
-			}
-		} else {
-			goto check_middle;
-		}
-	
-eof:
-		ts = (struct timeval *)(frame->data
+	/* Check for SOF/EOF packet */
+	if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
+	    (~in[8] & 0x08))
+		goto check_middle;
+
+	/* Frame end */
+	if (in[8] & 0x80) {
+		ts = (struct timeval *)(frame->data 
 		      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
 		do_gettimeofday(ts);
 
- 		PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-			ov->curframe,
-			(int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd);
-
-		// FIXME: Since we don't know the header formats yet,
-		// there is no way to know what the actual image size is
-		frame->rawwidth = frame->width;
-		frame->rawheight = frame->height;
+		/* Get the actual frame size from the EOF header */
+		frame->rawwidth = ((int)(in[9]) + 1) * 8;
+		frame->rawheight = ((int)(in[10]) + 1) * 8;
+
+ 		PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
+			ov->curframe, pnum, frame->rawwidth, frame->rawheight,
+			frame->bytes_recvd);
 
 		/* Validate the header data */
 		RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+		RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
+				  ov->maxheight);
 
 		/* Don't allow byte count to exceed buffer size */
-		RESTRICT_TO_RANGE(frame->bytes_recvd,
-				  8, 
-				  MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
 		if (frame->scanstate == STATE_LINES) {
-	    		int iFrameNext;
+	    		int nextf;
 
 			frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
 
@@ -4099,115 +3786,277 @@
 
 			/* If next frame is ready or grabbing,
 			 * point to it */
-			iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
-			if (ov->frame[iFrameNext].grabstate == FRAME_READY
-			    || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
-				ov->curframe = iFrameNext;
-				ov->frame[iFrameNext].scanstate = STATE_SCANNING;
-				frame = &ov->frame[iFrameNext];
+			nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+			if (ov->frame[nextf].grabstate == FRAME_READY
+			    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+				ov->curframe = nextf;
+				ov->frame[nextf].scanstate = STATE_SCANNING;
 			} else {
 				if (frame->grabstate == FRAME_DONE) {
-					PDEBUG(4, "Frame done! congratulations");
+					PDEBUG(4, "** Frame done **");
 				} else {
 					PDEBUG(4, "Frame not ready? state = %d",
-						ov->frame[iFrameNext].grabstate);
+						ov->frame[nextf].grabstate);
 				}
 
 				ov->curframe = -1;
-				PDEBUG(4, "SOF dropped (no active frame)");
-				continue;  /* Nowhere to store this frame */
 			}
+		} else {
+			PDEBUG(5, "Frame done, but not scanning");
 		}
 		/* Image corruption caused by misplaced frame->segment = 0
 		 * fixed by carlosf@conectiva.com.br
 		 */
-sof:
-		PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-// Snapshot not reverse-engineered yet.
-#if 0
+	} else {
+		/* Frame start */
+		PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+
 		/* Check to see if it's a snapshot frame */
 		/* FIXME?? Should the snapshot reset go here? Performance? */
-		if (cdata[8] & 0x02) {
+		if (in[8] & 0x02) {
 			frame->snapshot = 1;
 			PDEBUG(3, "snapshot detected");
 		}
-#endif
+
 		frame->scanstate = STATE_LINES;
 		frame->bytes_recvd = 0;
-//		frame->compressed = 1;
+		frame->compressed = in[8] & 0x40;
+	}
 
 check_middle:
-		/* Are we in a frame? */
-		if (frame->scanstate != STATE_LINES) {
-			PDEBUG(4, "scanstate: no SOF yet");
-			continue;
-		}
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(5, "Not in a frame; packet skipped");
+		return;
+	}
 
-		/* Dump all data exactly as received */
-		if (dumppix == 2) {
-			frame->bytes_recvd += n;
-			if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
-				memmove(frame->rawdata + frame->bytes_recvd - n,
-					&cdata[0], n);
-			else
-				PDEBUG(3, "Raw data buffer overrun!! (%d)",
-					frame->bytes_recvd
-					- MAX_RAW_DATA_SIZE(ov->maxwidth,
-							    ov->maxheight));
-		} else {
-			/* All incoming data are divided into 8-byte segments. If the
-			 * segment contains all zero bytes, it must be skipped. These
-			 * zero-segments allow the OV518 to mainain a constant data rate
-			 * regardless of the effectiveness of the compression. Segments
-			 * are aligned relative to the beginning of each isochronous
-			 * packet. The first segment is a header (the decompressor
-			 * skips it later).
-			 */
-
-			int b, in = 0, allzero, copied=0;
-
-			while (in < n) {
-				allzero = 1;
-				for (b = 0; b < 8; b++) {
-					if (cdata[in + b]) {
-						allzero = 0;
-						break;
-					}
+	/* If frame start, skip header */
+	if (frame->bytes_recvd == 0)
+		offset = 9;
+	else
+		offset = 0;
+
+	num = n - offset - 1;
+
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n - 1;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
+				in, n - 1);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else if (!frame->compressed && !remove_zeros) {
+		frame->bytes_recvd += num;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - num,
+				in + offset, num);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
+		int b, read = 0, allzero, copied = 0;
+		if (offset) {
+			frame->bytes_recvd += 32 - offset;	// Bytes out
+			memcpy(frame->rawdata,	in + offset, 32 - offset);
+			read += 32;
+		}
+
+		while (read < n - 1) {
+			allzero = 1;
+			for (b = 0; b < 32; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
 				}
+			}
 
-				if (allzero) {
+			if (allzero) {
 				/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 32 <= max_raw)
+				{
+					memcpy(frame->rawdata
+						+ frame->bytes_recvd + copied,
+						in + read, 32);
+					copied += 32;
 				} else {
-					if (frame->bytes_recvd + copied + 8
-					    <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
-						memmove(frame->rawdata + frame->bytes_recvd + copied,
-							&cdata[in], 8);
-						copied += 8;
-					} else {
-						PDEBUG(3, "Raw data buffer overrun!!");
-					}
+					PDEBUG(3, "Raw data buffer overrun!!");
 				}
-				in += 8;
 			}
-			frame->bytes_recvd += copied;
+			read += 32;
 		}
-	}
 
-	return totlen;
+		frame->bytes_recvd += copied;
+	}
 }
 
-static void 
+static inline void 
+ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+	int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+	struct ov511_frame *frame = &ov->frame[ov->curframe];
+	struct timeval *ts;
+
+	if (printph) {
+		info("ph: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+		     in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7],
+		     in[8], in[9], in[10], in[11]);
+	}
+
+	/* A false positive here is likely, until OVT gives me
+	 * the definitive SOF/EOF format */
+	if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
+		if (frame->scanstate == STATE_LINES) {
+			PDEBUG(4, "Detected frame end/start");
+			goto eof;
+		} else { //scanstate == STATE_SCANNING
+			/* Frame start */
+			PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+			goto sof;
+		}
+	} else {
+		goto check_middle;
+	}
+
+eof:
+	ts = (struct timeval *)(frame->data
+	      + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+	do_gettimeofday(ts);
+
+	PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
+		ov->curframe,
+		(int)(in[9]), (int)(in[10]), frame->bytes_recvd);
+
+	// FIXME: Since we don't know the header formats yet,
+	// there is no way to know what the actual image size is
+	frame->rawwidth = frame->width;
+	frame->rawheight = frame->height;
+
+	/* Validate the header data */
+	RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+	RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+
+	/* Don't allow byte count to exceed buffer size */
+	RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+	if (frame->scanstate == STATE_LINES) {
+    		int nextf;
+
+		frame->grabstate = FRAME_DONE;	// FIXME: Is this right?
+
+		if (waitqueue_active(&frame->wq)) {
+			frame->grabstate = FRAME_DONE;
+			wake_up_interruptible(&frame->wq);
+		}
+
+		/* If next frame is ready or grabbing,
+		 * point to it */
+		nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+		if (ov->frame[nextf].grabstate == FRAME_READY
+		    || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+			ov->curframe = nextf;
+			ov->frame[nextf].scanstate = STATE_SCANNING;
+			frame = &ov->frame[nextf];
+		} else {
+			if (frame->grabstate == FRAME_DONE) {
+				PDEBUG(4, "** Frame done **");
+			} else {
+				PDEBUG(4, "Frame not ready? state = %d",
+				       ov->frame[nextf].grabstate);
+			}
+
+			ov->curframe = -1;
+			PDEBUG(4, "SOF dropped (no active frame)");
+			return;  /* Nowhere to store this frame */
+		}
+	}
+sof:
+	PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+
+// Snapshot not reverse-engineered yet.
+#if 0
+	/* Check to see if it's a snapshot frame */
+	/* FIXME?? Should the snapshot reset go here? Performance? */
+	if (in[8] & 0x02) {
+		frame->snapshot = 1;
+		PDEBUG(3, "snapshot detected");
+	}
+#endif
+	frame->scanstate = STATE_LINES;
+	frame->bytes_recvd = 0;
+//		frame->compressed = 1;
+
+check_middle:
+	/* Are we in a frame? */
+	if (frame->scanstate != STATE_LINES) {
+		PDEBUG(4, "scanstate: no SOF yet");
+		return;
+	}
+
+	/* Dump all data exactly as received */
+	if (dumppix == 2) {
+		frame->bytes_recvd += n;
+		if (frame->bytes_recvd <= max_raw)
+			memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
+		else
+			PDEBUG(3, "Raw data buffer overrun!! (%d)",
+				frame->bytes_recvd - max_raw);
+	} else {
+		/* All incoming data are divided into 8-byte segments. If the
+		 * segment contains all zero bytes, it must be skipped. These
+		 * zero-segments allow the OV518 to mainain a constant data rate
+		 * regardless of the effectiveness of the compression. Segments
+		 * are aligned relative to the beginning of each isochronous
+		 * packet. The first segment is a header (the decompressor
+		 * skips it later).
+		 */
+
+		int b, read = 0, allzero, copied = 0;
+
+		while (read < n) {
+			allzero = 1;
+			for (b = 0; b < 8; b++) {
+				if (in[read + b]) {
+					allzero = 0;
+					break;
+				}
+			}
+
+			if (allzero) {
+			/* Don't copy it */
+			} else {
+				if (frame->bytes_recvd + copied + 8 <= max_raw)
+				{
+					memcpy(frame->rawdata 
+						+ frame->bytes_recvd + copied,
+						in + read, 8);
+					copied += 8;
+				} else {
+					PDEBUG(3, "Raw data buffer overrun!!");
+				}
+			}
+			read += 8;
+		}
+		frame->bytes_recvd += copied;
+	}
+}
+
+static void 
 ov51x_isoc_irq(struct urb *urb)
 {
-	int len;
+	int i;
 	struct usb_ov511 *ov;
+	struct ov511_sbuf *sbuf;
 
 	if (!urb->context) {
 		PDEBUG(4, "no context");
 		return;
 	}
 
-	ov = (struct usb_ov511 *) urb->context;
+	sbuf = urb->context;
+	ov = sbuf->ov;
 
 	if (!ov || !ov->dev || !ov->user) {
 		PDEBUG(4, "no device, or not open");
@@ -4219,16 +4068,52 @@
 		return;
 	}
 
+        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+                PDEBUG(4, "URB unlinked");
+                return;
+        }
+
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		err("ERROR: urb->status=%d: %s", urb->status,
+		    symbolic(urb_errlist, urb->status));
+		return;
+	}
+
 	/* Copy the data received into our frame buffer */
-	if (ov->curframe >= 0) {
-		if (ov->bclass == BCL_OV511)
-			len = ov511_move_data(ov, urb);
-		else if (ov->bclass == BCL_OV518)
-			len = ov518_move_data(ov, urb);
-		else
-			err("Unknown bridge device (%d)", ov->bridge);
-	} else if (waitqueue_active(&ov->wq)) {
-		wake_up_interruptible(&ov->wq);
+	PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
+	       urb->number_of_packets);
+	for (i = 0; i < urb->number_of_packets; i++) {
+		/* Warning: Don't call *_move_data() if no frame active! */
+		if (ov->curframe >= 0) {
+			int n = urb->iso_frame_desc[i].actual_length;
+			int st = urb->iso_frame_desc[i].status;
+			unsigned char *cdata;
+
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = 0;
+
+			cdata = urb->transfer_buffer
+				+ urb->iso_frame_desc[i].offset;
+
+			if (!n) {
+				PDEBUG(4, "Zero-length packet");
+				continue;
+			}
+
+			if (st)
+				PDEBUG(2, "data error: [%d] len=%d, status=%d",
+				       i, n, st);
+
+			if (ov->bclass == BCL_OV511)
+				ov511_move_data(ov, cdata, n);
+			else if (ov->bclass == BCL_OV518)
+				ov518_move_data(ov, cdata, n);
+			else
+				err("Unknown bridge device (%d)", ov->bridge);
+
+		} else if (waitqueue_active(&ov->wq)) {
+			wake_up_interruptible(&ov->wq);
+		}
 	}
 
 	urb->dev = ov->dev;
@@ -4297,14 +4182,13 @@
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-	
 		if (!urb) {
 			err("init isoc: usb_alloc_urb ret. NULL");
 			return -ENOMEM;
 		}
 		ov->sbuf[n].urb = urb;
 		urb->dev = ov->dev;
-		urb->context = ov;
+		urb->context = &ov->sbuf[n];
 		urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = ov->sbuf[n].data;
@@ -4334,10 +4218,23 @@
 }
 
 static void 
-ov51x_stop_isoc(struct usb_ov511 *ov)
+ov51x_unlink_isoc(struct usb_ov511 *ov)
 {
 	int n;
 
+	/* Unschedule all of the iso td's */
+	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
+		if (ov->sbuf[n].urb) {
+			usb_unlink_urb(ov->sbuf[n].urb);
+			usb_free_urb(ov->sbuf[n].urb);
+			ov->sbuf[n].urb = NULL;
+		}
+	}
+}
+
+static void 
+ov51x_stop_isoc(struct usb_ov511 *ov)
+{
 	if (!ov->streaming || !ov->dev)
 		return;
 
@@ -4347,15 +4244,7 @@
 
 	ov->streaming = 0;
 
-	/* Unschedule all of the iso td's */
-	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov->sbuf[n].urb);
-			usb_free_urb(ov->sbuf[n].urb);
-			ov->sbuf[n].urb = NULL;
-		}
-	}
+	ov51x_unlink_isoc(ov);
 }
 
 static int 
@@ -4409,6 +4298,55 @@
  *
  ***************************************************************************/
 
+/* 
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void 
+ov51x_do_dealloc(struct usb_ov511 *ov)
+{
+	int i;
+	PDEBUG(4, "entered");
+
+	if (ov->fbuf) {
+		rvfree(ov->fbuf, OV511_NUMFRAMES
+		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+		ov->fbuf = NULL;
+	}
+
+	if (ov->rawfbuf) {
+		vfree(ov->rawfbuf);
+		ov->rawfbuf = NULL;
+	}
+
+	if (ov->tempfbuf) {
+		vfree(ov->tempfbuf);
+		ov->tempfbuf = NULL;
+	}
+
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		if (ov->sbuf[i].data) {
+			kfree(ov->sbuf[i].data);
+			ov->sbuf[i].data = NULL;
+		}
+	}
+
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		ov->frame[i].data = NULL;
+		ov->frame[i].rawdata = NULL;
+		ov->frame[i].tempdata = NULL;
+		if (ov->frame[i].compbuf) {
+			free_page((unsigned long) ov->frame[i].compbuf);
+			ov->frame[i].compbuf = NULL;
+		}
+	}
+
+	PDEBUG(4, "buffer memory deallocated");
+	ov->buf_state = BUF_NOT_ALLOCATED;
+	PDEBUG(4, "leaving");
+}
+
 static int 
 ov51x_alloc(struct usb_ov511 *ov)
 {
@@ -4434,40 +4372,23 @@
 		goto error;
 
 	ov->rawfbuf = vmalloc(raw_bufsize);
-	if (!ov->rawfbuf) {
-		rvfree(ov->fbuf, data_bufsize);
-		ov->fbuf = NULL;
+	if (!ov->rawfbuf)
 		goto error;
-	}
+
 	memset(ov->rawfbuf, 0, raw_bufsize);
 
 	ov->tempfbuf = vmalloc(raw_bufsize);
-	if (!ov->tempfbuf) {
-		vfree(ov->rawfbuf);
-		ov->rawfbuf = NULL;
-		rvfree(ov->fbuf, data_bufsize);
-		ov->fbuf = NULL;
+	if (!ov->tempfbuf)
 		goto error;
-	}
+
 	memset(ov->tempfbuf, 0, raw_bufsize);
 
 	for (i = 0; i < OV511_NUMSBUF; i++) {
 		ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
 			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-		if (!ov->sbuf[i].data) {
-			while (--i) {
-				kfree(ov->sbuf[i].data);
-				ov->sbuf[i].data = NULL;
-			}
-			vfree(ov->tempfbuf);
-			ov->tempfbuf = NULL;
-			vfree(ov->rawfbuf);
-			ov->rawfbuf = NULL;
-			rvfree(ov->fbuf, data_bufsize);
-			ov->fbuf = NULL;
-
+		if (!ov->sbuf[i].data)
 			goto error;
-		}
+
 		PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
 	}
 
@@ -4477,6 +4398,12 @@
 		 + i * MAX_RAW_DATA_SIZE(w, h);
 		ov->frame[i].tempdata = ov->tempfbuf 
 		 + i * MAX_RAW_DATA_SIZE(w, h);
+
+		ov->frame[i].compbuf = 
+		 (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (!ov->frame[i].compbuf)
+			goto error;
+
 		PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
 	}
 
@@ -4486,57 +4413,12 @@
 	PDEBUG(4, "leaving");
 	return 0;
 error:
-	ov->buf_state = BUF_NOT_ALLOCATED;
+	ov51x_do_dealloc(ov);
 	up(&ov->buf_lock);
 	PDEBUG(4, "errored");
 	return -ENOMEM;
 }
 
-/* 
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void 
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
-	int i;
-	PDEBUG(4, "entered");
-
-	if (ov->fbuf) {
-		rvfree(ov->fbuf, OV511_NUMFRAMES
-		       * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-		ov->fbuf = NULL;
-	}
-
-	if (ov->rawfbuf) {
-		vfree(ov->rawfbuf);
-		ov->rawfbuf = NULL;
-	}
-
-	if (ov->tempfbuf) {
-		vfree(ov->tempfbuf);
-		ov->tempfbuf = NULL;
-	}
-
-	for (i = 0; i < OV511_NUMSBUF; i++) {
-		if (ov->sbuf[i].data) {
-			kfree(ov->sbuf[i].data);
-			ov->sbuf[i].data = NULL;
-		}
-	}
-
-	for (i = 0; i < OV511_NUMFRAMES; i++) {
-		ov->frame[i].data = NULL;
-		ov->frame[i].rawdata = NULL;
-		ov->frame[i].tempdata = NULL;
-	}
-
-	PDEBUG(4, "buffer memory deallocated");
-	ov->buf_state = BUF_NOT_ALLOCATED;
-	PDEBUG(4, "leaving");
-}
-
 static void 
 ov51x_buf_callback(unsigned long data)
 {
@@ -4585,9 +4467,16 @@
  *
  ***************************************************************************/
 
+#ifdef OV511_OLD_V4L
 static int 
 ov51x_v4l1_open(struct video_device *vdev, int flags)
 {
+#else
+static int 
+ov51x_v4l1_open(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+#endif
 	struct usb_ov511 *ov = vdev->priv;
 	int err, i;
 
@@ -4639,9 +4528,16 @@
 	return err;
 }
 
+#ifdef OV511_OLD_V4L
 static void 
 ov51x_v4l1_close(struct video_device *vdev)
 {
+#else
+static int 
+ov51x_v4l1_close(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+#endif
 	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
@@ -4674,32 +4570,19 @@
 		kfree(ov);
 		ov = NULL;
 	}
-}
-
-static int 
-ov51x_v4l1_init_done(struct video_device *vdev)
-{
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-	create_proc_ov511_cam(vdev->priv);
-#endif
 
+#ifdef OV511_OLD_V4L
+	return;
+#else
 	return 0;
-}
-
-static long 
-ov51x_v4l1_write(struct video_device *vdev, const char *buf,
-		 unsigned long count, int noblock)
-{
-	return -EINVAL;
+#endif
 }
 
 /* Do not call this function directly! */
 static int 
-ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
+ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
 			  void *arg)
 {
-	struct usb_ov511 *ov = vdev->priv;
-
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
 	if (!ov->dev)
@@ -4708,95 +4591,79 @@
 	switch (cmd) {
 	case VIDIOCGCAP:
 	{
-		struct video_capability b;
+		struct video_capability *b = arg;
 
 		PDEBUG(4, "VIDIOCGCAP");
 
-		memset(&b, 0, sizeof(b));
-		sprintf(b.name, "%s USB Camera",
-			ov->bridge == BRG_OV511 ? "OV511" :
-			ov->bridge == BRG_OV511PLUS ? "OV511+" :
-			ov->bridge == BRG_OV518 ? "OV518" :
-			ov->bridge == BRG_OV518PLUS ? "OV518+" :
-			"unknown");
-		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		memset(b, 0, sizeof(struct video_capability));
+		sprintf(b->name, "%s USB Camera",
+			symbolic(brglist, ov->bridge));
+		b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
 		if (ov->has_tuner)
-			b.type |= VID_TYPE_TUNER;
-		b.channels = ov->num_inputs;
-		b.audios = ov->has_audio_proc ? 1:0;
-		b.maxwidth = ov->maxwidth;
-		b.maxheight = ov->maxheight;
-		b.minwidth = ov->minwidth;
-		b.minheight = ov->minheight;
+			b->type |= VID_TYPE_TUNER;
+		b->channels = ov->num_inputs;
+		b->audios = ov->has_audio_proc ? 1:0;
+		b->maxwidth = ov->maxwidth;
+		b->maxheight = ov->maxheight;
+		b->minwidth = ov->minwidth;
+		b->minheight = ov->minheight;
 
-		if (copy_to_user(arg, &b, sizeof(b)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCGCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 
 		PDEBUG(4, "VIDIOCGCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		v.norm = ov->norm;
-		v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
-		v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
-		v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
-//		v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-		v.tuners = (ov->has_tuner) ? 1:0;
-		decoder_get_input_name(ov, v.channel, v.name);
+		v->norm = ov->norm;
+		v->type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
+		v->flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
+		v->flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
+//		v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+		v->tuners = (ov->has_tuner) ? 1:0;
+		decoder_get_input_name(ov, v->channel, v->name);
 
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-				
 		return 0;
 	}
 	case VIDIOCSCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 		int err;
 
 		PDEBUG(4, "VIDIOCSCHAN");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
 		/* Make sure it's not a camera */
 		if (!ov->has_decoder) {
-			if (v.channel == 0)
+			if (v->channel == 0)
 				return 0;
 			else
 				return -EINVAL;
 		}
 
-		if (v.norm != VIDEO_MODE_PAL &&
-		    v.norm != VIDEO_MODE_NTSC &&
-		    v.norm != VIDEO_MODE_SECAM &&
-		    v.norm != VIDEO_MODE_AUTO) {
-			err("Invalid norm (%d)", v.norm);
+		if (v->norm != VIDEO_MODE_PAL &&
+		    v->norm != VIDEO_MODE_NTSC &&
+		    v->norm != VIDEO_MODE_SECAM &&
+		    v->norm != VIDEO_MODE_AUTO) {
+			err("Invalid norm (%d)", v->norm);
 			return -EINVAL;
 		}
 
-		if ((unsigned)(v.channel) >= ov->num_inputs) {
-			err("Invalid channel (%d)", v.channel);
+		if ((unsigned)(v->channel) >= ov->num_inputs) {
+			err("Invalid channel (%d)", v->channel);
 			return -EINVAL;
 		}
 
-		err = decoder_set_input(ov, v.channel);
+		err = decoder_set_input(ov, v->channel);
 		if (err)
 			return err;
 
-		err = decoder_set_norm(ov, v.norm);
+		err = decoder_set_norm(ov, v->norm);
 		if (err)
 			return err;
 
@@ -4804,43 +4671,37 @@
 	}
 	case VIDIOCGPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 
 		PDEBUG(4, "VIDIOCGPICT");
 
-		memset(&p, 0, sizeof(p));
-
-		if (sensor_get_picture(ov, &p))
+		memset(p, 0, sizeof(struct video_picture));
+		if (sensor_get_picture(ov, p))
 			return -EIO;
 
-		if (copy_to_user(arg, &p, sizeof(p)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCSPICT:
 	{
-		struct video_picture p;
+		struct video_picture *p = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCSPICT");
 
-		if (copy_from_user(&p, arg, sizeof(p)))
-			return -EFAULT;
-
-		if (!get_depth(p.palette))
+		if (!get_depth(p->palette))
 			return -EINVAL;
 
-		if (sensor_set_picture(ov, &p))
+		if (sensor_set_picture(ov, p))
 			return -EIO;
 
-		if (force_palette && p.palette != force_palette) {
-			info("Palette rejected (%d)", p.palette);
+		if (force_palette && p->palette != force_palette) {
+			info("Palette rejected (%s)",
+			     symbolic(v4l1_plist, p->palette));
 			return -EINVAL;
 		}
 
 		// FIXME: Format should be independent of frames
-		if (p.palette != ov->frame[0].format) {
+		if (p->palette != ov->frame[0].format) {
 			PDEBUG(4, "Detected format change");
 
 			/* If we're collecting previous frame wait
@@ -4849,79 +4710,73 @@
 			if (signal_pending(current)) return -EINTR;
 
 			mode_init_regs(ov, ov->frame[0].width,
-				ov->frame[0].height, p.palette, ov->sub_flag);
+				ov->frame[0].height, p->palette, ov->sub_flag);
 		}
 
-		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
+		PDEBUG(4, "Setting depth=%d, palette=%s",
+		       p->depth, symbolic(v4l1_plist, p->palette));
+
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].depth = p.depth;
-			ov->frame[i].format = p.palette;
+			ov->frame[i].depth = p->depth;
+			ov->frame[i].format = p->palette;
 		}
 
 		return 0;
 	}
 	case VIDIOCGCAPTURE:
 	{
-		int vf;
+		int *vf = arg;
 
 		PDEBUG(4, "VIDIOCGCAPTURE");
 
-		if (copy_from_user(&vf, arg, sizeof(vf)))
-			return -EFAULT;
-		ov->sub_flag = vf;
+		ov->sub_flag = *vf;
 		return 0;
 	}
 	case VIDIOCSCAPTURE:
 	{
-		struct video_capture vc;
+		struct video_capture *vc = arg;
 
 		PDEBUG(4, "VIDIOCSCAPTURE");
 
-		if (copy_from_user(&vc, arg, sizeof(vc)))
-			return -EFAULT;
-		if (vc.flags)
+		if (vc->flags)
 			return -EINVAL;
-		if (vc.decimation)
+		if (vc->decimation)
 			return -EINVAL;
 
-		vc.x &= ~3L;
-		vc.y &= ~1L;
-		vc.y &= ~31L;
-
-		if (vc.width == 0)
-			vc.width = 32;
-
-		vc.height /= 16;
-		vc.height *= 16;
-		if (vc.height == 0)
-			vc.height = 16;
-
-		ov->subx = vc.x;
-		ov->suby = vc.y;
-		ov->subw = vc.width;
-		ov->subh = vc.height;
+		vc->x &= ~3L;
+		vc->y &= ~1L;
+		vc->y &= ~31L;
+
+		if (vc->width == 0)
+			vc->width = 32;
+
+		vc->height /= 16;
+		vc->height *= 16;
+		if (vc->height == 0)
+			vc->height = 16;
+
+		ov->subx = vc->x;
+		ov->suby = vc->y;
+		ov->subw = vc->width;
+		ov->subh = vc->height;
 
 		return 0;
 	}
 	case VIDIOCSWIN:
 	{
-		struct video_window vw;
+		struct video_window *vw = arg;
 		int i, result;
 
-		if (copy_from_user(&vw, arg, sizeof(vw)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
-			vw.width, vw.height);
+		PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
 
 #if 0
-		if (vw.flags)
+		if (vw->flags)
 			return -EINVAL;
-		if (vw.clipcount)
+		if (vw->clipcount)
 			return -EINVAL;
-		if (vw.height != ov->maxheight)
+		if (vw->height != ov->maxheight)
 			return -EINVAL;
-		if (vw.width != ov->maxwidth)
+		if (vw->width != ov->maxwidth)
 			return -EINVAL;
 #endif
 
@@ -4930,140 +4785,132 @@
 		interruptible_sleep_on(&ov->wq);
 		if (signal_pending(current)) return -EINTR;
 
-		result = mode_init_regs(ov, vw.width, vw.height,
+		result = mode_init_regs(ov, vw->width, vw->height,
 			ov->frame[0].format, ov->sub_flag);
 		if (result < 0)
 			return result;
 
 		for (i = 0; i < OV511_NUMFRAMES; i++) {
-			ov->frame[i].width = vw.width;
-			ov->frame[i].height = vw.height;
+			ov->frame[i].width = vw->width;
+			ov->frame[i].height = vw->height;
 		}
 
 		return 0;
 	}
 	case VIDIOCGWIN:
 	{
-		struct video_window vw;
+		struct video_window *vw = arg;
 
-		memset(&vw, 0, sizeof(vw));
-		vw.x = 0;		/* FIXME */
-		vw.y = 0;
-		vw.width = ov->frame[0].width;
-		vw.height = ov->frame[0].height;
-		vw.flags = 30;
+		memset(vw, 0, sizeof(struct video_window));
+		vw->x = 0;		/* FIXME */
+		vw->y = 0;
+		vw->width = ov->frame[0].width;
+		vw->height = ov->frame[0].height;
+		vw->flags = 30;
 
-		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
-
-		if (copy_to_user(arg, &vw, sizeof(vw)))
-			return -EFAULT;
+		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
 
 		return 0;
 	}
 	case VIDIOCGMBUF:
 	{
-		struct video_mbuf vm;
+		struct video_mbuf *vm = arg;
 		int i;
 
 		PDEBUG(4, "VIDIOCGMBUF");
 
-		memset(&vm, 0, sizeof(vm));
-		vm.size = OV511_NUMFRAMES
-			* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-		vm.frames = OV511_NUMFRAMES;
+		memset(vm, 0, sizeof(struct video_mbuf));
+		vm->size = OV511_NUMFRAMES
+			   * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+		vm->frames = OV511_NUMFRAMES;
 
-		vm.offsets[0] = 0;
+		vm->offsets[0] = 0;
 		for (i = 1; i < OV511_NUMFRAMES; i++) {
-			vm.offsets[i] = vm.offsets[i-1]
+			vm->offsets[i] = vm->offsets[i-1]
 			   + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
 		}
 
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCMCAPTURE:
 	{
-		struct video_mmap vm;
+		struct video_mmap *vm = arg;
 		int ret, depth;
+		unsigned int f = vm->frame;
 
-		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-			return -EFAULT;
-
-		PDEBUG(4, "CMCAPTURE");
-		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
-			vm.frame, vm.width, vm.height, vm.format);
+		PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
+			vm->height, symbolic(v4l1_plist, vm->format));
 
-		depth = get_depth(vm.format);
+		depth = get_depth(vm->format);
 		if (!depth) {
-			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
+			err("VIDIOCMCAPTURE: invalid format (%s)",
+			    symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
-			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
+		if (f >= OV511_NUMFRAMES) {
+			err("VIDIOCMCAPTURE: invalid frame (%d)", f);
 			return -EINVAL;
 		}
 
-		if (vm.width > ov->maxwidth 
-		    || vm.height > ov->maxheight) {
+		if (vm->width > ov->maxwidth 
+		    || vm->height > ov->maxheight) {
 			err("VIDIOCMCAPTURE: requested dimensions too big");
 			return -EINVAL;
 		}
 
-		if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) {
+		if (ov->frame[f].grabstate == FRAME_GRABBING) {
 			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
 			return -EBUSY;
 		}
 
-		if (force_palette && vm.format != force_palette) {
-			info("palette rejected (%d)", vm.format);
+		if (force_palette && (vm->format != force_palette)) {
+			info("palette rejected (%s)",
+			     symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
-		if ((ov->frame[vm.frame].width != vm.width) ||
-		    (ov->frame[vm.frame].height != vm.height) ||
-		    (ov->frame[vm.frame].format != vm.format) ||
-		    (ov->frame[vm.frame].sub_flag != ov->sub_flag) ||
-		    (ov->frame[vm.frame].depth != depth)) {
+		if ((ov->frame[f].width != vm->width) ||
+		    (ov->frame[f].height != vm->height) ||
+		    (ov->frame[f].format != vm->format) ||
+		    (ov->frame[f].sub_flag != ov->sub_flag) ||
+		    (ov->frame[f].depth != depth)) {
 			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
 
 			/* If we're collecting previous frame wait
 			   before changing modes */
 			interruptible_sleep_on(&ov->wq);
 			if (signal_pending(current)) return -EINTR;
-			ret = mode_init_regs(ov, vm.width, vm.height,
-				vm.format, ov->sub_flag);
+			ret = mode_init_regs(ov, vm->width, vm->height,
+				vm->format, ov->sub_flag);
 #if 0
 			if (ret < 0) {
 				PDEBUG(1, "Got error while initializing regs ");
 				return ret;
 			}
 #endif
-			ov->frame[vm.frame].width = vm.width;
-			ov->frame[vm.frame].height = vm.height;
-			ov->frame[vm.frame].format = vm.format;
-			ov->frame[vm.frame].sub_flag = ov->sub_flag;
-			ov->frame[vm.frame].depth = depth;
+			ov->frame[f].width = vm->width;
+			ov->frame[f].height = vm->height;
+			ov->frame[f].format = vm->format;
+			ov->frame[f].sub_flag = ov->sub_flag;
+			ov->frame[f].depth = depth;
 		}
 
 		/* Mark it as ready */
-		ov->frame[vm.frame].grabstate = FRAME_READY;
+		ov->frame[f].grabstate = FRAME_READY;
 
-		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);
+		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
 
-		return ov51x_new_frame(ov, vm.frame);
+		return ov51x_new_frame(ov, f);
 	}
 	case VIDIOCSYNC:
 	{
-		int fnum, rc;
+		unsigned int fnum = *((unsigned int *) arg);
 		struct ov511_frame *frame;
+		int rc;
 
-		if (copy_from_user((void *)&fnum, arg, sizeof(int)))
-			return -EFAULT;
 
-		if ((unsigned)fnum >= OV511_NUMFRAMES) {
+		if (fnum >= OV511_NUMFRAMES) {
 			err("VIDIOCSYNC: invalid frame (%d)", fnum);
 			return -EINVAL;
 		}
@@ -5125,124 +4972,105 @@
 	}
 	case VIDIOCGFBUF:
 	{
-		struct video_buffer vb;
+		struct video_buffer *vb = arg;
 
-		PDEBUG(4, "VIDIOCSCHAN");
+		PDEBUG(4, "VIDIOCGFBUF");
 
-		memset(&vb, 0, sizeof(vb));
-		vb.base = NULL;	/* frame buffer not supported, not used */
-
-		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-			return -EFAULT;
+		memset(vb, 0, sizeof(struct video_buffer));
 
 		return 0;
 	}
 	case VIDIOCGUNIT:
 	{
-		struct video_unit vu;
+		struct video_unit *vu = arg;
 
 		PDEBUG(4, "VIDIOCGUNIT");
 
-		memset(&vu, 0, sizeof(vu));
-
-		vu.video = ov->vdev.minor;	/* Video minor */
-		vu.vbi = VIDEO_NO_UNIT;		/* VBI minor */
-		vu.radio = VIDEO_NO_UNIT;	/* Radio minor */
-		vu.audio = VIDEO_NO_UNIT;	/* Audio minor */
-		vu.teletext = VIDEO_NO_UNIT;	/* Teletext minor */
+		memset(vu, 0, sizeof(struct video_unit));
 
-		if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
-			return -EFAULT;
+		vu->video = ov->vdev.minor;
+		vu->vbi = VIDEO_NO_UNIT;
+		vu->radio = VIDEO_NO_UNIT;
+		vu->audio = VIDEO_NO_UNIT;
+		vu->teletext = VIDEO_NO_UNIT;
 
 		return 0;
 	}
 	case VIDIOCGTUNER:
 	{
-		struct video_tuner v;
+		struct video_tuner *v = arg;
 
 		PDEBUG(4, "VIDIOCGTUNER");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		if (!ov->has_tuner || v.tuner)	// Only tuner 0
+		if (!ov->has_tuner || v->tuner)	// Only tuner 0
 			return -EINVAL;
 
-		strcpy(v.name, "Television");
+		strcpy(v->name, "Television");
 
 		// FIXME: Need a way to get the real values
-		v.rangelow = 0;
-		v.rangehigh = ~0;
+		v->rangelow = 0;
+		v->rangehigh = ~0;
 
-		v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC |
-		    VIDEO_TUNER_SECAM;
-		v.mode = 0; 		/* FIXME:  Not sure what this is yet */
-		v.signal = 0xFFFF;	/* unknown */
+		v->flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC
+			   | VIDEO_TUNER_SECAM;
+		v->mode = 0; 		/* FIXME:  Not sure what this is yet */
+		v->signal = 0xFFFF;	/* unknown */
 
-		call_i2c_clients(ov, cmd, &v);
-
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
+		call_i2c_clients(ov, cmd, v);
 
 		return 0;
 	}
 	case VIDIOCSTUNER:
 	{
-		struct video_tuner v;
+		struct video_tuner *v = arg;
 		int err;
 
 		PDEBUG(4, "VIDIOCSTUNER");
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
 		/* Only no or one tuner for now */
-		if (!ov->has_tuner || v.tuner)
+		if (!ov->has_tuner || v->tuner)
 			return -EINVAL;
 
 		/* and it only has certain valid modes */
-		if (v.mode != VIDEO_MODE_PAL &&
-		    v.mode != VIDEO_MODE_NTSC &&
-		    v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;
+		if (v->mode != VIDEO_MODE_PAL &&
+		    v->mode != VIDEO_MODE_NTSC &&
+		    v->mode != VIDEO_MODE_SECAM)
+			return -EOPNOTSUPP;
 
 		/* Is this right/necessary? */
-		err = decoder_set_norm(ov, v.mode);
+		err = decoder_set_norm(ov, v->mode);
 		if (err)
 			return err;
 
-		call_i2c_clients(ov, cmd, &v);
+		call_i2c_clients(ov, cmd, v);
 
 		return 0;
 	}
 	case VIDIOCGFREQ:
 	{
-		unsigned long v = ov->freq;
+		unsigned long v = *((unsigned long *) arg);
 
 		PDEBUG(4, "VIDIOCGFREQ");
 
 		if (!ov->has_tuner)
 			return -EINVAL;
+
+		v = ov->freq;
 #if 0
 		/* FIXME: this is necessary for testing */
 		v = 46*16;
 #endif
-		if (copy_to_user(arg, &v, sizeof(v)))
-			return -EFAULT;
-
 		return 0;
 	}
 	case VIDIOCSFREQ:
 	{
-		unsigned long v;
+		unsigned long v = *((unsigned long *) arg);
+
+		PDEBUG(4, "VIDIOCSFREQ: %lx", v);
 
 		if (!ov->has_tuner)
 			return -EINVAL;
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			return -EFAULT;
-
-		PDEBUG(4, "VIDIOCSFREQ: %lx", v);
-
 		ov->freq = v;
 		call_i2c_clients(ov, cmd, &v);
 
@@ -5262,25 +5090,110 @@
 	return 0;
 }
 
+#ifdef OV511_OLD_V4L
+/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
+int
+ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	char	sbuf[128];
+	void    *mbuf = NULL;
+	void	*parg = NULL;
+	int	err  = -EINVAL;
+	
+	/*  Copy arguments into temp kernel buffer  */
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:
+		parg = arg;
+		break;
+	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+	case _IOC_WRITE:
+	case (_IOC_WRITE | _IOC_READ):
+		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+			parg = sbuf;
+		} else {
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
+		}
+		
+		err = -EFAULT;
+		if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
+			goto out;
+		break;
+	}
+
+	err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
+	if (err == -ENOIOCTLCMD)
+		err = -EINVAL;
+	if (err < 0)
+		goto out;
+
+	/*  Copy results into user buffer  */
+	switch (_IOC_DIR(cmd))
+	{
+	case _IOC_READ:
+	case (_IOC_WRITE | _IOC_READ):
+		if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
+			err = -EFAULT;
+		break;
+	}
+
+out:
+	if (mbuf)
+		kfree(mbuf);
+	return err;
+}
+
 static int 
 ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
+	struct usb_ov511 *ov = vdev->priv;
 	int rc;
+
+	if (down_interruptible(&ov->lock))
+		return -EINTR;
+
+	rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
+
+	up(&ov->lock);
+	return rc;
+}
+
+#else	/* If new V4L API */
+
+static int 
+ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+		 unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
 	struct usb_ov511 *ov = vdev->priv;
+	int rc;
 
 	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg);
+	rc = ov51x_v4l1_ioctl_internal(ov, cmd, arg);
 
 	up(&ov->lock);
 	return rc;
 }
+#endif	/* OV511_OLD_V4L */
 
+#ifdef OV511_OLD_V4L
 static inline long 
 ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
 		int noblock)
 {
+#else
+static inline int 
+ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
+{
+	struct video_device *vdev = video_devdata(file);
+	int noblock = file->f_flags&O_NONBLOCK;
+	unsigned long count = cnt;
+#endif
 	struct usb_ov511 *ov = vdev->priv;
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
@@ -5429,12 +5342,23 @@
 	return rc;
 }
 
-static int 
+static int
+#ifdef OV511_OLD_V4L
 ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev,
 		const char *adr, unsigned long size)
 {
-	struct usb_ov511 *ov = vdev->priv;
 	unsigned long start = (unsigned long)adr;
+
+#else	/* New V4L API */
+
+ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end - vma->vm_start;
+#endif	/* OV511_OLD_V4L */
+
+	struct usb_ov511 *ov = vdev->priv;
 	unsigned long page, pos;
 
 	if (ov->dev == NULL)
@@ -5453,7 +5377,8 @@
 	pos = (unsigned long)ov->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE,
+				     PAGE_SHARED)) {
 			up(&ov->lock);
 			return -EAGAIN;
 		}
@@ -5469,6 +5394,7 @@
 	return 0;
 }
 
+#ifdef OV511_OLD_V4L
 static struct video_device vdev_template = {
 	owner:		THIS_MODULE,
 	name:		"OV511 USB Camera",
@@ -5477,12 +5403,32 @@
 	open:		ov51x_v4l1_open,
 	close:		ov51x_v4l1_close,
 	read:		ov51x_v4l1_read,
-	write:		ov51x_v4l1_write,
 	ioctl:		ov51x_v4l1_ioctl,
 	mmap:		ov51x_v4l1_mmap,
-	initialize:	ov51x_v4l1_init_done,
 };
 
+#else	/* New V4L API */
+
+static struct file_operations ov511_fops = {
+	owner:		THIS_MODULE,
+	open:		ov51x_v4l1_open,
+	release:       	ov51x_v4l1_close,
+	read:		ov51x_v4l1_read,
+	mmap:		ov51x_v4l1_mmap,
+	ioctl:          video_generic_ioctl,
+	llseek:         no_llseek,
+};
+
+static struct video_device vdev_template = {
+	owner:		THIS_MODULE,
+	name:		"OV511 USB Camera",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	VID_HARDWARE_OV511,
+	fops:           &ov511_fops,
+	kernel_ioctl:	ov51x_v4l1_ioctl,
+};
+#endif	/* OV511_OLD_V4L */
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 static int 
 ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -5497,7 +5443,7 @@
 	if (!pde)
 		return -ENOENT;
 
-	ov = (struct usb_ov511 *) pde->data;
+	ov = pde->data;
 	if (!ov)
 		return -ENODEV;
 
@@ -6067,19 +6013,18 @@
 	if (rc < 0) {
 		err("Error detecting sensor type");
 		return -1;
-	} else if ((rc & 3) == 0) {
-		info("Sensor is an OV6630");
+	} 
+
+	if ((rc & 3) == 0)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 1) {
-		info("Sensor is an OV6620");
+	else if ((rc & 3) == 1)
 		ov->sensor = SEN_OV6620;
-	} else if ((rc & 3) == 2) {
-		info("Sensor is an OV6630AE");
+	else if ((rc & 3) == 2)
 		ov->sensor = SEN_OV6630;
-	} else if ((rc & 3) == 3) {
-		info("Sensor is an OV6630AF");
+	else if ((rc & 3) == 3)
 		ov->sensor = SEN_OV6630;
-	} 
+
+	info("Sensor is an %s", symbolic(senlist, ov->sensor));
 
 	/* Set sensor-specific vars */
 	ov->maxwidth = 352;
@@ -6165,7 +6110,7 @@
 
 /* This initializes the SAA7111A video decoder. */
 static int 
-saa7111a_configure(struct usb_ov511 *ov511)
+saa7111a_configure(struct usb_ov511 *ov)
 {
 	int rc;
 
@@ -6210,44 +6155,44 @@
 #endif
 
 	/* Set sensor-specific vars */
-	ov511->maxwidth = 640;
-	ov511->maxheight = 480;		/* Even/Odd fields */
-	ov511->minwidth = 320;
-	ov511->minheight = 240;		/* Even field only */
-
-	ov511->has_decoder = 1;
-	ov511->num_inputs = 8;
-	ov511->norm = VIDEO_MODE_AUTO;
-	ov511->stop_during_set = 0;	/* Decoder guarantees stable image */
+	ov->maxwidth = 640;
+	ov->maxheight = 480;		/* Even/Odd fields */
+	ov->minwidth = 320;
+	ov->minheight = 240;		/* Even field only */
+
+	ov->has_decoder = 1;
+	ov->num_inputs = 8;
+	ov->norm = VIDEO_MODE_AUTO;
+	ov->stop_during_set = 0;	/* Decoder guarantees stable image */
 
 	/* Decoder doesn't change these values, so we use these instead of
 	 * acutally reading the registers (which doesn't work) */
-	ov511->brightness = 0x80 << 8;
-	ov511->contrast = 0x40 << 9;
-	ov511->colour = 0x40 << 9;
-	ov511->hue = 32768;
+	ov->brightness = 0x80 << 8;
+	ov->contrast = 0x40 << 9;
+	ov->colour = 0x40 << 9;
+	ov->hue = 32768;
 
 	PDEBUG(4, "Writing SAA7111A registers");
-	if (write_regvals(ov511, aRegvalsNormSAA7111A))
+	if (write_regvals(ov, aRegvalsNormSAA7111A))
 		return -1;
 
 	/* Detect version of decoder. This must be done after writing the
          * initial regs or the decoder will lock up. */
-	rc = i2c_r(ov511, 0x00);
+	rc = i2c_r(ov, 0x00);
 
 	if (rc < 0) {
 		err("Error detecting sensor version");
 		return -1;
 	} else {
 		info("Sensor is an SAA7111A (version 0x%x)", rc);
-		ov511->sensor = SEN_SAA7111A;
+		ov->sensor = SEN_SAA7111A;
 	}
 
 	// FIXME: Fix this for OV518(+)
 	/* Latch to negative edge of clock. Otherwise, we get incorrect
 	 * colors and jitter in the digital signal. */
-	if (ov511->bclass == BCL_OV511)
-		reg_w(ov511, 0x11, 0x00);
+	if (ov->bclass == BCL_OV511)
+		reg_w(ov, 0x11, 0x00);
 	else
 		warn("SAA7111A not yet supported with OV518/OV518+");
 
@@ -6258,8 +6203,6 @@
 static int 
 ov511_configure(struct usb_ov511 *ov)
 {
-	int i;
-
 	static struct ov511_regvals aRegvalsInit511[] = {
 		{ OV511_REG_BUS, R51x_SYS_RESET,	0x7f },
 	 	{ OV511_REG_BUS, R51x_SYS_INIT,		0x01 },
@@ -6301,24 +6244,18 @@
 		goto error;
 	}
 
-	ov->desc = -1;
 	PDEBUG (1, "CustomID = %d", ov->customid);
-	for (i = 0; clist[i].id >= 0; i++) {
-		if (ov->customid == clist[i].id) {
-			info("model: %s", clist[i].description);
-			ov->desc = i;
-			break;
-		}
-	}
+	ov->desc = symbolic(camlist, ov->customid);
+	info("model: %s", ov->desc);
 
-	if (clist[i].id == -1) {
+	if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
 		err("Camera type (%d) not recognized", ov->customid);
 		err("Please notify " EMAIL " of the name,");
 		err("manufacturer, model, and this number of your camera.");
 		err("Also include the output of the detection process.");
 	} 
 
-	if (clist[i].id == 6) {	/* USB Life TV (NTSC) */
+	if (ov->customid == 6) {	/* USB Life TV (NTSC) */
 		ov->tuner_type = 8;		/* Temic 4036FY5 3X 1981 */
 	}
 
@@ -6545,7 +6482,6 @@
  *
  ***************************************************************************/
 
-/* 2.2.x compatibility */
 static void *
 ov51x_probe(struct usb_device *dev, unsigned int ifnum,
 	    const struct usb_device_id *id)
@@ -6592,29 +6528,24 @@
 
 	switch (dev->descriptor.idProduct) {
 	case PROD_OV511:
-		info("USB OV511 camera found");
 		ov->bridge = BRG_OV511;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV511PLUS:
-		info("USB OV511+ camera found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
 	case PROD_OV518:
-		info("USB OV518 camera found");
 		ov->bridge = BRG_OV518;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_OV518PLUS:
-		info("USB OV518+ camera found");
 		ov->bridge = BRG_OV518PLUS;
 		ov->bclass = BCL_OV518;
 		break;
 	case PROD_ME2CAM:
 		if (dev->descriptor.idVendor != VEND_MATTEL)
 			goto error;
-		info("Intel Play Me2Cam (OV511+) found");
 		ov->bridge = BRG_OV511PLUS;
 		ov->bclass = BCL_OV511;
 		break;
@@ -6623,6 +6554,8 @@
 		goto error_dealloc;
 	}
 
+	info("USB %s video device found", symbolic(brglist, ov->bridge));
+
 	/* Workaround for some applications that want data in RGB
 	 * instead of BGR. */
 	if (force_rgb)
@@ -6656,6 +6589,12 @@
 		init_waitqueue_head(&ov->frame[i].wq);
 	}
 
+	for (i = 0; i < OV511_NUMSBUF; i++) {
+		ov->sbuf[i].ov = ov;
+		spin_lock_init(&ov->sbuf[i].lock);
+		ov->sbuf[i].n = i;
+	}
+
 	/* Unnecessary? (This is done on open(). Need to make sure variables
 	 * are properly initialized without this before removing it, though). */
 	if (ov51x_set_default_params(ov) < 0)
@@ -6690,11 +6629,13 @@
 
 	info("Device registered on minor %d", ov->vdev.minor);
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	create_proc_ov511_cam(ov);
+#endif
+
      	return ov;
 
 error:
-	err("Camera initialization failed");
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	/* Safe to call even if entry doesn't exist */
 	destroy_proc_ov511_cam(ov);
@@ -6707,9 +6648,6 @@
 		up(&ov->cbuf_lock);
 	}
 
-	usb_driver_release_interface(&ov511_driver,
-		&dev->actconfig->interface[ov->iface]);
-
 error_dealloc:
 	if (ov) {
 		kfree(ov);
@@ -6717,6 +6655,7 @@
 	}
 
 error_out:
+	err("Camera initialization failed");
 	return NULL;
 }
 
@@ -6749,22 +6688,12 @@
 
 	ov->streaming = 0;
 
-	/* Unschedule all of the iso td's */
-	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-		if (ov->sbuf[n].urb) {
-			ov->sbuf[n].urb->next = NULL;
-			usb_unlink_urb(ov->sbuf[n].urb);
-			usb_free_urb(ov->sbuf[n].urb);
-			ov->sbuf[n].urb = NULL;
-		}
-	}
+	ov51x_unlink_isoc(ov);
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
         destroy_proc_ov511_cam(ov);
 #endif
 
-	usb_driver_release_interface(&ov511_driver,
-		&ov->dev->actconfig->interface[ov->iface]);
 	ov->dev = NULL;
 
 	/* Free the memory */
diff -urN linux-2.5.6-pre2/drivers/usb/ov511.h linux-2.5.6-pre3/drivers/usb/ov511.h
--- linux-2.5.6-pre2/drivers/usb/ov511.h	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/drivers/usb/ov511.h	Wed Mar  6 17:17:53 2002
@@ -10,8 +10,8 @@
 
 #ifdef OV511_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\
-		__LINE__ , ## args)
+		if (debug >= (level)) info("[%s:%d] " fmt, \
+		__PRETTY_FUNCTION__, __LINE__ , ## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
@@ -243,6 +243,16 @@
 
 #define OV511_ENDPOINT_ADDRESS	1	/* Isoc endpoint number */
 
+#define OV511_NUMFRAMES	2
+#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
+	#error "OV511_NUMFRAMES is too high"
+#endif
+
+#define OV511_NUMSBUF		2
+
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE		4
+
 /* Bridge types */
 enum {
 	BRG_UNKNOWN,
@@ -376,9 +386,14 @@
 			       struct ov511_i2c_struct)
 /* ------------- End IOCTL interface -------------- */
 
+struct usb_ov511;		/* Forward declaration */
+
 struct ov511_sbuf {
-	char *data;
+	struct usb_ov511 *ov;
+	unsigned char *data;
 	struct urb *urb;
+	spinlock_t lock;
+	int n;
 };
 
 enum {
@@ -401,9 +416,10 @@
 
 struct ov511_frame {
 	int framenum;		/* Index of this frame */
-	char *data;		/* Frame buffer */
-	char *tempdata;		/* Temp buffer for multi-stage conversions */
-	char *rawdata;		/* Raw camera data buffer */
+	unsigned char *data;	/* Frame buffer */
+	unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
+	unsigned char *rawdata;	/* Raw camera data buffer */
+	unsigned char *compbuf;	/* Temp buffer for decompressor */
 
 	int depth;		/* Bytes per pixel */
 	int width;		/* Width application is expecting */
@@ -428,27 +444,20 @@
 	int snapshot;		/* True if frame was a snapshot */
 };
 
-#define DECOMP_INTERFACE_VER 2
+#define DECOMP_INTERFACE_VER 3
 
 /* Compression module operations */
 struct ov51x_decomp_ops {
-	int (*decomp_400)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_420)(unsigned char *, unsigned char *, int, int, int);
-	int (*decomp_422)(unsigned char *, unsigned char *, int, int, int);
+	int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
+	int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
+			  int, int, int);
 	void (*decomp_lock)(void);
 	void (*decomp_unlock)(void);
 };
 
-#define OV511_NUMFRAMES	2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-	#error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF		2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE		4
-
 struct usb_ov511 {
 	struct video_device vdev;
 
@@ -456,7 +465,7 @@
 	struct usb_device *dev;
 
 	int customid;
-	int desc;
+	char *desc;
 	unsigned char iface;
 
 	/* Determined by sensor type */
@@ -490,9 +499,9 @@
 	int lightfreq;		/* Power (lighting) frequency */
 	int bandfilt;		/* Banding filter enabled flag */
 
-	char *fbuf;		/* Videodev buffer area */
-	char *tempfbuf;		/* Temporary (intermediate) buffer area */
-	char *rawfbuf;		/* Raw camera data buffer area */
+	unsigned char *fbuf;	/* Videodev buffer area */
+	unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
+	unsigned char *rawfbuf;	/* Raw camera data buffer area */
 
 	int sub_flag;		/* Pix Array subcapture on flag */
 	int subx;		/* Pix Array subcapture x offset */
@@ -556,16 +565,29 @@
 	struct semaphore cbuf_lock;
 };
 
-struct cam_list {
-	int id;
-	char *description;
-};
-
-struct palette_list {
+/* Used to represent a list of values and their respective symbolic names */
+struct symbolic_list {
 	int num;
 	char *name;
 };
 
+#define NOT_DEFINED_STR "Unknown"
+
+/* Returns the name of the matching element in the symbolic_list array. The
+ * end of the list must be marked with an element that has a NULL name.
+ */
+static inline char * 
+symbolic(struct symbolic_list list[], int num)
+{
+	int i;
+
+	for (i = 0; list[i].name != NULL; i++)
+			if (list[i].num == num)
+				return (list[i].name);
+
+	return (NOT_DEFINED_STR);
+}
+
 struct mode_list_518 {
 	int width;
 	int height;
diff -urN linux-2.5.6-pre2/drivers/usb/storage/isd200.c linux-2.5.6-pre3/drivers/usb/storage/isd200.c
--- linux-2.5.6-pre2/drivers/usb/storage/isd200.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/drivers/usb/storage/isd200.c	Wed Mar  6 17:17:54 2002
@@ -821,7 +821,7 @@
  * Invoke the transport and basic error-handling/recovery methods
  *
  * This is used by the protocol layers to actually send the message to
- * the device and recieve the response.
+ * the device and receive the response.
  */
 void isd200_invoke_transport( struct us_data *us, 
 			      Scsi_Cmnd *srb, 
diff -urN linux-2.5.6-pre2/drivers/usb/storage/transport.c linux-2.5.6-pre3/drivers/usb/storage/transport.c
--- linux-2.5.6-pre2/drivers/usb/storage/transport.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/drivers/usb/storage/transport.c	Wed Mar  6 17:17:54 2002
@@ -612,7 +612,7 @@
 /* Invoke the transport and basic error-handling/recovery methods
  *
  * This is used by the protocol layers to actually send the message to
- * the device and recieve the response.
+ * the device and receive the response.
  */
 void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
@@ -798,7 +798,7 @@
 {
 	struct us_data *us = (struct us_data *)urb->context;
 
-	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+	US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
 	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
 	US_DEBUGP("-- IRQ state is %d\n", urb->status);
 	US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
diff -urN linux-2.5.6-pre2/fs/block_dev.c linux-2.5.6-pre3/fs/block_dev.c
--- linux-2.5.6-pre2/fs/block_dev.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/fs/block_dev.c	Wed Mar  6 17:17:54 2002
@@ -442,6 +442,27 @@
 	spin_unlock(&bdev_lock);
 }
 
+int bd_claim(struct block_device *bdev, void *holder)
+{
+	int res = -EBUSY;
+	spin_lock(&bdev_lock);
+	if (!bdev->bd_holder || bdev->bd_holder == holder) {
+		bdev->bd_holder = holder;
+		bdev->bd_holders++;
+		res = 0;
+	}
+	spin_unlock(&bdev_lock);
+	return res;
+}
+
+void bd_release(struct block_device *bdev)
+{
+	spin_lock(&bdev_lock);
+	if (!--bdev->bd_holders)
+		bdev->bd_holder = NULL;
+	spin_unlock(&bdev_lock);
+}
+
 static struct {
 	const char *name;
 	struct block_device_operations *bdops;
diff -urN linux-2.5.6-pre2/fs/coda/cache.c linux-2.5.6-pre3/fs/coda/cache.c
--- linux-2.5.6-pre2/fs/coda/cache.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/fs/coda/cache.c	Wed Mar  6 17:17:54 2002
@@ -71,7 +71,6 @@
         hit = ((mask & cii->c_cached_perm) == mask) &&
                 coda_cred_ok(&cii->c_cached_cred);
 
-        CDEBUG(D_CACHE, "%s for ino %ld\n", hit ? "HIT" : "MISS", inode->i_ino);
         return hit;
 }
 
@@ -102,9 +101,6 @@
 		/* don't know what to do with negative dentries */
 		if ( ! de->d_inode ) 
 			continue;
-		CDEBUG(D_DOWNCALL, "%d for %*s/%*s\n", flag, 
-		       de->d_name.len, de->d_name.name, 
-		       de->d_parent->d_name.len, de->d_parent->d_name.name);
 		coda_flag_inode(de->d_inode, flag);
 	}
 	spin_unlock(&dcache_lock);
diff -urN linux-2.5.6-pre2/fs/coda/cnode.c linux-2.5.6-pre3/fs/coda/cnode.c
--- linux-2.5.6-pre2/fs/coda/cnode.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/fs/coda/cnode.c	Wed Mar  6 17:17:54 2002
@@ -11,9 +11,6 @@
 #include <linux/coda_fs_i.h>
 #include <linux/coda_psdev.h>
 
-extern int coda_debug;
-extern int coda_print_entry;
-
 inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
 {
 	if (fid1->Vnode != fid2->Vnode)   return 0;
@@ -42,11 +39,6 @@
 /* cnode.c */
 static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
 {
-        CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
-
-        if (coda_debug & D_SUPER ) 
-		print_vattr(attr);
-
         coda_vattr_to_iattr(inode, attr);
 
         if (S_ISREG(inode->i_mode)) {
@@ -72,10 +64,8 @@
 
 	inode = iget4(sb, ino, coda_inocmp, fid);
 
-	if ( !inode ) { 
-		CDEBUG(D_CNODE, "coda_iget: no inode\n");
+	if (!inode)
 		return ERR_PTR(-ENOMEM);
-	}
 
 	/* check if the inode is already initialized */
 	cii = ITOC(inode);
@@ -105,9 +95,6 @@
 	/* We get inode numbers from Venus -- see venus source */
 	error = venus_getattr(sb, fid, &attr);
 	if ( error ) {
-	    CDEBUG(D_CNODE, 
-		   "coda_cnode_make: coda_getvattr returned %d for %s.\n", 
-		   error, coda_f2s(fid));
 	    *inode = NULL;
 	    return error;
 	} 
@@ -117,10 +104,6 @@
 		printk("coda_cnode_make: coda_iget failed\n");
                 return PTR_ERR(*inode);
         }
-
-	CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
-		(*inode)->i_ino, atomic_read(&(*inode)->i_count), 
-		coda_f2s(&ITOC(*inode)->c_fid));
 	return 0;
 }
 
@@ -155,8 +138,6 @@
 		return NULL;
 	}
 
-	CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
-
 	nr = coda_f2i(fid);
 	inode = iget4(sb, nr, coda_inocmp, fid);
 	if ( !inode ) {
@@ -177,7 +158,6 @@
 	/* we shouldn't see inode collisions anymore */
 	if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
 
-        CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
         return inode;
 }
 
diff -urN linux-2.5.6-pre2/fs/coda/coda_linux.c linux-2.5.6-pre3/fs/coda/coda_linux.c
--- linux-2.5.6-pre2/fs/coda/coda_linux.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/fs/coda/coda_linux.c	Wed Mar  6 17:17:54 2002
@@ -24,9 +24,6 @@
 #include <linux/coda_fs_i.h>
 
 /* initialize the debugging variables */
-int coda_debug;
-int coda_print_entry; 
-int coda_access_cache = 1;
 int coda_fake_statfs;
 
 /* print a fid */
@@ -92,35 +89,23 @@
 {
 	unsigned short coda_flags = 0;
 	
-	if ( (flags & O_ACCMODE) == O_RDONLY ){ 
-		CDEBUG(D_FILE, "--> C_O_READ added\n");
+	if ((flags & O_ACCMODE) == O_RDONLY)
 		coda_flags |= C_O_READ;
-	}
 
-	if ( (flags & O_ACCMODE) ==  O_RDWR ) { 
-		CDEBUG(D_FILE, "--> C_O_READ | C_O_WRITE added\n");
+	if ((flags & O_ACCMODE) == O_RDWR)
 		coda_flags |= C_O_READ | C_O_WRITE;
-	}
 
-	if ( (flags & O_ACCMODE) == O_WRONLY ){ 
-		CDEBUG(D_FILE, "--> C_O_WRITE added\n");
+	if ((flags & O_ACCMODE) == O_WRONLY)
 		coda_flags |= C_O_WRITE;
-	}
 
-	if ( flags & O_TRUNC )  { 
-		CDEBUG(D_FILE, "--> C_O_TRUNC added\n");
+	if (flags & O_TRUNC)
 		coda_flags |= C_O_TRUNC;
-	}
 
-	if ( flags & O_CREAT )  { 
-		CDEBUG(D_FILE, "--> C_O_CREAT added\n");
+	if (flags & O_CREAT)
 		coda_flags |= C_O_CREAT;
-	}
 
-	if ( flags & O_EXCL ) {
+	if (flags & O_EXCL)
 		coda_flags |= C_O_EXCL;
-		CDEBUG(D_FILE, "--> C_O_EXCL added\n");
-	}
 
 	return coda_flags;
 }
diff -urN linux-2.5.6-pre2/fs/coda/dir.c linux-2.5.6-pre3/fs/coda/dir.c
--- linux-2.5.6-pre2/fs/coda/dir.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/fs/coda/dir.c	Wed Mar  6 17:17:54 2002
@@ -50,11 +50,7 @@
 static int coda_dentry_delete(struct dentry *);
 
 /* support routines */
-static void coda_prepare_fakefile(struct file *coda_file, 
-				  struct dentry *open_dentry,
-				  struct file *open_file);
-static int coda_venus_readdir(struct file *filp, void *dirent, 
-			      filldir_t filldir);
+static int coda_venus_readdir(struct file *filp, filldir_t filldir, void *dirent);
 int coda_fsync(struct file *, struct dentry *dentry, int datasync);
 
 int coda_hasmknod;
@@ -109,16 +105,10 @@
 		return ERR_PTR(-ENAMETOOLONG);
 	}
 
-        CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n", 
-	       name, (long)length, dir->i_ino, coda_i2s(dir));
-
 	lock_kernel();
         /* control object, create inode on the fly */
         if (coda_isroot(dir) && coda_iscontrol(name, length)) {
 	        error = coda_cnode_makectl(&res_inode, dir->i_sb);
-		CDEBUG(D_SPECIAL, 
-		       "Lookup on CTL object; dir ino %ld, count %d\n", 
-		       dir->i_ino, atomic_read(&dir->i_count));
 		dropme = 1;
                 goto exit;
         }
@@ -130,8 +120,6 @@
 	if (!error) {
 		if (type & CODA_NOCACHE) {
 			type &= (~CODA_NOCACHE);
-			CDEBUG(D_INODE, "dropme set for %s\n", 
-			       coda_f2s(&resfid));
 			dropme = 1;
 		}
 
@@ -141,13 +129,9 @@
 			return ERR_PTR(error);
 		}
 	} else if (error != -ENOENT) {
-	        CDEBUG(D_INODE, "error for %s(%*s)%d\n",
-		       coda_i2s(dir), (int)length, name, error);
 		unlock_kernel();
 		return ERR_PTR(error);
 	}
-	CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
-	       name, coda_f2s(&resfid), type, error, dropme);
 
 exit:
 	entry->d_time = 0;
@@ -164,28 +148,19 @@
 
 int coda_permission(struct inode *inode, int mask)
 {
+	umode_t mode = inode->i_mode;
         int error;
  
-	coda_vfs_stat.permission++;
+	if (!mask)
+		return 0; 
 
-        if ( mask == 0 )
-                return 0;
+	coda_vfs_stat.permission++;
 
-	if ( coda_access_cache ) {
-		coda_permission_stat.count++;
+	if (coda_cache_check(inode, mask))
+		return 0; 
 
-		if ( coda_cache_check(inode, mask) ) {
-			coda_permission_stat.hit_count++;
-			return 0; 
-		}
-	}
-
-        CDEBUG(D_INODE, "mask is %o\n", mask);
         error = venus_access(inode->i_sb, coda_i2f(inode), mask);
     
-        CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", 
-	       coda_i2s(inode), inode->i_ino, mask, error);
-
 	if (!error)
 		coda_cache_enter(inode, mask);
 
@@ -203,7 +178,7 @@
 	/* optimistically we can also act as if our nose bleeds. The
          * granularity of the mtime is coarse anyways so we might actually be
          * right most of the time. Note: we only do this for directories. */
-	dir->i_mtime = CURRENT_TIME;
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 #endif
 	if (link)
 		dir->i_nlink += link;
@@ -215,15 +190,13 @@
         int error=0;
 	const char *name=de->d_name.name;
 	int length=de->d_name.len;
-	struct inode *result = NULL;
+	struct inode *inode;
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
 	lock_kernel();
 	coda_vfs_stat.create++;
 
-	CDEBUG(D_INODE, "name: %s, length %d, mode %o\n", name, length, mode);
-
 	if (coda_isroot(dir) && coda_iscontrol(name, length)) {
 		unlock_kernel();
 		return -EPERM;
@@ -233,25 +206,22 @@
 				0, mode, 0, &newfid, &attrs);
 
         if ( error ) {
-		CDEBUG(D_INODE, "create: %s, result %d\n",
-		       coda_f2s(&newfid), error); 
 		unlock_kernel();
 		d_drop(de);
 		return error;
 	}
 
-	error = coda_cnode_make(&result, &newfid, dir->i_sb);
-	if ( error ) {
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		unlock_kernel();
 		d_drop(de);
-		result = NULL;
-		return error;
+		return PTR_ERR(inode);
 	}
 
 	/* invalidate the directory cnode's attributes */
 	coda_dir_changed(dir, 0);
 	unlock_kernel();
-	d_instantiate(de, result);
+	d_instantiate(de, inode);
         return 0;
 }
 
@@ -260,7 +230,7 @@
         int error=0;
 	const char *name=de->d_name.name;
 	int length=de->d_name.len;
-	struct inode *result = NULL;
+	struct inode *inode;
 	struct ViceFid newfid;
 	struct coda_vattr attrs;
 
@@ -270,9 +240,6 @@
 	lock_kernel();
 	coda_vfs_stat.create++;
 
-	CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",
-	       name, length, mode, rdev);
-
 	if (coda_isroot(dir) && coda_iscontrol(name, length)) {
 		unlock_kernel();
 		return -EPERM;
@@ -282,32 +249,29 @@
 				0, mode, rdev, &newfid, &attrs);
 
         if ( error ) {
-		CDEBUG(D_INODE, "mknod: %s, result %d\n",
-		       coda_f2s(&newfid), error); 
-		d_drop(de);
 		unlock_kernel();
+		d_drop(de);
 		return error;
 	}
 
-	error = coda_cnode_make(&result, &newfid, dir->i_sb);
-	if ( error ) {
-		d_drop(de);
-		result = NULL;
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		unlock_kernel();
-		return error;
+		d_drop(de);
+		return PTR_ERR(inode);
 	}
 
 	/* invalidate the directory cnode's attributes */
 	coda_dir_changed(dir, 0);
 	unlock_kernel();
-	d_instantiate(de, result);
+	d_instantiate(de, inode);
         return 0;
 }			     
 
 static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
 {
 	struct inode *inode;
-	struct coda_vattr attr;
+	struct coda_vattr attrs;
 	const char *name = de->d_name.name;
 	int len = de->d_name.len;
 	int error;
@@ -321,29 +285,21 @@
 		return -EPERM;
 	}
 
-	CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", 
-	       name, len, coda_i2s(dir), mode);
-
-	attr.va_mode = mode;
+	attrs.va_mode = mode;
 	error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
-			       name, len, &newfid, &attr);
+			       name, len, &newfid, &attrs);
         
         if ( error ) {
-	        CDEBUG(D_INODE, "mkdir error: %s result %d\n", 
-		       coda_f2s(&newfid), error); 
-		d_drop(de);
 		unlock_kernel();
-                return error;
+		d_drop(de);
+		return error;
         }
          
-	CDEBUG(D_INODE, "mkdir: new dir has fid %s.\n", 
-	       coda_f2s(&newfid)); 
-
-	error = coda_cnode_make(&inode, &newfid, dir->i_sb);
-	if ( error ) {
-		d_drop(de);
+	inode = coda_iget(dir->i_sb, &newfid, &attrs);
+	if ( IS_ERR(inode) ) {
 		unlock_kernel();
-		return error;
+		d_drop(de);
+		return PTR_ERR(inode);
 	}
 	
 	/* invalidate the directory cnode's attributes */
@@ -370,9 +326,6 @@
 		return -EPERM;
 	}
 
-	CDEBUG(D_INODE, "old: fid: %s\n", coda_i2s(inode));
-	CDEBUG(D_INODE, "directory: %s\n", coda_i2s(dir_inode));
-
 	error = venus_link(dir_inode->i_sb, coda_i2f(inode),
 			   coda_i2f(dir_inode), (const char *)name, len);
 
@@ -387,7 +340,6 @@
 	inode->i_nlink++;
         
 out:
-	CDEBUG(D_INODE, "link result %d\n",error);
 	unlock_kernel();
 	return(error);
 }
@@ -415,8 +367,6 @@
 		return -ENAMETOOLONG;
 	}
 
-        CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
-
 	/*
 	 * This entry is now negative. Since we do not create
 	 * an inode for the entry we have to drop it. 
@@ -429,7 +379,6 @@
 	if ( !error )
 		coda_dir_changed(dir_inode, 0);
 
-        CDEBUG(D_INODE, "in symlink result %d\n",error);
 	unlock_kernel();
         return error;
 }
@@ -444,12 +393,8 @@
 	lock_kernel();
 	coda_vfs_stat.unlink++;
 
-        CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , 
-	       coda_i2s(dir), dir->i_ino);
-
         error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
         if ( error ) {
-                CDEBUG(D_INODE, "upc returned error %d\n", error);
 		unlock_kernel();
                 return error;
         }
@@ -477,7 +422,6 @@
 	error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
 
         if ( error ) {
-                CDEBUG(D_INODE, "upc returned error %d\n", error);
 		unlock_kernel();
                 return error;
         }
@@ -504,11 +448,6 @@
 	lock_kernel();
 	coda_vfs_stat.rename++;
 
-        CDEBUG(D_INODE, "old: %s, (%d length), new: %s"
-	       "(%d length). old:d_count: %d, new:d_count: %d\n", 
-	       old_name, old_length, new_name, new_length,
-	       atomic_read(&old_dentry->d_count), atomic_read(&new_dentry->d_count));
-
         error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), 
 			     coda_i2f(new_dir), old_length, new_length, 
 			     (const char *) old_name, (const char *)new_name);
@@ -526,8 +465,6 @@
 			coda_flag_inode(new_dir, C_VATTR);
                 }
 	}
-
-	CDEBUG(D_INODE, "result %d\n", error); 
 	unlock_kernel();
 
 	return error;
@@ -535,155 +472,108 @@
 
 
 /* file operations for directories */
-int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
+int coda_readdir(struct file *coda_file, void *dirent,  filldir_t filldir)
 {
         int result = 0;
-	struct dentry *cdentry;
-	struct inode *cinode, *inode = file->f_dentry->d_inode;
-	struct file *cfile, fakefile;
-	struct coda_inode_info *cii = ITOC(inode);
+	struct dentry *coda_dentry = coda_file->f_dentry;
+	struct inode *coda_inode = coda_dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(coda_inode);
+	struct file *host_file = cii->c_container;
+
+        BUG_ON(!host_file);
 
 	coda_vfs_stat.readdir++;
 
-        cfile = cii->c_container;
-        if (!cfile) BUG();
+	/* Access to both host and coda f_pos fields is serialized on the
+	 * coda_file->f_dentry->d_inode->i_sem which has already been taken by
+	 * vfs_readdir. Userspace shouldn't 'play' with the container file as
+	 * long as the file is held open. */
+	host_file->f_pos = coda_file->f_pos;
 
-	cinode = cii->c_container->f_dentry->d_inode;
-	if ( S_ISREG(cinode->i_mode) ) {
+	if ( !host_file->f_op->readdir )
 		/* Venus: we must read Venus dirents from the file */
-		cdentry = cii->c_container->f_dentry;
-		coda_prepare_fakefile(file, cdentry, &fakefile);
-
-		result = coda_venus_readdir(&fakefile, dirent, filldir);
-
-		file->f_pos = fakefile.f_pos;
-		file->f_version = fakefile.f_version;
-        } else {
-		/* potemkin case: we are handed a directory inode */
-		result = vfs_readdir(file, filldir, dirent);
-        }
+		result = coda_venus_readdir(host_file, filldir, dirent);
+        else
+		/* potemkin case: we were handed a directory inode */
+		result = vfs_readdir(host_file, filldir, dirent);
 
+	coda_file->f_pos = host_file->f_pos;
 	return result;
 }
 
-/* support routines */
-
-/* instantiate a fake file to pass to coda_venus_readdir */
-static void coda_prepare_fakefile(struct file *coda_file, 
-				  struct dentry *cont_dentry,
-				  struct file *fake_file)
-{
-	fake_file->f_dentry = cont_dentry;
-	fake_file->f_pos = coda_file->f_pos;
-	fake_file->f_version = coda_file->f_version;
-	fake_file->f_op = cont_dentry->d_inode->i_fop;
-	fake_file->f_flags = coda_file->f_flags;
-	return ;
-}
-
-/* 
- * this structure is manipulated by filldir in vfs layer.
- * the count holds the remaining amount of space in the getdents buffer,
- * beyond the current_dir pointer.
- *
- * What structure is this comment referring to?? -JH
- */
+static inline unsigned int CDT2DT(unsigned char cdt)
+{
+    unsigned int dt;
 
-/* should be big enough to hold any single directory entry */
-#define DIR_BUFSIZE 2048
+    switch(cdt) {
+    case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
+    case CDT_FIFO:    dt = DT_FIFO;    break;
+    case CDT_CHR:     dt = DT_CHR;     break;
+    case CDT_DIR:     dt = DT_DIR;     break;
+    case CDT_BLK:     dt = DT_BLK;     break;
+    case CDT_REG:     dt = DT_REG;     break;
+    case CDT_LNK:     dt = DT_LNK;     break;
+    case CDT_SOCK:    dt = DT_SOCK;    break;
+    case CDT_WHT:     dt = DT_WHT;     break;
+    default:	      dt = DT_UNKNOWN; break;
+    }
+    return dt;
+}
 
-static int coda_venus_readdir(struct file *filp, void *getdent, 
-			      filldir_t filldir)
+/* support routines */
+static int coda_venus_readdir(struct file *filp, filldir_t filldir,
+			      void *getdent)
 {
-        int bufsize;
-	int offset = filp->f_pos; /* offset in the directory file */
-	int count = 0;
-	int pos = 0;      /* offset in the block we read */
-	int result = 0; /* either an error or # of entries returned */
-	int errfill;
-        char *buff = NULL;
-        struct venus_dirent *vdirent;
-        int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
-	int i;
-
-        CODA_ALLOC(buff, char *, DIR_BUFSIZE);
-        if ( !buff ) { 
-                printk("coda_venus_readdir: out of memory.\n");
-                return -ENOMEM;
-        }
+	int result = 0; /* # of entries returned */
+        struct venus_dirent *vdir;
+        unsigned long vdir_size =
+	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
+	int ret;
+
+	vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
+	if (!vdir) return -ENOMEM;
+
+	while(1) {
+		/* we use this routine to read the file into our buffer */
+		ret = kernel_read(filp, filp->f_pos, (char *)vdir,
+				  sizeof(*vdir));
+		if (ret < 0) {
+			printk("coda_venus_readdir: read dir failed %d\n", ret);
+			break;
+		}
+		if (ret == 0) break; /* end of directory file reached */
 
-        /* we use this routine to read the file into our buffer */
-        bufsize = kernel_read(filp, filp->f_pos, buff, DIR_BUFSIZE);
-        if ( bufsize < 0) {
-                printk("coda_venus_readdir: cannot read directory %d.\n",
-		       bufsize);
-                result = bufsize;
-                goto exit;
-        }
-        if ( bufsize == 0) {
-                result = 0;
-                goto exit;
-        }
-	
-        /* Parse and write into user space. Filldir tells us when done! */
-        CDEBUG(D_FILE, "buffsize: %d offset %d, count %d.\n", 
-	       bufsize, offset, count);
-
-	i = 0;
-	result = 0; 
-        while ( pos + string_offset < bufsize && i < 1024) {
-                vdirent = (struct venus_dirent *) (buff + pos);
-
-                /* test if the name is fully in the buffer */
-                if ( pos + string_offset + (int) vdirent->d_namlen >= bufsize ){
-			if ( result == 0 )
-				printk("CODA: Invalid directory cfino: %ld\n", 
-				       filp->f_dentry->d_inode->i_ino);
-                        break;
-                }
-                /* now we are certain that we can read the entry from buff */
+		/* catch truncated reads */
+		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
+		    printk("coda_venus_readdir: short read: %ld\n", 
+			   filp->f_dentry->d_inode->i_ino);
+		    ret = -EBADF;
+		    break;
+		}
+		/* validate whether the directory file actually makes sense */
+		if (vdir->d_reclen < vdir_size + vdir->d_namlen ||
+		    vdir->d_namlen > CODA_MAXNAMLEN) {
+		    printk("coda_venus_readdir: Invalid directory: %ld\n", 
+			   filp->f_dentry->d_inode->i_ino);
+		    ret = -EBADF;
+		    break;
+		}
 
-                /* if we don't have a null entry, copy it */
-                if ( vdirent->d_fileno && vdirent->d_reclen ) {
-                        int namlen  = vdirent->d_namlen;
-                        off_t offs  = filp->f_pos; 
-                        ino_t ino   = vdirent->d_fileno;
-                        char *name  = vdirent->d_name;
-
-			errfill = filldir(getdent,  name, namlen, 
-					  offs, ino, DT_UNKNOWN); 
-CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
-			/* errfill means no space for filling in this round */
-			if ( errfill < 0 ) {
-				result = 0;
-				break;
-			}
-                        /* adjust count */
-                        result++;
-                }
-                /* next one */
-                filp->f_pos += vdirent->d_reclen;
-		if ( filp->f_pos > filp->f_dentry->d_inode->i_size )
-			break; 
-		if ( !vdirent->d_reclen ) {
-			printk("CODA: Invalid directory, cfino: %ld\n", 
-			       filp->f_dentry->d_inode->i_ino);
-			result = -EINVAL;
-			break;
+		/* skip null entries */
+		if (vdir->d_fileno) {
+		    unsigned int d_type = CDT2DT(vdir->d_type);
+		    ret = filldir(getdent, vdir->d_name, vdir->d_namlen, 
+				  filp->f_pos, vdir->d_fileno, d_type); 
+		    /* failure means no space for filling in this round */
+		    if (ret < 0) break;
+		    result++;
 		}
-                pos += (unsigned int) vdirent->d_reclen;
-		i++;
-	} 
-
-	if ( i >= 1024 ) {
-		printk("Repeating too much in readdir %ld\n", 
-		       filp->f_dentry->d_inode->i_ino);
-		result = -EINVAL;
+		/* we'll always have progress because d_reclen is unsigned and
+		 * we've already established it is non-zero. */
+		filp->f_pos += vdir->d_reclen;
 	}
-
-exit:
-        CODA_FREE(buff, DIR_BUFSIZE);
-        return result;
+	kfree(vdir);
+        return result ? result : ret;
 }
 
 /* called when a cache lookup succeeds */
@@ -701,7 +591,7 @@
 		goto bad;
 
 	cii = ITOC(de->d_inode);
-	if (cii->c_flags & (C_PURGE | C_FLUSH))
+	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
 		goto out;
 
 	shrink_dcache_parent(de);
@@ -710,12 +600,9 @@
 	if (cii->c_flags & C_FLUSH) 
 		coda_flag_inode_children(inode, C_FLUSH);
 
-	if (atomic_read(&de->d_count) > 1) {
+	if (atomic_read(&de->d_count) > 1)
 		/* pretend it's valid, but don't change the flags */
-		CDEBUG(D_DOWNCALL, "BOOM for: ino %ld, %s\n",
-		       de->d_inode->i_ino, coda_f2s(&cii->c_fid));
 		goto out;
-	}
 
 	/* clear the flags. */
 	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
@@ -741,9 +628,6 @@
 
 	flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE;
 	if (is_bad_inode(dentry->d_inode) || flags) {
-		CDEBUG(D_DOWNCALL, "bad inode, unhashing %s/%s, %ld\n", 
-		       dentry->d_parent->d_name.name, dentry->d_name.name,
-		       dentry->d_inode->i_ino);
 		return 1;
 	}
 	return 0;
@@ -766,10 +650,6 @@
 	struct inode *inode = dentry->d_inode;
 	struct coda_inode_info *cii = ITOC(inode);
 
-	CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
-	       dentry->d_name.len, dentry->d_name.name,
-	       dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
-
 	lock_kernel();
 	if ( !cii->c_flags )
 		goto ok;
@@ -798,9 +678,7 @@
 		if (inode->i_ino != old_ino)
 			goto return_bad_inode;
 		
-		if ( cii->c_flags ) 
-			coda_flag_inode_children(inode, C_FLUSH);
-		
+		coda_flag_inode_children(inode, C_FLUSH);
 		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
 	}
 
diff -urN linux-2.5.6-pre2/fs/coda/file.c linux-2.5.6-pre3/fs/coda/file.c
--- linux-2.5.6-pre2/fs/coda/file.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/fs/coda/file.c	Wed Mar  6 17:17:54 2002
@@ -69,6 +69,7 @@
 
 	cfile->f_flags = flags;
 	inode->i_size = cinode->i_size;
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	up(&inode->i_sem);
 
 	return ret;
@@ -103,12 +104,8 @@
 	lock_kernel();
 	coda_vfs_stat.open++;
 
-	CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
-	       f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags);
-
 	error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh); 
 	if (error || !fh) {
-	        CDEBUG(D_FILE, "coda_open: venus_open result %d\n", error);
 		unlock_kernel();
 		return error;
 	}
@@ -132,12 +129,6 @@
 		f->private_data = cred;
 	}
 
-	CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", 
-	       error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino);
-	CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", 
-	       fh->f_dentry->d_inode->i_ino,
-	       atomic_read(&fh->f_dentry->d_inode->i_count),
-               fh->f_dentry->d_inode->i_op);
 	unlock_kernel();
 	return 0;
 }
@@ -174,8 +165,6 @@
 
 	cinode = cfile->f_dentry->d_inode;
 
-	CDEBUG(D_FILE, "FLUSH coda (file %p ct %d)\n", file, fcnt);
-
 	err = venus_store(inode->i_sb, coda_i2f(inode), cflags,
                           (struct coda_cred *)file->private_data);
 	if (err == -EOPNOTSUPP) {
@@ -183,7 +172,6 @@
 		err = 0;
 	}
 
-	CDEBUG(D_FILE, "coda_flush: result: %d\n", err);
 	return err;
 }
 
diff -urN linux-2.5.6-pre2/fs/coda/inode.c linux-2.5.6-pre3/fs/coda/inode.c
--- linux-2.5.6-pre2/fs/coda/inode.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/fs/coda/inode.c	Wed Mar  6 17:17:54 2002
@@ -245,10 +245,6 @@
 {
 	struct coda_inode_info *cii = ITOC(inode);
 
-        CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", 
-	       inode->i_ino, atomic_read(&inode->i_count));        
-	CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
-
 	if (cii->c_container) BUG();
 	
         list_del_init(&cii->c_cilist);
@@ -264,9 +260,9 @@
 	
         memset(&vattr, 0, sizeof(vattr)); 
 
+	inode->i_ctime = CURRENT_TIME;
         coda_iattr_to_vattr(iattr, &vattr);
         vattr.va_type = C_VNON; /* cannot set type */
-	CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
 
 	/* Venus is responsible for truncating the container-file!!! */
 	error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
@@ -275,7 +271,6 @@
 	        coda_vattr_to_iattr(inode, &vattr); 
 		coda_cache_clear_inode(inode);
 	}
-	CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error);
 
 	return error;
 }
diff -urN linux-2.5.6-pre2/fs/coda/pioctl.c linux-2.5.6-pre3/fs/coda/pioctl.c
--- linux-2.5.6-pre2/fs/coda/pioctl.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/fs/coda/pioctl.c	Wed Mar  6 17:17:54 2002
@@ -65,8 +65,6 @@
          * Look up the pathname. Note that the pathname is in 
          * user memory, and namei takes care of this
          */
-	CDEBUG(D_PIOCTL, "namei, data.follow = %d\n", 
-	       data.follow);
         if ( data.follow ) {
                 error = user_path_walk(data.path, &nd);
 	} else {
@@ -74,15 +72,11 @@
 	}
 		
 	if ( error ) {
-                CDEBUG(D_PIOCTL, "error: lookup fails.\n");
 		return error;
         } else {
 	        target_inode = nd.dentry->d_inode;
 	}
 	
-	CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%x\n",
-	       target_inode->i_ino, kdev_val(target_inode->i_dev));
-
 	/* return if it is not a Coda inode */
 	if ( target_inode->i_sb != inode->i_sb ) {
 		path_release(&nd);
@@ -94,9 +88,6 @@
 
 	error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
 
-        CDEBUG(D_PIOCTL, "ioctl on inode %ld\n", target_inode->i_ino);
-	CDEBUG(D_DOWNCALL, "dput on ino: %ld, icount %d, dcount %d\n", target_inode->i_ino, 
-	       atomic_read(&target_inode->i_count), atomic_read(&nd.dentry->d_count));
 	path_release(&nd);
         return error;
 }
diff -urN linux-2.5.6-pre2/fs/coda/psdev.c linux-2.5.6-pre3/fs/coda/psdev.c
--- linux-2.5.6-pre2/fs/coda/psdev.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/fs/coda/psdev.c	Wed Mar  6 17:17:54 2002
@@ -114,9 +114,6 @@
 	if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
 	        return -EFAULT;
 
-	CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), nbytes %ld\n", 
-	       current->pid, hdr.opcode, hdr.unique, (long)nbytes);
-
         if (DOWNCALL(hdr.opcode)) {
 		struct super_block *sb = NULL;
                 union outputArgs *dcbuf;
@@ -124,11 +121,9 @@
 
 		sb = vcp->vc_sb;
 		if ( !sb ) {
-			CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n");
                         count = nbytes;
                         goto out;
 		}
-		CDEBUG(D_PSDEV, "handling downcall\n");
 
 		if  ( nbytes < sizeof(struct coda_out_hdr) ) {
 		        printk("coda_downcall opc %ld uniq %ld, not enough!\n",
@@ -182,8 +177,6 @@
 		goto out;
 	}
 
-	CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", hdr.unique);
-
         /* move data into response buffer. */
 	if (req->uc_outSize < nbytes) {
                 printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n",
@@ -209,10 +202,6 @@
 		outp->fh = fget(outp->fd);
 	}
 
-	CDEBUG(D_PSDEV, 
-	       "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n", 
-	        (long)count, hdr.opcode, hdr.unique, &req);
-
         wake_up(&req->uc_sleep);
 out:
         return(count ? count : retval);  
@@ -277,9 +266,6 @@
 		goto out;
 	}
 
-	CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", 
-			req->uc_opcode, req->uc_unique);
-
 	CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
 	upc_free(req);
 out:
@@ -315,8 +301,6 @@
 	
 	file->private_data = vcp;
 
-	CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse);
-
 	unlock_kernel();
         return 0;
 }
@@ -335,14 +319,12 @@
 		return -1;
 	}
 
-	CDEBUG(D_PSDEV, "psdev_release: inuse %d\n", vcp->vc_inuse);
 	if (--vcp->vc_inuse) {
 		unlock_kernel();
 		return 0;
 	}
         
         /* Wakeup clients so they can return. */
-	CDEBUG(D_PSDEV, "wake up pending clients\n");
 	lh = vcp->vc_pending.next;
 	next = lh;
 	while ( (lh = next) != &vcp->vc_pending) {
@@ -359,13 +341,11 @@
         }
         
 	lh = &vcp->vc_processing;
-	CDEBUG(D_PSDEV, "wake up processing clients\n");
 	while ( (lh = lh->next) != &vcp->vc_processing) {
 		req = list_entry(lh, struct upc_req, uc_chain);
 		req->uc_flags |= REQ_ABORT;
 	        wake_up(&req->uc_sleep);
         }
-	CDEBUG(D_PSDEV, "Done.\n");
 
 	unlock_kernel();
 	return 0;
diff -urN linux-2.5.6-pre2/fs/coda/sysctl.c linux-2.5.6-pre3/fs/coda/sysctl.c
--- linux-2.5.6-pre2/fs/coda/sysctl.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/fs/coda/sysctl.c	Wed Mar  6 17:17:54 2002
@@ -37,26 +37,18 @@
 
 #define FS_CODA         1       /* Coda file system */
 
-#define CODA_DEBUG  	 1	 /* control debugging */
-#define CODA_ENTRY	 2       /* control enter/leave pattern */
 #define CODA_TIMEOUT    3       /* timeout on upcalls to become intrble */
-#define CODA_MC         4       /* use/do not use the access cache */
 #define CODA_HARD       5       /* mount type "hard" or "soft" */
 #define CODA_VFS 	 6       /* vfs statistics */
 #define CODA_UPCALL 	 7       /* upcall statistics */
-#define CODA_PERMISSION	 8       /* permission statistics */
 #define CODA_CACHE_INV 	 9       /* cache invalidation statistics */
 #define CODA_FAKE_STATFS 10	 /* don't query venus for actual cache usage */
 
 static ctl_table coda_table[] = {
-	{CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &proc_dointvec},
-	{CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
- 	{CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &proc_dointvec}, 
  	{CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
  	{CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
  	{CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
  	{CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
- 	{CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
  	{CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
  	{CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
 	{ 0 }
@@ -68,7 +60,6 @@
 };
 
 struct coda_vfs_stats		coda_vfs_stat;
-struct coda_permission_stats	coda_permission_stat;
 struct coda_cache_inv_stats	coda_cache_inv_stat;
 struct coda_upcall_stats_entry  coda_upcall_stat[CODA_NCALLS];
 struct coda_upcallstats         coda_callstats;
@@ -126,11 +117,6 @@
 	memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
 }
 
-void reset_coda_permission_stats( void )
-{
-	memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
-}
-
 void reset_coda_cache_inv_stats( void )
 {
 	memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
@@ -141,7 +127,6 @@
 		    unsigned long runtime )
 {
 	unsigned long time = runtime;	/* time in us */
-	CDEBUG(D_SPECIAL, "time: %ld\n", time);
 
 	if ( pentry->count == 0 ) {
 		pentry->time_sum = pentry->time_squared_sum = 0;
@@ -257,21 +242,6 @@
 	return 0;
 }
 
-int do_reset_coda_permission_stats( ctl_table * table, int write, 
-				    struct file * filp, void * buffer, 
-				    size_t * lenp )
-{
-	if ( write ) {
-		reset_coda_permission_stats();
-
-		filp->f_pos += *lenp;
-	} else {
-		*lenp = 0;
-	}
-
-	return 0;
-}
-
 int do_reset_coda_cache_inv_stats( ctl_table * table, int write, 
 				   struct file * filp, void * buffer, 
 				   size_t * lenp )
@@ -394,35 +364,6 @@
 	return len;
 }
 
-int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
-				    int length)
-{
-	int len=0;
-	off_t begin;
-	struct coda_permission_stats * ps = & coda_permission_stat;
-  
-	/* this works as long as we are below 1024 characters! */
-	len += sprintf( buffer,
-			"Coda permission statistics\n"
-			"==========================\n\n"
-			"count\t\t%9d\n"
-			"hit count\t%9d\n",
-
-			ps->count,
-			ps->hit_count );
-  
-	begin = offset;
-	*start = buffer + begin;
-	len -= begin;
-
-	if ( len > length )
-		len = length;
-	if ( len < 0 )
-		len = 0;
-
-	return len;
-}
-
 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
 				   int length)
 {
@@ -484,7 +425,6 @@
 	memset(&coda_callstats, 0, sizeof(coda_callstats));
 	reset_coda_vfs_stats();
 	reset_coda_upcall_stats();
-	reset_coda_permission_stats();
 	reset_coda_cache_inv_stats();
 
 #ifdef CONFIG_PROC_FS
@@ -493,7 +433,6 @@
 		proc_fs_coda->owner = THIS_MODULE;
 		coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
 		coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
-		coda_proc_create("permission_stats", coda_permission_stats_get_info);
 		coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
 	}
 #endif
@@ -516,7 +455,6 @@
 
 #if CONFIG_PROC_FS
         remove_proc_entry("cache_inv_stats", proc_fs_coda);
-        remove_proc_entry("permission_stats", proc_fs_coda);
         remove_proc_entry("upcall_stats", proc_fs_coda);
         remove_proc_entry("vfs_stats", proc_fs_coda);
 	remove_proc_entry("coda", proc_root_fs);
diff -urN linux-2.5.6-pre2/fs/coda/upcall.c linux-2.5.6-pre3/fs/coda/upcall.c
--- linux-2.5.6-pre2/fs/coda/upcall.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/fs/coda/upcall.c	Wed Mar  6 17:17:54 2002
@@ -89,8 +89,6 @@
 	        printk("coda_get_rootfid: error %d\n", error);
 	} else {
 		*fidp = (ViceFid) outp->coda_root.VFid;
-		CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
-		       fidp->Volume, fidp->Vnode);
 	}
 
 	CODA_FREE(inp, insize);
@@ -131,7 +129,6 @@
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-        CDEBUG(D_SUPER, " result %d\n", error); 
         CODA_FREE(inp, insize);
         return error;
 }
@@ -313,8 +310,6 @@
         memcpy((char *)(inp) + offset, new_name, new_length);
         *((char *)inp + offset + new_length) = '\0';
 
-        CDEBUG(D_INODE, "destname in packet: %s\n", 
-              (char *)inp + (int) inp->coda_rename.destname);
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
 	CODA_FREE(inp, insize);
@@ -426,7 +421,6 @@
 		*(buffer + retlen) = '\0';
 	}
         
-        CDEBUG(D_INODE, " result %d\n",error);
         CODA_FREE(inp, insize);
         return error;
 }
@@ -455,7 +449,6 @@
         
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-        CDEBUG(D_INODE, " result %d\n",error);
 	CODA_FREE(inp, insize);
         return error;
 }
@@ -491,7 +484,6 @@
 
 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-        CDEBUG(D_INODE, " result %d\n",error);
 	CODA_FREE(inp, insize);
         return error;
 }
@@ -580,9 +572,6 @@
         
 	/* Copy out the OUT buffer. */
         if (outp->coda_ioctl.len > data->vi.out_size) {
-                CDEBUG(D_FILE, "return len %d <= request len %d\n",
-                      outp->coda_ioctl.len, 
-                      data->vi.out_size);
 		error = -EINVAL;
         } else {
 		error = verify_area(VERIFY_WRITE, data->vi.out, 
@@ -623,7 +612,6 @@
 		printk("coda_statfs: Venus returns: %d\n", error);
 	}
 
-        CDEBUG(D_INODE, " result %d\n",error);
         CODA_FREE(inp, insize);
         return error;
 }
@@ -684,10 +672,6 @@
 		end.tv_usec -= begin.tv_usec;
 	}
 
-	CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
-		begin.tv_sec, (unsigned long)begin.tv_usec,
-		end.tv_sec, (unsigned long)end.tv_usec);
-
 	return 	((end.tv_sec * 1000000) + end.tv_usec);
 }
 
@@ -738,10 +722,6 @@
 	/* Append msg to pending queue and poke Venus. */
 	list_add(&(req->uc_chain), vcommp->vc_pending.prev);
         
-	CDEBUG(D_UPCALL, 
-	       "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
-	       current->pid, req->uc_opcode, req->uc_unique, req);
-
 	wake_up_interruptible(&vcommp->vc_waitq);
 	/* We can be interrupted while we wait for Venus to process
 	 * our request.  If the interrupt occurs before Venus has read
@@ -756,29 +736,17 @@
 	runtime = coda_waitfor_upcall(req, vcommp);
 	coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
 
-	CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
-	       req->uc_opcode, jiffies - req->uc_posttime, 
-	       req->uc_unique, req->uc_outSize);
-	CDEBUG(D_UPCALL, 
-	       "..process %d woken up by Venus for req at %p, data at %p\n", 
-	       current->pid, req, req->uc_data);
 	if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
 	    /* Op went through, interrupt or not... */
 	    if (req->uc_flags & REQ_WRITE) {
 		out = (union outputArgs *)req->uc_data;
 		/* here we map positive Venus errors to kernel errors */
 		error = -out->oh.result;
-		CDEBUG(D_UPCALL, 
-		       "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
-		       out->oh.unique, out->oh.opcode, out->oh.result, out);
 		*outSize = req->uc_outSize;
 		goto exit;
 	    }
 	    if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
 		/* Interrupted before venus read it. */
-		CDEBUG(D_UPCALL, 
-		       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
-		       req->uc_opcode, req->uc_unique, req->uc_flags);
 		list_del(&(req->uc_chain));
 		/* perhaps the best way to convince the app to
 		   give up? */
@@ -790,10 +758,6 @@
 		    union inputArgs *sig_inputArgs;
 		    struct upc_req *sig_req;
 		    
-		    CDEBUG(D_UPCALL, 
-			   "Sending Venus a signal: op = %d.%d, flags = %x\n",
-			   req->uc_opcode, req->uc_unique, req->uc_flags);
-		    
 		    list_del(&(req->uc_chain));
 		    error = -ENOMEM;
 		    sig_req = upc_alloc();
@@ -815,9 +779,6 @@
 		    sig_req->uc_unique = sig_inputArgs->ih.unique;
 		    sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 		    sig_req->uc_outSize = sizeof(struct coda_in_hdr);
-		    CDEBUG(D_UPCALL, 
-			   "coda_upcall: enqueing signal msg (%d, %d)\n",
-			   sig_req->uc_opcode, sig_req->uc_unique);
 		    
 		    /* insert at head of queue! */
 		    list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
@@ -876,16 +837,13 @@
 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 {
 	/* Handle invalidation requests. */
-          if ( !sb || !sb->s_root || !sb->s_root->d_inode) { 
-	          CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
+          if ( !sb || !sb->s_root || !sb->s_root->d_inode)
 		  return 0; 
-	  }
 
 	  switch (opcode) {
 
 	  case CODA_FLUSH : {
 	           clstats(CODA_FLUSH);
-		   CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
 		   coda_cache_clear_all(sb, NULL);
 		   shrink_dcache_sb(sb);
 		   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
@@ -894,7 +852,6 @@
 
 	  case CODA_PURGEUSER : {
 	           struct coda_cred *cred = &out->coda_purgeuser.cred;
-		   CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
 		   if ( !cred ) {
 		           printk("PURGEUSER: null cred!\n");
 			   return 0;
@@ -907,19 +864,14 @@
 	  case CODA_ZAPDIR : {
 	          struct inode *inode;
 		  ViceFid *fid = &out->coda_zapdir.CodaFid;
-		  CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
 		  clstats(CODA_ZAPDIR);
 
 		  inode = coda_fid_to_inode(fid, sb);
 		  if (inode) {
-			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n", 
-				 inode->i_ino);
 			  coda_flag_inode_children(inode, C_PURGE);
-			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
 	                  coda_flag_inode(inode, C_VATTR);
 			  iput(inode);
-		  } else 
-			  CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
+		  }
 		  
 		  return(0);
 	  }
@@ -928,27 +880,20 @@
 	          struct inode *inode;
 		  struct ViceFid *fid = &out->coda_zapfile.CodaFid;
 		  clstats(CODA_ZAPFILE);
-		  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) {
-			  CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
-				 inode->i_ino);
 	                  coda_flag_inode(inode, C_VATTR);
 			  iput(inode);
-		  } else 
-			  CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
+		  }
 		  return 0;
 	  }
 
 	  case CODA_PURGEFID : {
 	          struct inode *inode;
 		  ViceFid *fid = &out->coda_purgefid.CodaFid;
-		  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
 		  clstats(CODA_PURGEFID);
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) { 
-			CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
-			       inode->i_ino);
 			coda_flag_inode_children(inode, C_PURGE);
 
 			/* catch the dentries later if some are still busy */
@@ -956,8 +901,7 @@
 			d_prune_aliases(inode);
 
 			iput(inode);
-		  } else 
-			CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
+		  }
 		  return 0;
 	  }
 
@@ -966,16 +910,11 @@
 		  ViceFid *oldfid = &out->coda_replace.OldFid;
 		  ViceFid *newfid = &out->coda_replace.NewFid;
 		  clstats(CODA_REPLACE);
-		  CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
 		  inode = coda_fid_to_inode(oldfid, sb);
 		  if ( inode ) { 
-			  CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
-				 inode->i_ino);
 			  coda_replace_fid(inode, oldfid, newfid);
 			  iput(inode);
-		  }else 
-			  CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
-		  
+		  }
 		  return 0;
 	  }
 	  }
diff -urN linux-2.5.6-pre2/fs/exec.c linux-2.5.6-pre3/fs/exec.c
--- linux-2.5.6-pre2/fs/exec.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/fs/exec.c	Wed Mar  6 17:17:55 2002
@@ -343,15 +343,11 @@
 struct file *open_exec(const char *name)
 {
 	struct nameidata nd;
-	struct inode *inode;
-	struct file *file;
-	int err = 0;
+	int err = path_lookup(name, LOOKUP_FOLLOW, &nd);
+	struct file *file = ERR_PTR(err);
 
-	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		err = path_walk(name, &nd);
-	file = ERR_PTR(err);
 	if (!err) {
-		inode = nd.dentry->d_inode;
+		struct inode *inode = nd.dentry->d_inode;
 		file = ERR_PTR(-EACCES);
 		if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
 		    S_ISREG(inode->i_mode)) {
diff -urN linux-2.5.6-pre2/fs/hpfs/ea.c linux-2.5.6-pre3/fs/hpfs/ea.c
--- linux-2.5.6-pre2/fs/hpfs/ea.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/fs/hpfs/ea.c	Wed Mar  6 17:17:55 2002
@@ -9,8 +9,8 @@
 #include <linux/string.h>
 #include "hpfs_fn.h"
 
-/* Remove external extended attributes. ano specifies wheter a is a 
-   direct sector where eas start or an anode */
+/* Remove external extended attributes. ano specifies whether a is a 
+   direct sector where eas starts or an anode */
 
 void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
 {
diff -urN linux-2.5.6-pre2/fs/intermezzo/kml_reint.c linux-2.5.6-pre3/fs/intermezzo/kml_reint.c
--- linux-2.5.6-pre2/fs/intermezzo/kml_reint.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/fs/intermezzo/kml_reint.c	Wed Mar  6 17:17:55 2002
@@ -360,8 +360,7 @@
         struct dentry *dentry;
 	int error;
 
-	if (path_init(pathname, LOOKUP_PARENT, &nd))
-		error = path_walk(mtpt, &nd);
+	error = path_lookup(pathname, LOOKUP_PARENT, &nd);
         if (error) {
                 CDEBUG (D_KML, "Yean!!!!::Can't find mtpt::%s\n", mtpt);
                 return error;
diff -urN linux-2.5.6-pre2/fs/intermezzo/presto.c linux-2.5.6-pre3/fs/intermezzo/presto.c
--- linux-2.5.6-pre2/fs/intermezzo/presto.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/fs/intermezzo/presto.c	Wed Mar  6 17:17:55 2002
@@ -32,7 +32,6 @@
 
 int presto_walk(const char *name, struct nameidata *nd)
 {
-        int err;
         /* we do not follow symlinks to support symlink operations 
            correctly. The vfs should always hand us resolved dentries
            so we should not be required to use LOOKUP_FOLLOW. At the
@@ -40,13 +39,8 @@
            resolved pathname and not the symlink. SHP
            XXX: This code implies that direct symlinks do not work. SHP
         */
-        unsigned int flags = LOOKUP_POSITIVE;
-
-        ENTRY;
-        err = 0;
-        if (path_init(name, flags, nd)) 
-                err = path_walk(name, nd);
-        return err;
+        unsigned int flags = 0;
+        return path_lookup(name, flags, nd);
 }
 
 inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
diff -urN linux-2.5.6-pre2/fs/intermezzo/vfs.c linux-2.5.6-pre3/fs/intermezzo/vfs.c
--- linux-2.5.6-pre2/fs/intermezzo/vfs.c	Wed Mar  6 17:17:37 2002
+++ linux-2.5.6-pre3/fs/intermezzo/vfs.c	Wed Mar  6 17:17:55 2002
@@ -538,9 +538,7 @@
         }
 
         /* this looks up the parent */
-//        if (path_init(pathname, LOOKUP_FOLLOW | LOOKUP_POSITIVE, &nd))
-        if (path_init(pathname,  LOOKUP_PARENT, &nd))
-                error = path_walk(pathname, &nd);
+        error = path_lookup(pathname,  LOOKUP_PARENT, &nd);
         if (error) {
 		EXIT;
                 goto exit;
@@ -673,56 +671,47 @@
                          struct lento_vfs_context *info)
 {
         int error;
-        char * from;
+	struct dentry *new_dentry;
+	struct nameidata nd, old_nd;
         char * to;
         struct presto_file_set *fset;
 
-        from = getname(oldname);
-        if(IS_ERR(from))
-                return PTR_ERR(from);
         to = getname(newname);
-        error = PTR_ERR(to);
-        if (!IS_ERR(to)) {
-                struct dentry *new_dentry;
-                struct nameidata nd, old_nd;
-
-                error = 0;
-                if (path_init(from, LOOKUP_POSITIVE, &old_nd))
-                        error = path_walk(from, &old_nd);
-                if (error)
-                        goto exit;
-                if (path_init(to, LOOKUP_PARENT, &nd))
-                        error = path_walk(to, &nd);
-                if (error)
-                        goto out;
-                error = -EXDEV;
-                if (old_nd.mnt != nd.mnt)
-                        goto out;
-                new_dentry = lookup_create(&nd, 0);
-                error = PTR_ERR(new_dentry);
+        if(IS_ERR(to))
+                return PTR_ERR(to);
 
-                if (!IS_ERR(new_dentry)) {
-                        fset = presto_fset(new_dentry);
-                        error = -EINVAL;
-                        if ( !fset ) {
-                                printk("No fileset!\n");
-                                EXIT;
-                                goto out2;
-                        }
-                        error = presto_do_link(fset, old_nd.dentry, 
-                                               nd.dentry,
-                                               new_dentry, info);
-                        dput(new_dentry);
-                }
-        out2:
-                up(&nd.dentry->d_inode->i_sem);
-                path_release(&nd);
-        out:
-                path_release(&old_nd);
-        exit:
-                putname(to);
-        }
-        putname(from);
+	error = __user_walk(oldname, 0, &old_nd);
+	if (error)
+		goto exit;
+	error = path_lookup(to, LOOKUP_PARENT, &nd);
+	if (error)
+		goto out;
+	error = -EXDEV;
+	if (old_nd.mnt != nd.mnt)
+		goto out;
+	new_dentry = lookup_create(&nd, 0);
+	error = PTR_ERR(new_dentry);
+
+	if (!IS_ERR(new_dentry)) {
+		fset = presto_fset(new_dentry);
+		error = -EINVAL;
+		if ( !fset ) {
+			printk("No fileset!\n");
+			EXIT;
+			goto out2;
+		}
+		error = presto_do_link(fset, old_nd.dentry, 
+				       nd.dentry,
+				       new_dentry, info);
+		dput(new_dentry);
+	}
+out2:
+	up(&nd.dentry->d_inode->i_sem);
+	path_release(&nd);
+out:
+	path_release(&old_nd);
+exit:
+	putname(to);
 
         return error;
 }
@@ -843,8 +832,7 @@
         if(IS_ERR(name))
                 return PTR_ERR(name);
 
-        if (path_init(name, LOOKUP_PARENT, &nd))
-                error = path_walk(name, &nd);
+        error = path_lookup(name, LOOKUP_PARENT, &nd);
         if (error)
                 goto exit;
         error = -EISDIR;
@@ -1007,8 +995,7 @@
                 goto exit_from;
         }
 
-        if (path_init(to, LOOKUP_PARENT, &nd)) 
-                error = path_walk(to, &nd);
+        error = path_lookup(to, LOOKUP_PARENT, &nd);
         if (error) {
                 EXIT;
                 goto exit_to;
@@ -1168,8 +1155,7 @@
                 return error;
         }
 
-        if (path_init(pathname, LOOKUP_PARENT, &nd))
-                error = path_walk(pathname, &nd);
+        error = path_lookup(pathname, LOOKUP_PARENT, &nd);
         if (error)
                 goto out_name;
 
@@ -1308,8 +1294,7 @@
         if(IS_ERR(name))
                 return PTR_ERR(name);
 
-        if (path_init(name, LOOKUP_PARENT, &nd))
-                error = path_walk(name, &nd);
+        error = path_lookup(name, LOOKUP_PARENT, &nd);
         if (error)
                 goto exit;
 
@@ -1465,8 +1450,7 @@
         if (IS_ERR(tmp))
                 return PTR_ERR(tmp);
 
-        if (path_init(tmp, LOOKUP_PARENT, &nd))
-                error = path_walk(tmp, &nd);
+        error = path_lookup(tmp, LOOKUP_PARENT, &nd);
         if (error)
                 goto out;
         dentry = lookup_create(&nd, 0);
@@ -1746,14 +1730,12 @@
 
         ENTRY;
 
-        if (path_init(oldname, LOOKUP_PARENT, &oldnd))
-                error = path_walk(oldname, &oldnd);
+        error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
 
         if (error)
                 goto exit;
 
-        if (path_init(newname, LOOKUP_PARENT, &newnd))
-                error = path_walk(newname, &newnd);
+        error = path_lookup(newname, LOOKUP_PARENT, &newnd);
         if (error)
                 goto exit1;
 
diff -urN linux-2.5.6-pre2/fs/jffs2/compr_zlib.c linux-2.5.6-pre3/fs/jffs2/compr_zlib.c
--- linux-2.5.6-pre2/fs/jffs2/compr_zlib.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/fs/jffs2/compr_zlib.c	Wed Mar  6 17:17:55 2002
@@ -1,7 +1,7 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
@@ -31,36 +31,22 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: compr_zlib.c,v 1.8 2001/09/20 15:28:31 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.15 2002/03/04 09:35:48 dwmw2 Exp $
  *
  */
 
-#ifdef __KERNEL__
-#include <linux/zlib.h>
-#else
-#include "zlib.h"
+#ifndef __KERNEL__
+#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
 #endif
 
-#ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/mtd/compatmac.h> /* for min() */
 #include <linux/slab.h>
 #include <linux/jffs2.h>
+#include <linux/zlib.h>
 #include "nodelist.h"
 
-#else
-#define min(x,y) ((x)<(y)?(x):(y))
-#ifndef D1
-#define D1(x)
-#endif
-#define KERN_DEBUG
-#define KERN_NOTICE
-#define KERN_WARNING
-#define printk printf
-#include <stdio.h>
-#include <asm/types.h>
-#endif
-
 	/* Plan: call deflate() with avail_in == *sourcelen, 
 		avail_out = *dstlen - 12 and flush == Z_FINISH. 
 		If it doesn't manage to finish,	call it again with
@@ -70,8 +56,37 @@
 	*/
 #define STREAM_END_SPACE 12
 
+static DECLARE_MUTEX(deflate_sem);
+static DECLARE_MUTEX(inflate_sem);
+static void *deflate_workspace;
+static void *inflate_workspace;
+
+int __init jffs2_zlib_init(void)
+{
+	deflate_workspace = vmalloc(zlib_deflate_workspacesize());
+	if (!deflate_workspace) {
+		printk("Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
+		return -ENOMEM;
+	}
+	D1(printk("Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
+	inflate_workspace = vmalloc(zlib_inflate_workspacesize());
+	if (!inflate_workspace) {
+		printk("Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
+		vfree(deflate_workspace);
+		return -ENOMEM;
+	}
+	D1(printk("Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
+	return 0;
+}
+
+void __exit jffs2_zlib_exit(void)
+{
+	vfree(deflate_workspace);
+	vfree(inflate_workspace);
+}
+
 int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   __u32 *sourcelen, __u32 *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen)
 {
 	z_stream strm;
 	int ret;
@@ -79,22 +94,15 @@
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
-#ifdef __KERNEL__
-	strm.workspace = kmalloc(zlib_deflate_workspacesize(),
-				 GFP_KERNEL);
-	if (strm.workspace == NULL) {
-		printk(KERN_WARNING "deflateInit alloc of workspace failed\n");
-		return -1;
-	}
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&deflate_sem);
+	strm.workspace = deflate_workspace;
 
 	if (Z_OK != zlib_deflateInit(&strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
+		up(&deflate_sem);
 		return -1;
 	}
+
 	strm.next_in = data_in;
 	strm.total_in = 0;
 	
@@ -111,56 +119,44 @@
 			  strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			goto out_err;
+			zlib_deflateEnd(&strm);
+			up(&deflate_sem);
+			return -1;
 		}
 	}
 	strm.avail_out += STREAM_END_SPACE;
 	strm.avail_in = 0;
 	ret = zlib_deflate(&strm, Z_FINISH);
+	zlib_deflateEnd(&strm);
+	up(&deflate_sem);
 	if (ret != Z_STREAM_END) {
 		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		goto out_err;
-
+		return -1;
 	}
-	zlib_deflateEnd(&strm);
-	kfree(strm.workspace);
 
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", strm.total_in, strm.total_out));
+	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
+		  strm.total_in, strm.total_out));
 
 	if (strm.total_out >= strm.total_in)
 		return -1;
 
-
 	*dstlen = strm.total_out;
 	*sourcelen = strm.total_in;
 	return 0;
-
- out_err:
-	zlib_deflateEnd(&strm);
-	kfree(strm.workspace);
-	return -1;
 }
 
 void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      __u32 srclen, __u32 destlen)
+		      uint32_t srclen, uint32_t destlen)
 {
 	z_stream strm;
 	int ret;
 
-#ifdef __KERNEL__
-	strm.workspace = kmalloc(zlib_inflate_workspacesize(),
-				 GFP_KERNEL);
-	if (strm.workspace == NULL) {
-		printk(KERN_WARNING "inflateInit alloc of workspace failed\n");
-		return;
-	}
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&inflate_sem);
+	strm.workspace = inflate_workspace;
 
 	if (Z_OK != zlib_inflateInit(&strm)) {
 		printk(KERN_WARNING "inflateInit failed\n");
+		up(&inflate_sem);
 		return;
 	}
 	strm.next_in = data_in;
@@ -177,5 +173,5 @@
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
 	zlib_inflateEnd(&strm);
-	kfree(strm.workspace);
+	up(&inflate_sem);
 }
diff -urN linux-2.5.6-pre2/fs/jffs2/nodelist.h linux-2.5.6-pre3/fs/jffs2/nodelist.h
--- linux-2.5.6-pre2/fs/jffs2/nodelist.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/jffs2/nodelist.h	Wed Mar  6 17:17:55 2002
@@ -32,6 +32,7 @@
  * under either the RHEPL or the GPL.
  *
  * $Id: nodelist.h,v 1.46.2.1 2002/02/23 14:04:44 dwmw2 Exp $
+ * + zlib_init calls from v1.65
  *
  */
 
@@ -349,3 +350,7 @@
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
 void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
 void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
+
+/* compr_zlib.c */
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
diff -urN linux-2.5.6-pre2/fs/jffs2/super.c linux-2.5.6-pre3/fs/jffs2/super.c
--- linux-2.5.6-pre2/fs/jffs2/super.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/jffs2/super.c	Wed Mar  6 17:17:55 2002
@@ -32,6 +32,7 @@
  * under either the RHEPL or the GPL.
  *
  * $Id: super.c,v 1.48.2.1 2002/02/23 14:13:34 dwmw2 Exp $
+ * + zlib_init calls from v1.56
  *
  */
 
@@ -373,6 +374,11 @@
 	}
 #endif
 
+	ret = jffs2_zlib_init();
+	if (ret) {
+		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+		return ret;
+	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
@@ -389,6 +395,7 @@
 static void __exit exit_jffs2_fs(void)
 {
 	jffs2_destroy_slab_caches();
+	jffs2_zlib_exit();
 	unregister_filesystem(&jffs2_fs_type);
 }
 
diff -urN linux-2.5.6-pre2/fs/namei.c linux-2.5.6-pre3/fs/namei.c
--- linux-2.5.6-pre2/fs/namei.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/fs/namei.c	Wed Mar  6 17:17:55 2002
@@ -609,18 +609,13 @@
 		}
 		err = -ENOENT;
 		if (!inode)
-			goto no_inode;
+			break;
 		if (lookup_flags & LOOKUP_DIRECTORY) {
 			err = -ENOTDIR; 
 			if (!inode->i_op || !inode->i_op->lookup)
 				break;
 		}
 		goto return_base;
-no_inode:
-		err = -ENOENT;
-		if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
-			break;
-		goto return_base;
 lookup_parent:
 		nd->last = this;
 		nd->last_type = LAST_NORM;
@@ -686,17 +681,16 @@
 	struct nameidata nd;
 	struct vfsmount *mnt = NULL, *oldmnt;
 	struct dentry *dentry = NULL, *olddentry;
-	if (emul) {
-		read_lock(&current->fs->lock);
-		nd.mnt = mntget(current->fs->rootmnt);
-		nd.dentry = dget(current->fs->root);
-		read_unlock(&current->fs->lock);
-		nd.flags = LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_POSITIVE;
-		if (path_walk(emul,&nd) == 0) {
-			mnt = nd.mnt;
-			dentry = nd.dentry;
-		}
+	int err;
+
+	if (!emul)
+		goto set_it;
+	err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd);
+	if (err) {
+		mnt = nd.mnt;
+		dentry = nd.dentry;
 	}
+set_it:
 	write_lock(&current->fs->lock);
 	oldmnt = current->fs->altrootmnt;
 	olddentry = current->fs->altroot;
@@ -825,15 +819,11 @@
  */
 int __user_walk(const char *name, unsigned flags, struct nameidata *nd)
 {
-	char *tmp;
-	int err;
+	char *tmp = getname(name);
+	int err = PTR_ERR(tmp);
 
-	tmp = getname(name);
-	err = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
-		err = 0;
-		if (path_init(tmp, flags, nd))
-			err = path_walk(tmp, nd);
+		err = path_lookup(tmp, flags, nd);
 		putname(tmp);
 	}
 	return err;
@@ -1024,8 +1014,7 @@
 	 * The simplest case - just a plain lookup.
 	 */
 	if (!(flag & O_CREAT)) {
-		if (path_init(pathname, lookup_flags(flag), nd))
-			error = path_walk(pathname, nd);
+		error = path_lookup(pathname, lookup_flags(flag), nd);
 		if (error)
 			return error;
 		dentry = nd->dentry;
@@ -1035,8 +1024,7 @@
 	/*
 	 * Create - we need to know the parent.
 	 */
-	if (path_init(pathname, LOOKUP_PARENT, nd))
-		error = path_walk(pathname, nd);
+	error = path_lookup(pathname, LOOKUP_PARENT, nd);
 	if (error)
 		return error;
 
@@ -1281,8 +1269,7 @@
 	if (IS_ERR(tmp))
 		return PTR_ERR(tmp);
 
-	if (path_init(tmp, LOOKUP_PARENT, &nd))
-		error = path_walk(tmp, &nd);
+	error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 	if (error)
 		goto out;
 	dentry = lookup_create(&nd, 0);
@@ -1342,8 +1329,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(tmp, LOOKUP_PARENT, &nd))
-			error = path_walk(tmp, &nd);
+		error = path_lookup(tmp, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 1);
@@ -1434,8 +1420,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 
@@ -1506,8 +1491,7 @@
 	if(IS_ERR(name))
 		return PTR_ERR(name);
 
-	if (path_init(name, LOOKUP_PARENT, &nd))
-		error = path_walk(name, &nd);
+	error = path_lookup(name, LOOKUP_PARENT, &nd);
 	if (error)
 		goto exit;
 	error = -EISDIR;
@@ -1570,8 +1554,7 @@
 		struct dentry *dentry;
 		struct nameidata nd;
 
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
+		error = path_lookup(to, LOOKUP_PARENT, &nd);
 		if (error)
 			goto out;
 		dentry = lookup_create(&nd, 0);
@@ -1634,46 +1617,37 @@
  */
 asmlinkage long sys_link(const char * oldname, const char * newname)
 {
+	struct dentry *new_dentry;
+	struct nameidata nd, old_nd;
 	int error;
-	char * from;
 	char * to;
 
-	from = getname(oldname);
-	if(IS_ERR(from))
-		return PTR_ERR(from);
 	to = getname(newname);
-	error = PTR_ERR(to);
-	if (!IS_ERR(to)) {
-		struct dentry *new_dentry;
-		struct nameidata nd, old_nd;
+	if (IS_ERR(to))
+		return PTR_ERR(to);
 
-		error = 0;
-		if (path_init(from, LOOKUP_POSITIVE, &old_nd))
-			error = path_walk(from, &old_nd);
-		if (error)
-			goto exit;
-		if (path_init(to, LOOKUP_PARENT, &nd))
-			error = path_walk(to, &nd);
-		if (error)
-			goto out;
-		error = -EXDEV;
-		if (old_nd.mnt != nd.mnt)
-			goto out_release;
-		new_dentry = lookup_create(&nd, 0);
-		error = PTR_ERR(new_dentry);
-		if (!IS_ERR(new_dentry)) {
-			error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-			dput(new_dentry);
-		}
-		up(&nd.dentry->d_inode->i_sem);
+	error = __user_walk(oldname, 0, &old_nd);
+	if (error)
+		goto exit;
+	error = path_lookup(to, LOOKUP_PARENT, &nd);
+	if (error)
+		goto out;
+	error = -EXDEV;
+	if (old_nd.mnt != nd.mnt)
+		goto out_release;
+	new_dentry = lookup_create(&nd, 0);
+	error = PTR_ERR(new_dentry);
+	if (!IS_ERR(new_dentry)) {
+		error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+		dput(new_dentry);
+	}
+	up(&nd.dentry->d_inode->i_sem);
 out_release:
-		path_release(&nd);
+	path_release(&nd);
 out:
-		path_release(&old_nd);
+	path_release(&old_nd);
 exit:
-		putname(to);
-	}
-	putname(from);
+	putname(to);
 
 	return error;
 }
@@ -1830,14 +1804,11 @@
 	struct dentry * trap;
 	struct nameidata oldnd, newnd;
 
-	if (path_init(oldname, LOOKUP_PARENT, &oldnd))
-		error = path_walk(oldname, &oldnd);
-
+	error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
 	if (error)
 		goto exit;
 
-	if (path_init(newname, LOOKUP_PARENT, &newnd))
-		error = path_walk(newname, &newnd);
+	error = path_lookup(newname, LOOKUP_PARENT, &newnd);
 	if (error)
 		goto exit1;
 
diff -urN linux-2.5.6-pre2/fs/namespace.c linux-2.5.6-pre3/fs/namespace.c
--- linux-2.5.6-pre2/fs/namespace.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/fs/namespace.c	Wed Mar  6 17:17:55 2002
@@ -360,17 +360,9 @@
 asmlinkage long sys_umount(char * name, int flags)
 {
 	struct nameidata nd;
-	char *kname;
 	int retval;
 
-	kname = getname(name);
-	retval = PTR_ERR(kname);
-	if (IS_ERR(kname))
-		goto out;
-	retval = 0;
-	if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
-		retval = path_walk(kname, &nd);
-	putname(kname);
+	retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
 	if (retval)
 		goto out;
 	retval = -EINVAL;
@@ -497,8 +489,7 @@
 		return err;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -564,8 +555,7 @@
 		return -EPERM;
 	if (!old_name || !*old_name)
 		return -EINVAL;
-	if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd))
-		err = path_walk(old_name, &old_nd);
+	err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
 	if (err)
 		return err;
 
@@ -731,8 +721,7 @@
 	flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
 
 	/* ... and get the mountpoint */
-	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		retval = path_walk(dir_name, &nd);
+	retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
 	if (retval)
 		return retval;
 
@@ -911,7 +900,6 @@
 {
 	struct vfsmount *tmp;
 	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
-	char *name;
 	int error;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -919,28 +907,14 @@
 
 	lock_kernel();
 
-	name = getname(new_root);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out0;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd))
-		error = path_walk(name, &new_nd);
-	putname(name);
+	error = __user_walk(new_root, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd);
 	if (error)
 		goto out0;
 	error = -EINVAL;
 	if (!check_mnt(new_nd.mnt))
 		goto out1;
 
-	name = getname(put_old);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out1;
-	error = 0;
-	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
-		error = path_walk(name, &old_nd);
-	putname(name);
+	error = __user_walk(put_old, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd);
 	if (error)
 		goto out1;
 
diff -urN linux-2.5.6-pre2/fs/nfsd/export.c linux-2.5.6-pre3/fs/nfsd/export.c
--- linux-2.5.6-pre2/fs/nfsd/export.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/nfsd/export.c	Wed Mar  6 17:17:55 2002
@@ -238,9 +238,7 @@
 	}
 
 	/* Look up the dentry */
-	err = 0;
-	if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd))
-		err = path_walk(nxp->ex_path, &nd);
+	err = path_lookup(nxp->ex_path, 0, &nd);
 	if (err)
 		goto out_unlock;
 
@@ -408,8 +406,7 @@
 
 	err = -EPERM;
 	/* NB: we probably ought to check that it's NUL-terminated */
-	if (path_init(path, LOOKUP_POSITIVE, &nd) &&
-	    path_walk(path, &nd)) {
+	if (path_lookup(path, 0, &nd)) {
 		printk("nfsd: exp_rootfh path not found %s", path);
 		return err;
 	}
diff -urN linux-2.5.6-pre2/fs/open.c linux-2.5.6-pre3/fs/open.c
--- linux-2.5.6-pre2/fs/open.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/fs/open.c	Wed Mar  6 17:17:55 2002
@@ -358,19 +358,10 @@
 
 asmlinkage long sys_chdir(const char * filename)
 {
-	int error;
 	struct nameidata nd;
-	char *name;
-
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
+	int error;
 
-	error = 0;
-	if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
-		error = path_walk(name, &nd);
-	putname(name);
+	error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
 	if (error)
 		goto out;
 
@@ -418,19 +409,10 @@
 
 asmlinkage long sys_chroot(const char * filename)
 {
-	int error;
 	struct nameidata nd;
-	char *name;
-
-	name = getname(filename);
-	error = PTR_ERR(name);
-	if (IS_ERR(name))
-		goto out;
+	int error;
 
-	path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
-		      LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
-	error = path_walk(name, &nd);	
-	putname(name);
+	error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
 	if (error)
 		goto out;
 
diff -urN linux-2.5.6-pre2/fs/partitions/Config.in linux-2.5.6-pre3/fs/partitions/Config.in
--- linux-2.5.6-pre2/fs/partitions/Config.in	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/fs/partitions/Config.in	Wed Mar  6 17:17:55 2002
@@ -38,7 +38,7 @@
    fi
    if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
         "$CONFIG_MAC" != "y" -a "$CONFIG_SGI_IP22" != "y" -a \
-	"$CONFIG_SGI_IP27" != "y" ]; then
+	"$CONFIG_ARM" != "y" -a "$CONFIG_SGI_IP27" != "y" ]; then
       define_bool CONFIG_MSDOS_PARTITION y
    fi
    if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_AFFS_FS" = "y" ]; then
diff -urN linux-2.5.6-pre2/fs/partitions/check.c linux-2.5.6-pre3/fs/partitions/check.c
--- linux-2.5.6-pre2/fs/partitions/check.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/fs/partitions/check.c	Wed Mar  6 17:17:55 2002
@@ -480,3 +480,28 @@
 
 	return 0;
 }
+
+/*
+ * Make sure that a proposed subpartition is strictly contained inside
+ * the parent partition.  If all is well, call add_gd_partition().
+ */
+int
+check_and_add_subpartition(struct gendisk *hd, int super_minor, int minor,
+			   int sub_start, int sub_size)
+{
+	int start = hd->part[super_minor].start_sect;
+	int size = hd->part[super_minor].nr_sects;
+
+	if (start == sub_start && size == sub_size) {
+		/* full parent partition, we have it already */
+		return 0;
+	}
+
+	if (start <= sub_start && start+size >= sub_start+sub_size) {
+		add_gd_partition(hd, minor, sub_start, sub_size);
+		return 1;
+	}
+
+	printk("bad subpartition - ignored\n");
+	return 0;
+}
diff -urN linux-2.5.6-pre2/fs/partitions/check.h linux-2.5.6-pre3/fs/partitions/check.h
--- linux-2.5.6-pre2/fs/partitions/check.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/fs/partitions/check.h	Wed Mar  6 17:17:55 2002
@@ -7,4 +7,10 @@
  */
 void add_gd_partition(struct gendisk *hd, int minor, int start, int size);
 
+/*
+ * check_and_add_subpartition does the same for subpartitions
+ */
+int check_and_add_subpartition(struct gendisk *hd, int super_minor,
+			       int minor, int sub_start, int sub_size);
+
 extern int warn_no_part;
diff -urN linux-2.5.6-pre2/fs/partitions/msdos.c linux-2.5.6-pre3/fs/partitions/msdos.c
--- linux-2.5.6-pre2/fs/partitions/msdos.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/fs/partitions/msdos.c	Wed Mar  6 17:17:55 2002
@@ -261,50 +261,6 @@
 }
 
 #ifdef CONFIG_BSD_DISKLABEL
-static void
-check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p,
-	int minor, int *current_minor)
-{
-	struct hd_struct *lin_p;
-		/* check relative position of partitions.  */
-	for (lin_p = hd->part + 1 + minor;
-	     lin_p - hd->part - minor < *current_minor; lin_p++) {
-			/* no relationship -> try again */
-		if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) ||
-		    lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size))
-			continue;	
-			/* equal -> no need to add */
-		if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && 
-			lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) 
-			return;
-			/* bsd living within dos partition */
-		if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect 
-			+ lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) {
-#ifdef DEBUG_BSD_DISKLABEL
-			printk("w: %d %ld+%ld,%d+%d", 
-				lin_p - hd->part, 
-				lin_p->start_sect, lin_p->nr_sects, 
-				le32_to_cpu(bsd_p->p_offset),
-				le32_to_cpu(bsd_p->p_size));
-#endif
-			break;
-		}
-	 /* ouch: bsd and linux overlap. Don't even try for that partition */
-#ifdef DEBUG_BSD_DISKLABEL
-		printk("???: %d %ld+%ld,%d+%d",
-			lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
-			le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size));
-#endif
-		printk("???");
-		return;
-	} /* if the bsd partition is not currently known to linux, we end
-	   * up here 
-	   */
-	add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset),
-			 le32_to_cpu(bsd_p->p_size));
-	(*current_minor)++;
-}
-
 /* 
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See extended_partition() for more information.
@@ -326,16 +282,22 @@
 		put_dev_sector(sect);
 		return;
 	}
-	printk(" %s: <%s", partition_name(hd, minor, buf), name);
+	printk(" %s: <%s:", partition_name(hd, minor, buf), name);
 
 	if (le16_to_cpu(l->d_npartitions) < max_partitions)
 		max_partitions = le16_to_cpu(l->d_npartitions);
-	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
+	for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
+		int bsd_start, bsd_size;
+
 		if ((*current_minor & mask) == 0)
 			break;
 		if (p->p_fstype == BSD_FS_UNUSED) 
 			continue;
-		check_and_add_bsd_partition(hd, p, minor, current_minor);
+		bsd_start = le32_to_cpu(p->p_offset);
+		bsd_size = le32_to_cpu(p->p_size);
+		if (check_and_add_subpartition(hd, minor, *current_minor,
+					       bsd_start, bsd_size))
+			(*current_minor)++;
 	}
 	put_dev_sector(sect);
 	printk(" >\n");
diff -urN linux-2.5.6-pre2/fs/reiserfs/fix_node.c linux-2.5.6-pre3/fs/reiserfs/fix_node.c
--- linux-2.5.6-pre2/fs/reiserfs/fix_node.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/fs/reiserfs/fix_node.c	Wed Mar  6 17:17:56 2002
@@ -2099,7 +2099,7 @@
       reiserfs_panic (p_s_sb, "tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n", descr, level, p_s_bh);
     }
 
-    if (!kdev_same(p_s_bh->b_dev, p_s_sb->s_dev) || 
+    if (p_s_bh->b_bdev != p_s_sb->s_bdev || 
 	p_s_bh->b_size != p_s_sb->s_blocksize ||
 	p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
       reiserfs_panic (p_s_sb, "tb_buffer_sanity_check(): check failed for buffer %s[%d] (%b)\n", descr, level, p_s_bh);
diff -urN linux-2.5.6-pre2/fs/reiserfs/inode.c linux-2.5.6-pre3/fs/reiserfs/inode.c
--- linux-2.5.6-pre2/fs/reiserfs/inode.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/reiserfs/inode.c	Wed Mar  6 17:17:56 2002
@@ -1702,7 +1702,7 @@
 	** call prepare_write
 	*/
 	reiserfs_warning("clm-6000: error reading block %lu on dev %s\n",
-	                  bh->b_blocknr, kdevname(bh->b_dev)) ;
+	                  bh->b_blocknr, p_s_inode->i_sb->s_id) ;
 	error = -EIO ;
 	goto unlock ;
     }
diff -urN linux-2.5.6-pre2/fs/reiserfs/journal.c linux-2.5.6-pre3/fs/reiserfs/journal.c
--- linux-2.5.6-pre2/fs/reiserfs/journal.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/fs/reiserfs/journal.c	Wed Mar  6 17:17:56 2002
@@ -98,6 +98,21 @@
 static int release_journal_dev( struct super_block *super,
 				struct reiserfs_journal *journal );
 
+static inline struct buffer_head *journ_get_hash_table(struct super_block *s, int block)
+{
+	return __get_hash_table(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize);
+}
+ 
+static inline struct buffer_head *journ_getblk(struct super_block *s, int block)
+{
+	return __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize);
+}
+
+static inline struct buffer_head *journ_bread(struct super_block *s, int block)
+{
+	return __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize);
+}
+
 static void init_journal_hash(struct super_block *p_s_sb) {
   memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
 }
@@ -690,7 +705,7 @@
   count = 0 ;
   for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
     bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start+i) %  SB_ONDISK_JOURNAL_SIZE(s);
-    tbh = get_hash_table(SB_JOURNAL_DEV(s), bn, s->s_blocksize) ;
+    tbh = journ_get_hash_table(s, bn) ;
 
 /* kill this sanity check */
 if (count > (orig_commit_left + 2)) {
@@ -719,7 +734,7 @@
     for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && 
                  i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */
       bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
-      tbh = get_hash_table(SB_JOURNAL_DEV(s), bn, s->s_blocksize) ;
+      tbh = journ_get_hash_table(s, bn) ;
 
       wait_on_buffer(tbh) ;
       if (!buffer_uptodate(tbh)) {
@@ -1410,9 +1425,8 @@
     offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
 
     /* ok, we have a journal description block, lets see if the transaction was valid */
-    c_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
-		 ((offset + le32_to_cpu(desc->j_len) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
-		 p_s_sb->s_blocksize) ;
+    c_bh = journ_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+		 ((offset + le32_to_cpu(desc->j_len) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
     if (!c_bh)
       return 0 ;
     commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
@@ -1466,7 +1480,7 @@
   unsigned long trans_offset ;
   int i;
 
-  d_bh = bread(SB_JOURNAL_DEV(p_s_sb), cur_dblock, p_s_sb->s_blocksize) ;
+  d_bh = journ_bread(p_s_sb, cur_dblock) ;
   if (!d_bh)
     return 1 ;
   desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
@@ -1490,9 +1504,9 @@
     brelse(d_bh) ;
     return 1 ;
   }
-  c_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+  c_bh = journ_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
 		((trans_offset + le32_to_cpu(desc->j_len) + 1) % 
-		 SB_ONDISK_JOURNAL_SIZE(p_s_sb)), p_s_sb->s_blocksize) ;
+		 SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
   if (!c_bh) {
     brelse(d_bh) ;
     return 1 ;
@@ -1521,7 +1535,7 @@
   }
   /* get all the buffer heads */
   for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) {
-    log_blocks[i] =  getblk(SB_JOURNAL_DEV(p_s_sb),  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb), p_s_sb->s_blocksize);
+    log_blocks[i] =  journ_getblk(p_s_sb,  SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
     if (i < JOURNAL_TRANS_HALF) {
       real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ;
     } else {
@@ -1600,7 +1614,7 @@
 **
 ** On exit, it sets things up so the first transaction will work correctly.
 */
-struct buffer_head * reiserfs_breada (kdev_t dev, int block, int bufsize,
+struct buffer_head * reiserfs_breada (struct super_block *sb, int block, 
 			    unsigned int max_block)
 {
 	struct buffer_head * bhlist[BUFNR];
@@ -1608,7 +1622,7 @@
 	struct buffer_head * bh;
 	int i, j;
 	
-	bh = getblk (dev, block, bufsize);
+	bh = sb_getblk (sb, block);
 	if (buffer_uptodate (bh))
 		return (bh);   
 		
@@ -1618,7 +1632,7 @@
 	bhlist[0] = bh;
 	j = 1;
 	for (i = 1; i < blocks; i++) {
-		bh = getblk (dev, block + i, bufsize);
+		bh = sb_getblk (sb, block + i);
 		if (buffer_uptodate (bh)) {
 			brelse (bh);
 			break;
@@ -1661,10 +1675,9 @@
   ** is the first unflushed, and if that transaction is not valid, 
   ** replay is done
   */
-  SB_JOURNAL(p_s_sb)->j_header_bh = bread (SB_JOURNAL_DEV(p_s_sb),
+  SB_JOURNAL(p_s_sb)->j_header_bh = journ_bread(p_s_sb,
 					   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
-					   SB_ONDISK_JOURNAL_SIZE(p_s_sb),
-					   p_s_sb->s_blocksize) ;
+					   SB_ONDISK_JOURNAL_SIZE(p_s_sb));
   if (!SB_JOURNAL(p_s_sb)->j_header_bh) {
     return 1 ;
   }
@@ -1685,7 +1698,7 @@
     ** there is nothing more we can do, and it makes no sense to read 
     ** through the whole log.
     */
-    d_bh = bread(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset), p_s_sb->s_blocksize) ;
+    d_bh = journ_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset)) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL) ;
     if (!ret) {
       continue_replay = 0 ;
@@ -1705,7 +1718,7 @@
   ** all the valid transactions, and pick out the oldest.
   */
   while(continue_replay && cur_dblock < (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb))) {
-    d_bh = reiserfs_breada(p_s_sb->s_dev, cur_dblock, p_s_sb->s_blocksize,
+    d_bh = reiserfs_breada(p_s_sb, cur_dblock,
 			   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ;
     ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ;
     if (ret == 1) {
@@ -1973,9 +1986,6 @@
 		if( !S_ISBLK( jdev_inode -> i_mode ) ) {
 			printk( "journal_init_dev: '%s' is not a block device", jdev_name );
 			result = -ENOTBLK;
-		} else if( journal -> j_dev_file -> f_vfsmnt -> mnt_flags & MNT_NODEV) {
-			printk( "journal_init_dev: Cannot use devices on '%s'", jdev_name );
-			result = -EACCES;
 		} else if( jdev_inode -> i_bdev == NULL ) {
 			printk( "journal_init_dev: bdev unintialized for '%s'", jdev_name );
 			result = -ENOMEM;
@@ -2039,9 +2049,8 @@
      rs = SB_DISK_SUPER_BLOCK(p_s_sb);
      
      /* read journal header */
-     bhjh = bread (SB_JOURNAL_DEV(p_s_sb),
-		   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb),
-		   SB_BLOCKSIZE(p_s_sb));
+     bhjh = journ_bread(p_s_sb,
+		   SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb));
      if (!bhjh) {
 	 printk("sh-459: unable to read  journal header\n") ;
 	 return 1 ;
@@ -2054,7 +2063,7 @@
 	 char fname[ 32 ];
 	 
 	 strcpy( jname, kdevname( SB_JOURNAL_DEV(p_s_sb) ) );
-	 strcpy( fname, kdevname( p_s_sb->s_dev ) );
+	 strcpy( fname, p_s_sb->s_id);
 	 printk("sh-460: journal header magic %x (device %s) does not match "
 		"to magic found in super block %x (device %s)\n",
 		jh->jh_journal.jp_journal_magic, jname,
@@ -2979,7 +2988,7 @@
   
   rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
   /* setup description block */
-  d_bh = getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start, p_s_sb->s_blocksize) ; 
+  d_bh = journ_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; 
   mark_buffer_uptodate(d_bh, 1) ;
   desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
   memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ;
@@ -2987,9 +2996,8 @@
   desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
 
   /* setup commit block.  Don't write (keep it clean too) this one until after everyone else is written */
-  c_bh =  getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
-		 ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
-		 p_s_sb->s_blocksize) ;
+  c_bh =  journ_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
+		 ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
   commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
   memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ;
   commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
@@ -3079,9 +3087,8 @@
     /* copy all the real blocks into log area.  dirty log blocks */
     if (test_bit(BH_JDirty, &cn->bh->b_state)) {
       struct buffer_head *tmp_bh ;
-      tmp_bh =  getblk(SB_JOURNAL_DEV(p_s_sb), SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
-		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)), 
-		       p_s_sb->s_blocksize) ;
+      tmp_bh =  journ_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
+		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
       mark_buffer_uptodate(tmp_bh, 1) ;
       memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
       jindex++ ;
diff -urN linux-2.5.6-pre2/fs/reiserfs/super.c linux-2.5.6-pre3/fs/reiserfs/super.c
--- linux-2.5.6-pre2/fs/reiserfs/super.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/reiserfs/super.c	Wed Mar  6 17:17:56 2002
@@ -581,11 +581,6 @@
 }
 
 
-int reiserfs_is_super(struct super_block *s) {
-   return (!kdev_same(s->s_dev, NODEV) && s->s_op == &reiserfs_sops) ;
-}
-
-
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -1201,6 +1196,11 @@
 	fs_flags:	FS_REQUIRES_DEV,
 };
 
+int reiserfs_is_super(struct super_block *s)
+{
+	return s->s_type == &reiserfs_fs_type;
+}
+
 //
 // this is exactly what 2.3.99-pre9's init_ext2_fs is
 //
diff -urN linux-2.5.6-pre2/fs/super.c linux-2.5.6-pre3/fs/super.c
--- linux-2.5.6-pre2/fs/super.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/fs/super.c	Wed Mar  6 17:17:56 2002
@@ -444,9 +444,10 @@
 	if (fs->fs_flags & FS_LITTER && sb->s_root)
 		d_genocide(sb->s_root);
 	generic_shutdown_super(sb);
-	if (bdev)
+	if (bdev) {
+		bd_release(bdev);
 		blkdev_put(bdev, BDEV_FS);
-	else
+	} else
 		put_anon_dev(dev);
 }
 
@@ -700,8 +701,7 @@
 	/* What device it is? */
 	if (!dev_name || !*dev_name)
 		return ERR_PTR(-EINVAL);
-	if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
-		error = path_walk(dev_name, &nd);
+	error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
 	if (error)
 		return ERR_PTR(error);
 	inode = nd.dentry->d_inode;
@@ -728,37 +728,40 @@
 	error = -EACCES;
 	if (!(flags & MS_RDONLY) && is_read_only(dev))
 		goto out1;
+	error = bd_claim(bdev, fs_type);
+	if (error)
+		goto out1;
 
 	error = -ENOMEM;
 	s = alloc_super();
 	if (!s)
-		goto out1;
+		goto out2;
 
 	error = -EBUSY;
 restart:
 	spin_lock(&sb_lock);
 
-	list_for_each(p, &super_blocks) {
+	list_for_each(p, &fs_type->fs_supers) {
 		struct super_block *old = sb_entry(p);
 		if (old->s_bdev != bdev)
 			continue;
-		if (old->s_type != fs_type ||
-		    ((flags ^ old->s_flags) & MS_RDONLY)) {
-			spin_unlock(&sb_lock);
-			destroy_super(s);
-			goto out1;
-		}
 		if (!grab_super(old))
 			goto restart;
 		destroy_super(s);
+		if ((flags ^ old->s_flags) & MS_RDONLY) {
+			up_write(&old->s_umount);
+			kill_super(old);
+			old = ERR_PTR(-EBUSY);
+		}
+		bd_release(bdev);
 		blkdev_put(bdev, BDEV_FS);
 		path_release(&nd);
 		return old;
 	}
-	s->s_dev = dev;
 	s->s_bdev = bdev;
-	s->s_flags = flags;
+	s->s_dev = dev;
 	insert_super(s, fs_type);
+	s->s_flags = flags;
 	strncpy(s->s_id, bdevname(dev), sizeof(s->s_id));
 	error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
 	if (error)
@@ -771,6 +774,8 @@
 	up_write(&s->s_umount);
 	kill_super(s);
 	goto out;
+out2:
+	bd_release(bdev);
 out1:
 	blkdev_put(bdev, BDEV_FS);
 out:
diff -urN linux-2.5.6-pre2/include/asm-arm/arch-sa1100/graphicsclient.h linux-2.5.6-pre3/include/asm-arm/arch-sa1100/graphicsclient.h
--- linux-2.5.6-pre2/include/asm-arm/arch-sa1100/graphicsclient.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/include/asm-arm/arch-sa1100/graphicsclient.h	Wed Mar  6 17:17:56 2002
@@ -76,15 +76,6 @@
 #define IRQ_GC_UART1_CTS       IRQ_GPIO16
 #define IRQ_GC_UART2_CTS       IRQ_GPIO17
 
-#ifndef __ASSEMBLY__
-struct gc_uart_ctrl_data_t {
-  int cts_gpio;
-  int cts_prev_state;
-  struct uart_info *info;
-  struct uart_port *port;
-};
-#endif /* __ASSEMBLY__ */
-
 /* LEDs */
 
 #define ADS_LED0	GPIO_GPIO20		/* on-board D22 */
diff -urN linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irqs.h linux-2.5.6-pre3/include/asm-arm/arch-sa1100/irqs.h
--- linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irqs.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/asm-arm/arch-sa1100/irqs.h	Wed Mar  6 17:17:56 2002
@@ -151,4 +151,5 @@
 #define IRQ_NEPONSET_SA1111	(IRQ_BOARD_START + 2)
 
 /* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */
-#define IRQ_SYSTEM3_SMC9196	(IRQ_BOARD_START + 0)
+#define IRQ_SYSTEM3_SA1111	(IRQ_BOARD_START + 0)
+#define IRQ_SYSTEM3_SMC9196	(IRQ_BOARD_START + 1)
diff -urN linux-2.5.6-pre2/include/asm-arm/arch-sa1100/system3.h linux-2.5.6-pre3/include/asm-arm/arch-sa1100/system3.h
--- linux-2.5.6-pre2/include/asm-arm/arch-sa1100/system3.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/include/asm-arm/arch-sa1100/system3.h	Wed Mar  6 17:17:56 2002
@@ -67,17 +67,17 @@
 /* System ID register */
 
 /* IRQ Source Register */
-#define PT_IRQ_LAN		( 1<<0 )
-#define PT_IRQ_X		( 1<<1 )
-#define PT_IRQ_SA1111	( 1<<2 )
-#define PT_IRQ_RS1		( 1<<3 )
-#define PT_IRQ_RS1_RING	( 1<<4 )
-#define PT_IRQ_RS1_DCD	( 1<<5 )
-#define PT_IRQ_RS1_DSR	( 1<<6 )
-#define PT_IRQ_RS2		( 1<<7 )
+#define PT_IRR_LAN		( 1<<0 )
+#define PT_IRR_X		( 1<<1 )
+#define PT_IRR_SA1111	( 1<<2 )
+#define PT_IRR_RS1		( 1<<3 )
+#define PT_IRR_RS1_RING	( 1<<4 )
+#define PT_IRR_RS1_DCD	( 1<<5 )
+#define PT_IRR_RS1_DSR	( 1<<6 )
+#define PT_IRR_RS2		( 1<<7 )
 
 /* FIXME */
-#define PT_IRQ_USAR		( 1<<1 )
+#define PT_IRR_USAR		( 1<<1 )
 
 /* CTRL 0 */
 #define PT_CTRL0_USBSLAVE	( 1<<0 )
diff -urN linux-2.5.6-pre2/include/asm-arm/pgalloc.h linux-2.5.6-pre3/include/asm-arm/pgalloc.h
--- linux-2.5.6-pre2/include/asm-arm/pgalloc.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/asm-arm/pgalloc.h	Wed Mar  6 17:17:56 2002
@@ -14,136 +14,20 @@
 
 #include <asm/processor.h>
 
-/*
- * Get the cache handling stuff now.
- */
 #include <asm/proc/cache.h>
-
-/*
- * ARM processors do not cache TLB tables in RAM.
- */
-#define flush_tlb_pgtables(mm,start,end)	do { } while (0)
-
-/*
- * Processor specific parts...
- */
 #include <asm/proc/pgalloc.h>
 
 /*
- * Page table cache stuff
- */
-#ifndef CONFIG_NO_PGT_CACHE
-
-#ifdef CONFIG_SMP
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif	/* CONFIG_SMP */
-
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
-
-#define pgd_quicklist		(quicklists.pgd_cache)
-#define pmd_quicklist		((unsigned long *)0)
-#define pte_quicklist		(quicklists.pte_cache)
-#define pgtable_cache_size	(quicklists.pgtable_cache_sz)
-
-/* used for quicklists */
-#define __pgd_next(pgd) (((unsigned long *)pgd)[1])
-#define __pte_next(pte)	(((unsigned long *)pte)[0])
-
-static inline pgd_t *get_pgd_fast(void)
-{
-	unsigned long *ret;
-
-	preempt_disable();
-	if ((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)__pgd_next(ret);
-		ret[1] = ret[2];
-		clean_dcache_entry(ret + 1);
-		pgtable_cache_size--;
-	}
-	preempt_enable();
-	return (pgd_t *)ret;
-}
-
-static inline void free_pgd_fast(pgd_t *pgd)
-{
-	preempt_disable();
-	__pgd_next(pgd) = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-	preempt_enable();
-}
-
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
-{
-	unsigned long *ret;
-
-	preempt_disable();
-	if((ret = pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)__pte_next(ret);
-		ret[0] = 0;
-		clean_dcache_entry(ret);
-		pgtable_cache_size--;
-	}
-	preempt_enable();
-	return (pte_t *)ret;
-}
-
-static inline void free_pte_fast(pte_t *pte)
-{
-	preempt_disable();
-	__pte_next(pte) = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
-	preempt_enable();
-}
-
-#else	/* CONFIG_NO_PGT_CACHE */
-
-#define pgd_quicklist			((unsigned long *)0)
-#define pmd_quicklist			((unsigned long *)0)
-#define pte_quicklist			((unsigned long *)0)
-
-#define get_pgd_fast()			((pgd_t *)0)
-#define pte_alloc_one_fast(mm,addr)	((pte_t *)0)
-
-#define free_pgd_fast(pgd)		free_pgd_slow(pgd)
-#define free_pte_fast(pte)		pte_free_slow(pte)
-
-#endif	/* CONFIG_NO_PGT_CACHE */
-
-#define pte_free(pte)			free_pte_fast(pte)
-
-
-/*
  * Since we have only two-level page tables, these are trivial
  */
-#define pmd_alloc_one_fast(mm,addr)	({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm,addr)		({ BUG(); ((pmd_t *)2); })
-#define pmd_free_slow(pmd)		do { } while (0)
-#define pmd_free_fast(pmd)		do { } while (0)
 #define pmd_free(pmd)			do { } while (0)
 #define pgd_populate(mm,pmd,pte)	BUG()
 
 extern pgd_t *get_pgd_slow(struct mm_struct *mm);
 extern void free_pgd_slow(pgd_t *pgd);
 
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-	pgd_t *pgd;
-
-	pgd = get_pgd_fast();
-	if (!pgd)
-		pgd = get_pgd_slow(mm);
-
-	return pgd;
-}
-
-#define pgd_free(pgd)			free_pgd_fast(pgd)
-
-extern int do_check_pgt_cache(int, int);
+#define pgd_alloc(mm)			get_pgd_slow(mm)
+#define pgd_free(pgd)			free_pgd_slow(pgd)
 
 #endif
diff -urN linux-2.5.6-pre2/include/asm-arm/pgtable.h linux-2.5.6-pre3/include/asm-arm/pgtable.h
--- linux-2.5.6-pre2/include/asm-arm/pgtable.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/include/asm-arm/pgtable.h	Wed Mar  6 17:17:56 2002
@@ -13,7 +13,6 @@
 #include <linux/config.h>
 #include <asm/arch/memory.h>
 #include <asm/arch/vmalloc.h>
-#include <asm/proc-fns.h>
 
 /*
  * PMD_SHIFT determines the size of the area a second-level page table can map
@@ -146,8 +145,16 @@
 #define pmd_offset(dir, addr)	((pmd_t *)(dir))
 
 /* Find an entry in the third-level page table.. */
-#define __pte_offset(addr)	(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#define pte_offset(dir, addr)	((pte_t *)pmd_page(*(dir)) + __pte_offset(addr))
+#define __pte_index(addr)	(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+#define pmd_page(dir)		((struct page *)__pmd_page(dir))
+
+#define __pte_offset(dir, addr)	((pte_t *)__pmd_page(*(dir)) + __pte_index(addr))
+#define pte_offset_kernel	__pte_offset
+#define pte_offset_map		__pte_offset
+#define pte_offset_map_nested	__pte_offset
+#define pte_unmap(pte)		do { } while (0)
+#define pte_unmap_nested(pte)	do { } while (0)
 
 #include <asm/proc/pgtable.h>
 
diff -urN linux-2.5.6-pre2/include/asm-arm/proc-armv/pgalloc.h linux-2.5.6-pre3/include/asm-arm/proc-armv/pgalloc.h
--- linux-2.5.6-pre2/include/asm-arm/proc-armv/pgalloc.h	Tue Feb 19 18:10:52 2002
+++ linux-2.5.6-pre3/include/asm-arm/proc-armv/pgalloc.h	Wed Mar  6 17:17:56 2002
@@ -18,7 +18,8 @@
  * from the Linux copy.  The processor copies are offset by -PTRS_PER_PTE
  * words from the Linux copy.
  */
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
 {
 	pte_t *pte;
 
@@ -28,10 +29,21 @@
 	return pte;
 }
 
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	pte_t *pte;
+
+	pte = kmem_cache_alloc(pte_cache, GFP_KERNEL);
+	if (pte)
+		pte += PTRS_PER_PTE;
+	return (struct page *)pte;
+}
+
 /*
  * Free one PTE table.
  */
-static inline void pte_free_slow(pte_t *pte)
+static inline void pte_free_kernel(pte_t *pte)
 {
 	if (pte) {
 		pte -= PTRS_PER_PTE;
@@ -39,6 +51,15 @@
 	}
 }
 
+static inline void pte_free(struct page *pte)
+{
+	pte_t *_pte = (pte_t *)pte;
+	if (pte) {
+		_pte -= PTRS_PER_PTE;
+		kmem_cache_free(pte_cache, _pte);
+	}
+}
+
 /*
  * Populate the pmdp entry with a pointer to the pte.  This pmd is part
  * of the mm address space.
@@ -46,12 +67,14 @@
  * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we
  * need to set stuff up correctly for it.
  */
+#define pmd_populate_kernel(mm,pmdp,pte)			\
+	do {							\
+		BUG_ON(mm != &init_mm);				\
+		set_pmd(pmdp, __mk_pmd(pte, _PAGE_KERNEL_TABLE));\
+	} while (0)
+
 #define pmd_populate(mm,pmdp,pte)				\
 	do {							\
-		unsigned long __prot;				\
-		if (mm == &init_mm)				\
-			__prot = _PAGE_KERNEL_TABLE;		\
-		else						\
-			__prot = _PAGE_USER_TABLE;		\
-		set_pmd(pmdp, __mk_pmd(pte, __prot));		\
+		BUG_ON(mm == &init_mm);				\
+		set_pmd(pmdp, __mk_pmd(pte, _PAGE_USER_TABLE));	\
 	} while (0)
diff -urN linux-2.5.6-pre2/include/asm-arm/proc-armv/pgtable.h linux-2.5.6-pre3/include/asm-arm/proc-armv/pgtable.h
--- linux-2.5.6-pre2/include/asm-arm/proc-armv/pgtable.h	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/include/asm-arm/proc-armv/pgtable.h	Wed Mar  6 17:17:56 2002
@@ -125,7 +125,7 @@
 	return pmd;
 }
 
-static inline unsigned long pmd_page(pmd_t pmd)
+static inline unsigned long __pmd_page(pmd_t pmd)
 {
 	unsigned long ptr;
 
diff -urN linux-2.5.6-pre2/include/asm-cris/ide.h linux-2.5.6-pre3/include/asm-cris/ide.h
--- linux-2.5.6-pre2/include/asm-cris/ide.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/include/asm-cris/ide.h	Wed Mar  6 17:17:56 2002
@@ -146,8 +146,7 @@
 unsigned char IN_BYTE(ide_ioreg_t reg);
 
 /* this tells ide.h not to define the standard macros */
-#define HAVE_ARCH_OUT_BYTE
-#define HAVE_ARCH_IN_BYTE
+#define HAVE_ARCH_IN_OUT	1
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.5.6-pre2/include/asm-i386/unistd.h linux-2.5.6-pre3/include/asm-i386/unistd.h
--- linux-2.5.6-pre2/include/asm-i386/unistd.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/include/asm-i386/unistd.h	Wed Mar  6 17:17:56 2002
@@ -243,6 +243,7 @@
 #define __NR_lremovexattr	236
 #define __NR_fremovexattr	237
 #define __NR_tkill		238
+#define __NR_sendfile64		239
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -urN linux-2.5.6-pre2/include/asm-ia64/sn/pci/pcibr.h linux-2.5.6-pre3/include/asm-ia64/sn/pci/pcibr.h
--- linux-2.5.6-pre2/include/asm-ia64/sn/pci/pcibr.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/include/asm-ia64/sn/pci/pcibr.h	Wed Mar  6 17:17:56 2002
@@ -47,7 +47,7 @@
  *	These functions are normal device driver entry points
  *	and are called along with the similar entry points from
  *	other device drivers. They are included here as documentation
- *	of their existance and purpose.
+ *	of their existence and purpose.
  *
  *	pcibr_init() is called to inform us that there is a pcibr driver
  *	configured into the kernel; it is responsible for registering
diff -urN linux-2.5.6-pre2/include/asm-ppc/highmem.h linux-2.5.6-pre3/include/asm-ppc/highmem.h
--- linux-2.5.6-pre2/include/asm-ppc/highmem.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/include/asm-ppc/highmem.h	Wed Mar  6 17:17:56 2002
@@ -106,7 +106,7 @@
 static inline void kunmap_atomic(void *kvaddr, enum km_type type)
 {
 #if HIGHMEM_DEBUG
-	unsigned long vaddr = (unsigned long) kvaddr;
+	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
 	unsigned int idx = type + KM_TYPE_NR*smp_processor_id();
 
 	if (vaddr < KMAP_FIX_BEGIN) // FIXME
diff -urN linux-2.5.6-pre2/include/asm-ppc/kmap_types.h linux-2.5.6-pre3/include/asm-ppc/kmap_types.h
--- linux-2.5.6-pre2/include/asm-ppc/kmap_types.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/include/asm-ppc/kmap_types.h	Wed Mar  6 17:17:56 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.kmap_types.h 1.9 08/29/01 14:03:05 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _ASM_KMAP_TYPES_H
@@ -12,6 +12,8 @@
 	KM_USER0,
 	KM_USER1,
 	KM_BIO_IRQ,
+	KM_PTE0,
+	KM_PTE1,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.5.6-pre2/include/asm-ppc/pgalloc.h linux-2.5.6-pre3/include/asm-ppc/pgalloc.h
--- linux-2.5.6-pre2/include/asm-ppc/pgalloc.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/include/asm-ppc/pgalloc.h	Wed Mar  6 17:17:56 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pgalloc.h 1.9 05/17/01 18:14:25 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _PPC_PGALLOC_H
@@ -7,55 +7,12 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <linux/highmem.h>
 #include <asm/processor.h>
 
-/*
- * This is handled very differently on the PPC since out page tables
- * are all 0's and I want to be able to use these zero'd pages elsewhere
- * as well - it gives us quite a speedup.
- *
- * Note that the SMP/UP versions are the same but we don't need a
- * per cpu list of zero pages because we do the zero-ing with the cache
- * off and the access routines are lock-free but the pgt cache stuff
- * is per-cpu since it isn't done with any lock-free access routines
- * (although I think we need arch-specific routines so I can do lock-free).
- *
- * I need to generalize this so we can use it for other arch's as well.
- * -- Cort
- */
-#ifdef CONFIG_SMP
-#define quicklists	cpu_data[smp_processor_id()]
-#else
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
-#endif
-
-#define pgd_quicklist 		(quicklists.pgd_cache)
-#define pmd_quicklist 		((unsigned long *)0)
-#define pte_quicklist 		(quicklists.pte_cache)
-#define pgtable_cache_size 	(quicklists.pgtable_cache_sz)
-
-extern unsigned long *zero_cache;    /* head linked list of pre-zero'd pages */
-extern atomic_t zero_sz;	     /* # currently pre-zero'd pages */
-extern atomic_t zeropage_hits;	     /* # zero'd pages request that we've done */
-extern atomic_t zeropage_calls;      /* # zero'd pages request that've been made */
-extern atomic_t zerototal;	     /* # pages zero'd over time */
-
-#define zero_quicklist     	(zero_cache)
-#define zero_cache_sz  	 	(zero_sz)
-#define zero_cache_calls 	(zeropage_calls)
-#define zero_cache_hits  	(zeropage_hits)
-#define zero_cache_total 	(zerototal)
-
-/* return a pre-zero'd page from the list, return NULL if none available -- Cort */
-extern unsigned long get_zero_page_fast(void);
-
 extern void __bad_pte(pmd_t *pmd);
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *ret;
 
@@ -64,85 +21,75 @@
 	return ret;
 }
 
-extern __inline__ pgd_t *get_pgd_fast(void)
-{
-        unsigned long *ret;
-
-        if ((ret = pgd_quicklist) != NULL) {
-                pgd_quicklist = (unsigned long *)(*ret);
-                ret[0] = 0;
-                pgtable_cache_size--;
-        } else
-                ret = (unsigned long *)get_pgd_slow();
-        return (pgd_t *)ret;
-}
-
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-        *(unsigned long **)pgd = pgd_quicklist;
-        pgd_quicklist = (unsigned long *) pgd;
-        pgtable_cache_size++;
-}
-
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+extern __inline__ void pgd_free(pgd_t *pgd)
 {
 	free_page((unsigned long)pgd);
 }
 
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc(mm)		get_pgd_fast()
-
 /*
  * We don't have any real pmd's, and this code never triggers because
  * the pgd will always be present..
  */
-#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 #define pmd_free(x)                     do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
 	pte_t *pte;
 	extern int mem_init_done;
 	extern void *early_get_page(void);
+	int timeout = 0;
 
-	if (mem_init_done)
-		pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	else
+	if (mem_init_done) {
+		while ((pte = (pte_t *) __get_free_page(GFP_KERNEL)) == NULL
+		       && ++timeout < 10) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ);
+		}
+	} else
 		pte = (pte_t *) early_get_page();
 	if (pte != NULL)
 		clear_page(pte);
 	return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-        unsigned long *ret;
+	struct page *pte;
+	int timeout = 0;
+#ifdef CONFIG_HIGHPTE
+	int flags = GFP_KERNEL | __GFP_HIGHMEM;
+#else
+	int flags = GFP_KERNEL;
+#endif
 
-        if ((ret = pte_quicklist) != NULL) {
-                pte_quicklist = (unsigned long *)(*ret);
-                ret[0] = 0;
-                pgtable_cache_size--;
+	while ((pte = alloc_pages(flags, 0)) == NULL) {
+		if (++timeout >= 10)
+			return NULL;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);
 	}
-        return (pte_t *)ret;
+	clear_highpage(pte);
+	return pte;
 }
 
-extern __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_kernel(pte_t *pte)
 {
-        *(unsigned long **)pte = pte_quicklist;
-        pte_quicklist = (unsigned long *) pte;
-        pgtable_cache_size++;
+	free_page((unsigned long)pte);
 }
 
-extern __inline__ void pte_free_slow(pte_t *pte)
+static inline void pte_free(struct page *pte)
 {
-	free_page((unsigned long)pte);
+	__free_page(pte);
 }
 
-#define pte_free(pte)    pte_free_slow(pte)
-
-#define pmd_populate(mm, pmd, pte)	(pmd_val(*(pmd)) = (unsigned long) (pte))
+#define pmd_populate_kernel(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = __pa(pte))
+#define pmd_populate(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = ((pte) - mem_map) << PAGE_SHIFT)
 
 extern int do_check_pgt_cache(int, int);
 
diff -urN linux-2.5.6-pre2/include/asm-ppc/pgtable.h linux-2.5.6-pre3/include/asm-ppc/pgtable.h
--- linux-2.5.6-pre2/include/asm-ppc/pgtable.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/include/asm-ppc/pgtable.h	Wed Mar  6 17:17:56 2002
@@ -13,6 +13,7 @@
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
+#include <asm/kmap_types.h>
 
 extern void _tlbie(unsigned long address);
 extern void _tlbia(void);
@@ -98,6 +99,7 @@
 		struct page *page, unsigned long addr, int len);
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void __flush_dcache_icache(void *page_va);
+extern void __flush_dcache_icache_phys(unsigned long physaddr);
 extern void flush_dcache_page(struct page *page);
 extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
 
@@ -274,7 +276,6 @@
 #define _PAGE_HWWRITE	0x0100	/* h/w write enable: never set in Linux PTE */
 #define _PAGE_USER	0x0800	/* One of the PP bits, the other is USER&~RW */
 
-#define _PMD_PRESENT	0x0001
 #define _PMD_PAGE_MASK	0x000c
 #define _PMD_PAGE_8M	0x000c
 
@@ -385,8 +386,8 @@
 #define pte_clear(ptep)		do { set_pte((ptep), __pte(0)); } while (0)
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
-#define	pmd_bad(pmd)		((pmd_val(pmd) & ~PAGE_MASK) != 0)
-#define	pmd_present(pmd)	((pmd_val(pmd) & PAGE_MASK) != 0)
+#define	pmd_bad(pmd)		(0)
+#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))
@@ -530,7 +531,10 @@
 
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
 
-#define pmd_page(pmd)	(pmd_val(pmd) & PAGE_MASK)
+#define pmd_page_kernel(pmd)	\
+	((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd)		\
+	(mem_map + (pmd_val(pmd) >> PAGE_SHIFT))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
@@ -545,11 +549,18 @@
 	return (pmd_t *) dir;
 }
 
-/* Find an entry in the third-level page table.. */ 
-static inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(address)		\
+	((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, addr)	\
+	((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(addr))
+#define pte_offset_map(dir, addr)		\
+	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + __pte_offset(addr))
+#define pte_offset_map_nested(dir, addr)	\
+	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + __pte_offset(addr))
+
+#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
 
 extern pgd_t swapper_pg_dir[1024];
 extern void paging_init(void);
@@ -558,10 +569,12 @@
  * When flushing the tlb entry for a page, we also need to flush the hash
  * table entry.  flush_hash_page is assembler (for speed) in hashtable.S.
  */
-extern int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+extern int flush_hash_pages(unsigned context, unsigned long va,
+			    unsigned long pmdval, int count);
 
 /* Add an HPTE to the hash table */
-extern void add_hash_page(unsigned context, unsigned long va, pte_t *ptep);
+extern void add_hash_page(unsigned context, unsigned long va,
+			  unsigned long pmdval);
 
 /*
  * Encode and decode a swap entry.
diff -urN linux-2.5.6-pre2/include/linux/blk.h linux-2.5.6-pre3/include/linux/blk.h
--- linux-2.5.6-pre2/include/linux/blk.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/linux/blk.h	Wed Mar  6 17:17:56 2002
@@ -11,18 +11,24 @@
 extern void set_device_ro(kdev_t dev,int flag);
 extern void add_blkdev_randomness(int major);
 
+#ifdef CONFIG_BLK_DEV_RAM
+
+extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;          /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;     /* starting block # of image */
+
 #ifdef CONFIG_BLK_DEV_INITRD
 
 #define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
 
 extern unsigned long initrd_start,initrd_end;
 extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
 void initrd_init(void);
 
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 #endif
+
 /*
  * end_request() and friends. Must be called with the request queue spinlock
  * acquired. All functions called within end_request() _must_be_ atomic.
diff -urN linux-2.5.6-pre2/include/linux/blkpg.h linux-2.5.6-pre3/include/linux/blkpg.h
--- linux-2.5.6-pre2/include/linux/blkpg.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/include/linux/blkpg.h	Wed Mar  6 17:17:56 2002
@@ -57,7 +57,7 @@
 #ifdef __KERNEL__
 
 extern char * partition_name(kdev_t dev);
-extern int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg);
+extern int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg);
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.5.6-pre2/include/linux/cache.h linux-2.5.6-pre3/include/linux/cache.h
--- linux-2.5.6-pre2/include/linux/cache.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/include/linux/cache.h	Wed Mar  6 17:17:56 2002
@@ -4,8 +4,10 @@
 #include <linux/config.h>
 #include <asm/cache.h>
 
+#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
+
 #ifndef L1_CACHE_ALIGN
-#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+#define L1_CACHE_ALIGN(x) ALIGN(x, L1_CACHE_BYTES)
 #endif
 
 #ifndef SMP_CACHE_BYTES
diff -urN linux-2.5.6-pre2/include/linux/coda_fs_i.h linux-2.5.6-pre3/include/linux/coda_fs_i.h
--- linux-2.5.6-pre2/include/linux/coda_fs_i.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/include/linux/coda_fs_i.h	Wed Mar  6 17:17:56 2002
@@ -34,6 +34,7 @@
 #define C_PURGE       0x8
 
 int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
+struct inode *coda_iget(struct super_block *sb, struct ViceFid *fid, struct coda_vattr *attr);
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
 struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
 void coda_replace_fid(struct inode *, ViceFid *, ViceFid *);
diff -urN linux-2.5.6-pre2/include/linux/coda_linux.h linux-2.5.6-pre3/include/linux/coda_linux.h
--- linux-2.5.6-pre2/include/linux/coda_linux.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre3/include/linux/coda_linux.h	Wed Mar  6 17:17:56 2002
@@ -44,8 +44,6 @@
 int coda_isnullfid(ViceFid *fid);
 
 /* global variables */
-extern int coda_debug;
-extern int coda_print_entry;
 extern int coda_access_cache;
 extern int coda_fake_statfs;
 
@@ -70,44 +68,19 @@
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
 
-
-/* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */ 
-#define D_INODE     2   /* print entry and exit into procedure */
-#define D_FILE      4   
-#define D_CACHE     8   /* cache debugging */
-#define D_MALLOC    16  /* print malloc, de-alloc information */
-#define D_CNODE     32
-#define D_UPCALL    64  /* up and downcall debugging */
-#define D_PSDEV    128  
-#define D_PIOCTL   256
-#define D_SPECIAL  512
-#define D_TIMING  1024
-#define D_DOWNCALL 2048
- 
-#define CDEBUG(mask, format, a...)                                \
-  do {                                                            \
-  if (coda_debug & mask) {                                        \
-    printk("(%s,l. %d): ",  __FUNCTION__, __LINE__);              \
-    printk(format, ## a); }                                       \
-} while (0)
-
-#define CODA_ALLOC(ptr, cast, size)                                       \
-do {                                                                      \
-    if (size < PAGE_SIZE) {                                               \
-        ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL);            \
-        CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr);     \
-     }  else {                                                            \
-        ptr = (cast)vmalloc((unsigned long) size);                        \
-	CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);}   \
-    if (ptr == 0) {                                                       \
+#define CODA_ALLOC(ptr, cast, size) do { \
+    if (size < PAGE_SIZE) \
+        ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \
+    else \
+        ptr = (cast)vmalloc((unsigned long) size); \
+    if (!ptr) \
         printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \
-    }                                                                     \
-    else memset( ptr, 0, size );                                          \
+    else memset( ptr, 0, size ); \
 } while (0)
 
 
-#define CODA_FREE(ptr,size) do {if (size < PAGE_SIZE) { kfree((ptr)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0)
+#define CODA_FREE(ptr,size) \
+    do { if (size < PAGE_SIZE) kfree((ptr)); else vfree((ptr)); } while (0)
 
 /* inode to cnode access functions */
 
diff -urN linux-2.5.6-pre2/include/linux/coda_proc.h linux-2.5.6-pre3/include/linux/coda_proc.h
--- linux-2.5.6-pre2/include/linux/coda_proc.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/include/linux/coda_proc.h	Wed Mar  6 17:17:56 2002
@@ -24,14 +24,12 @@
  *
  *	/proc/fs/coda/vfs_stats
  *		      upcall_stats
- *		      permission_stats
  *		      cache_inv_stats
  *
  * these four files are presented to reset the statistics to 0:
  *
  *	/proc/sys/coda/vfs_stats
  *		       upcall_stats
- *		       permission_stats
  *		       cache_inv_stats
  */
 
@@ -70,15 +68,6 @@
   unsigned long time_squared_sum;
 };
 
-
-
-/* cache hits for permissions statistics */
-struct coda_permission_stats 
-{
-	int count;
-	int hit_count;
-};
-
 /* cache invalidation statistics */
 struct coda_cache_inv_stats
 {
@@ -93,14 +82,12 @@
 
 /* these global variables hold the actual statistics data */
 extern struct coda_vfs_stats		coda_vfs_stat;
-extern struct coda_permission_stats	coda_permission_stat;
 extern struct coda_cache_inv_stats	coda_cache_inv_stat;
 extern int				coda_upcall_timestamping;
 
 /* reset statistics to 0 */
 void reset_coda_vfs_stats( void );
 void reset_coda_upcall_stats( void );
-void reset_coda_permission_stats( void );
 void reset_coda_cache_inv_stats( void );
 
 /* some utitlities to make it easier for you to do statistics for time */
@@ -121,9 +108,6 @@
 int do_reset_coda_upcall_stats( ctl_table * table, int write, 
 				struct file * filp, void * buffer, 
 				size_t * lenp );
-int do_reset_coda_permission_stats( ctl_table * table, int write, 
-				    struct file * filp, void * buffer, 
-				    size_t * lenp );
 int do_reset_coda_cache_inv_stats( ctl_table * table, int write, 
 				   struct file * filp, void * buffer, 
 				   size_t * lenp );
@@ -133,8 +117,6 @@
 			     int length);
 int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
 				int length);
-int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
-				    int length);
 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
 				   int length);
 
diff -urN linux-2.5.6-pre2/include/linux/compiler.h linux-2.5.6-pre3/include/linux/compiler.h
--- linux-2.5.6-pre2/include/linux/compiler.h	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/include/linux/compiler.h	Wed Mar  6 17:17:56 2002
@@ -13,4 +13,10 @@
 #define likely(x)	__builtin_expect((x),1)
 #define unlikely(x)	__builtin_expect((x),0)
 
+/* This macro obfuscates arithmetic on a variable address so that gcc
+   shouldn't recognize the original var, and make assumptions about it */
+#define RELOC_HIDE(var, off)					\
+  ({ __typeof__(&(var)) __ptr;					\
+    __asm__ ("" : "=g"(__ptr) : "0"((void *)&(var) + (off)));	\
+    *__ptr; })
 #endif /* __LINUX_COMPILER_H */
diff -urN linux-2.5.6-pre2/include/linux/fs.h linux-2.5.6-pre3/include/linux/fs.h
--- linux-2.5.6-pre2/include/linux/fs.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/linux/fs.h	Wed Mar  6 17:17:56 2002
@@ -400,6 +400,8 @@
 	const struct block_device_operations *bd_op;
 	struct semaphore	bd_sem;	/* open/close mutex */
 	struct list_head	bd_inodes;
+	void *			bd_holder;
+	int			bd_holders;
 };
 
 struct inode {
@@ -1069,6 +1071,8 @@
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
 extern int blkdev_put(struct block_device *, int);
+extern int bd_claim(struct block_device *, void *);
+extern void bd_release(struct block_device *);
 
 /* fs/devices.c */
 extern const struct block_device_operations *get_blkfops(unsigned int);
@@ -1273,7 +1277,6 @@
 #define LOOKUP_FOLLOW		(1)
 #define LOOKUP_DIRECTORY	(2)
 #define LOOKUP_CONTINUE		(4)
-#define LOOKUP_POSITIVE		(8)
 #define LOOKUP_PARENT		(16)
 #define LOOKUP_NOALT		(32)
 /*
@@ -1306,13 +1309,20 @@
 extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
+static inline int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+{
+	int error = 0;
+	if (path_init(path, flags, nd))
+		error = path_walk(path, nd);
+	return error;
+}
 extern void path_release(struct nameidata *);
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
-#define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
-#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+#define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW, nd)
+#define user_path_walk_link(name,nd) __user_walk(name, 0, nd)
 
 extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
@@ -1474,15 +1484,6 @@
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(kdev_t);
 extern void drop_super(struct super_block *sb);
-static inline int is_mounted(kdev_t dev)
-{
-	struct super_block *sb = get_super(dev);
-	if (sb) {
-		drop_super(sb);
-		return 1;
-	}
-	return 0;
-}
 extern kdev_t ROOT_DEV;
 extern char root_device_name[];
 
diff -urN linux-2.5.6-pre2/include/linux/hdreg.h linux-2.5.6-pre3/include/linux/hdreg.h
--- linux-2.5.6-pre2/include/linux/hdreg.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/include/linux/hdreg.h	Wed Mar  6 17:17:56 2002
@@ -51,7 +51,7 @@
 
 /*
  * Command Header sizes for IOCTL commands
- *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
+ *	HDIO_DRIVE_CMD and HDIO_DRIVE_TASK
  */
 
 #if 0
@@ -355,7 +355,6 @@
 #define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
 #define HDIO_TRISTATE_HWIF	0x031b	/* execute a channel tristate */
 #define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
-#define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
 #define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
 #define HDIO_DRIVE_CMD		0x031f	/* execute a special drive command */
 
diff -urN linux-2.5.6-pre2/include/linux/ide.h linux-2.5.6-pre3/include/linux/ide.h
--- linux-2.5.6-pre2/include/linux/ide.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/linux/ide.h	Wed Mar  6 17:17:56 2002
@@ -28,10 +28,7 @@
 
 /******************************************************************************
  * IDE driver configuration options (play with these as desired):
- *
- * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
  */
-#undef REALLY_FAST_IO			/* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
 
 #ifndef SUPPORT_SLOW_DATA_PORTS		/* 1 to support slow data ports */
@@ -49,32 +46,12 @@
 #ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
 #define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
 #endif
-
-#ifdef CONFIG_BLK_DEV_CMD640
-#if 0	/* change to 1 when debugging cmd640 problems */
-void cmd640_dump_regs (void);
-#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
-#endif
-#endif  /* CONFIG_BLK_DEV_CMD640 */
-
 #ifndef DISABLE_IRQ_NOSYNC
 #define DISABLE_IRQ_NOSYNC	0
 #endif
 
 /*
- * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
- */
-#define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
-
-#define IDE_DRIVE_TASK			98
-
-/*
- * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
- */
-#define IDE_DRIVE_TASKFILE		97
-
-/*
- *  "No user-serviceable parts" beyond this point  :)
+ *  "No user-serviceable parts" beyond this point
  *****************************************************************************/
 
 typedef unsigned char	byte;	/* used everywhere */
@@ -91,13 +68,6 @@
  */
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
 
-/*
- * Ensure that various configuration flags have compatible settings
- */
-#ifdef REALLY_SLOW_IO
-#undef REALLY_FAST_IO
-#endif
-
 #define HWIF(drive)		((drive)->hwif)
 #define HWGROUP(drive)		(HWIF(drive)->hwgroup)
 
@@ -192,33 +162,17 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
 #define SECTOR_SIZE	512
 #define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
-#define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
-#define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
-#define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
-
-#ifndef SPLIT_WORD
-#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
-#endif
-#ifndef MAKE_WORD
-#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
-#endif
-
 
 /*
  * Timeouts for various operations:
  */
 #define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
-#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
-#define WAIT_READY	(5*HZ)		/* 5sec - some laptops are very slow */
-#else
-#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
-#endif /* CONFIG_APM || CONFIG_APM_MODULE */
-#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
-#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
+#define WAIT_READY	(5*HZ)		/* 5sec   - some laptops are very slow */
+#define WAIT_PIDENTIFY	(10*HZ)		/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
+#define WAIT_WORSTCASE	(30*HZ)		/* 30sec  - worst case when spinning up */
+#define WAIT_CMD	(10*HZ)		/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
 #define SELECT_DRIVE(hwif,drive)				\
@@ -228,40 +182,12 @@
 	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
 }
 
-#define SELECT_INTERRUPT(hwif,drive)				\
-{								\
-	if (hwif->intrproc)					\
-		hwif->intrproc(drive);				\
-	else							\
-		OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);	\
-}
-
 #define SELECT_MASK(hwif,drive,mask)				\
 {								\
 	if (hwif->maskproc)					\
 		hwif->maskproc(drive,mask);			\
 }
 
-#define SELECT_READ_WRITE(hwif,drive,func)			\
-{								\
-	if (hwif->rwproc)					\
-		hwif->rwproc(drive,func);			\
-}
-
-#define QUIRK_LIST(hwif,drive)					\
-{								\
-	if (hwif->quirkproc)					\
-		(drive)->quirk_list = hwif->quirkproc(drive);	\
-}
-
-#define HOST(hwif,chipset)					\
-{								\
-	return ((hwif)->chipset == chipset) ? 1 : 0;		\
-}
-
-#define IDE_DEBUG(lineno) \
-	printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
-
 /*
  * Check for an interrupt and acknowledge the interrupt status
  */
@@ -269,19 +195,31 @@
 typedef int (ide_ack_intr_t)(struct hwif_s *);
 
 #ifndef NO_DMA
-#define NO_DMA  255
+# define NO_DMA  255
 #endif
 
 /*
- * hwif_chipset_t is used to keep track of the specific hardware
- * chipset used by each IDE interface, if known.
+ * This is used to keep track of the specific hardware chipset used by each IDE
+ * interface, if known. Please note that we don't discriminate between
+ * different PCI host chips here.
  */
-typedef enum {  ide_unknown,    ide_generic,    ide_pci,
-                ide_cmd640,     ide_dtc2278,    ide_ali14xx,
-                ide_qd65xx,     ide_umc8672,    ide_ht6560b,
-                ide_pdc4030,    ide_rz1000,     ide_trm290,
-                ide_cmd646,     ide_cy82c693,   ide_4drives,
-                ide_pmac,       ide_etrax100
+typedef enum {
+	ide_unknown,
+	ide_generic,
+	ide_pci,
+        ide_cmd640,
+	ide_dtc2278,
+	ide_ali14xx,
+	ide_qd65xx,
+	ide_umc8672,
+	ide_ht6560b,
+	ide_pdc4030,
+	ide_rz1000,
+	ide_trm290,
+	ide_cmd646,
+	ide_cy82c693,
+	ide_pmac,
+	ide_etrax100
 } hwif_chipset_t;
 
 
@@ -309,7 +247,7 @@
 /*
  * Set up hw_regs_t structure before calling ide_register_hw (optional)
  */
-void ide_setup_ports(	hw_regs_t *hw,
+void ide_setup_ports(hw_regs_t *hw,
 			ide_ioreg_t base,
 			int *offsets,
 			ide_ioreg_t ctrl,
@@ -320,28 +258,16 @@
 #include <asm/ide.h>
 
 /*
- * If the arch-dependant ide.h did not declare/define any OUT_BYTE
- * or IN_BYTE functions, we make some defaults here.
+ * If the arch-dependant ide.h did not declare/define any OUT_BYTE or IN_BYTE
+ * functions, we make some defaults here. The only architecture currently
+ * needing this is Cris.
  */
 
-#ifndef HAVE_ARCH_OUT_BYTE
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)          outb((b),(p))
-#define OUT_WORD(w,p)          outw((w),(p))
-#else
-#define OUT_BYTE(b,p)          outb_p((b),(p))
-#define OUT_WORD(w,p)          outw_p((w),(p))
-#endif
-#endif
-
-#ifndef HAVE_ARCH_IN_BYTE
-#ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb(p)
-#define IN_WORD(p)             (short)inw(p)
-#else
-#define IN_BYTE(p)             (byte)inb_p(p)
-#define IN_WORD(p)             (short)inw_p(p)
-#endif
+#ifndef HAVE_ARCH_IN_OUT
+# define OUT_BYTE(b,p)		outb((b),(p))
+# define OUT_WORD(w,p)		outw((w),(p))
+# define IN_BYTE(p)		(u8)inb(p)
+# define IN_WORD(p)		(u16)inw(p)
 #endif
 
 /*
@@ -370,6 +296,7 @@
 struct ide_settings_s;
 
 typedef struct ide_drive_s {
+	unsigned int	usage;		/* current "open()" count for drive */
 	char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
 
 	/* NOTE: If we had proper separation between channel and host chip, we
@@ -388,14 +315,14 @@
 	byte     using_dma;		/* disk is using dma for read/write */
 	byte	 retry_pio;		/* retrying dma capable host in pio */
 	byte	 state;			/* retry state */
-	byte     waiting_for_dma;	/* dma currently in progress */
 	byte     unmask;		/* flag: okay to unmask other irqs */
 	byte     slow;			/* flag: slow data port */
 	byte     bswap;			/* flag: byte swap data */
 	byte     dsc_overlap;		/* flag: DSC overlap */
 	byte     nice1;			/* flag: give potential excess bandwidth */
+	unsigned waiting_for_dma: 1;	/* dma currently in progress */
 	unsigned present	: 1;	/* drive is physically present */
-	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
+	unsigned noprobe	: 1;	/* from:  hdx=noprobe */
 	unsigned busy		: 1;	/* currently doing revalidate_disk() */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
@@ -422,7 +349,6 @@
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		nowerr;		/* used for ignoring WRERR_STAT */
 	byte		sect0;		/* offset of first sector for DM6:DDO */
-	unsigned int	usage;		/* current "open()" count for drive */
 	byte		head;		/* "real" number of heads */
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
@@ -555,12 +481,12 @@
 	unsigned long	select_data;	/* for use by chipset-specific code */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	int		irq;		/* our irq number */
-	byte		major;		/* our major number */
-	char 		name[80];	/* name of interface */
-	byte		index;		/* 0 for ide0; 1 for ide1; ... */
+	int		major;		/* our major number */
+	char		name[80];	/* name of interface */
+	int		index;		/* 0 for ide0; 1 for ide1; ... */
 	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
-	unsigned	present    : 1;	/* this interface exists */
+	unsigned	present    : 1;	/* there is a device on this interface */
 	unsigned	serialized : 1;	/* serialized operation with mate hwif */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
@@ -705,21 +631,19 @@
 	unsigned busy: 1; /* FIXME: this will go soon away... */
 	int (*cleanup)(ide_drive_t *);
 	int (*standby)(ide_drive_t *);
-	int (*flushcache)(ide_drive_t *);
 	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
 	int (*end_request)(ide_drive_t *drive, int uptodate);
 
 	int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 	int (*open)(struct inode *, struct file *, ide_drive_t *);
 	void (*release)(struct inode *, struct file *, ide_drive_t *);
-	int (*media_change)(ide_drive_t *);
+	int (*check_media_change)(ide_drive_t *);
 	void (*revalidate)(ide_drive_t *);
 
 	void (*pre_reset)(ide_drive_t *);
 	unsigned long (*capacity)(ide_drive_t *);
 	ide_startstop_t	(*special)(ide_drive_t *);
-	ide_proc_entry_t		*proc;
-	int (*driver_reinit)(ide_drive_t *);
+	ide_proc_entry_t *proc;
 };
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
@@ -734,6 +658,7 @@
 		__MOD_DEC_USE_COUNT((ata)->owner);	\
 } while(0)
 
+extern unsigned long ata_capacity(ide_drive_t *drive);
 
 /* FIXME: Actually implement and use them as soon as possible!  to make the
  * ide_scan_devices() go away! */
@@ -819,16 +744,6 @@
 ide_drive_t *get_info_ptr (kdev_t i_rdev);
 
 /*
- * Return the current idea about the total capacity of this drive.
- */
-unsigned long current_capacity (ide_drive_t *drive);
-
-/*
- * Revalidate (read partition tables)
- */
-extern void ide_revalidate_drive (ide_drive_t *drive);
-
-/*
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
@@ -892,18 +807,9 @@
 
 /*
  * Clean up after success/failure of an explicit drive cmd.
- * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
- * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
  */
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
-/*
- * Issue ATA command and wait for completion. use for implementing commands in kernel
- */
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
- 
 typedef struct ide_task_s {
 	task_ioreg_t		tfRegister[8];
 	task_ioreg_t		hobRegister[8];
@@ -941,15 +847,7 @@
  */
 
 ide_startstop_t set_multmode_intr (ide_drive_t *drive);
-ide_startstop_t set_geometry_intr (ide_drive_t *drive);
-ide_startstop_t recal_intr (ide_drive_t *drive);
 ide_startstop_t task_no_data_intr (ide_drive_t *drive);
-ide_startstop_t task_in_intr (ide_drive_t *drive);
-ide_startstop_t task_mulin_intr (ide_drive_t *drive);
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
-ide_startstop_t task_out_intr (ide_drive_t *drive);
-ide_startstop_t task_mulout_intr (ide_drive_t *drive);
-void ide_init_drive_taskfile (struct request *rq);
 
 int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
 
@@ -960,14 +858,9 @@
 /* Expects args is a full set of TF registers and parses the command type */
 int ide_cmd_type_parser (ide_task_t *args);
 
-int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 
-#ifdef CONFIG_PKT_TASK_IOCTL
-int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-#endif /* CONFIG_PKT_TASK_IOCTL */
-
 void ide_delay_50ms (void);
 
 byte ide_auto_reduce_xfer (ide_drive_t *drive);
@@ -994,14 +887,16 @@
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-request_queue_t *ide_get_queue (kdev_t dev);
+request_queue_t *ide_get_queue(kdev_t dev);
 
 /*
  * CompactFlash cards and their brethern pretend to be removable hard disks,
  * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ * This test catches them, and is invoked elsewhere when setting appropriate
+ * config bits.
  */
-int drive_is_flashcard (ide_drive_t *drive);
+
+extern int drive_is_flashcard(ide_drive_t *drive);
 
 int ide_spin_wait_hwgroup (ide_drive_t *drive);
 void ide_timer_expiry (unsigned long data);
@@ -1041,26 +936,23 @@
 #define ON_BOARD		1
 #define NEVER_BOARD		0
 #ifdef CONFIG_BLK_DEV_OFFBOARD
-#  define OFF_BOARD		ON_BOARD
-#else /* CONFIG_BLK_DEV_OFFBOARD */
-#  define OFF_BOARD		NEVER_BOARD
-#endif /* CONFIG_BLK_DEV_OFFBOARD */
+# define OFF_BOARD		ON_BOARD
+#else
+# define OFF_BOARD		NEVER_BOARD
+#endif
 
 void __init ide_scan_pcibus(int scan_direction);
 #endif
 #ifdef CONFIG_BLK_DEV_IDEDMA
-#define BAD_DMA_DRIVE		0
-#define GOOD_DMA_DRIVE		1
+# define BAD_DMA_DRIVE		0
+# define GOOD_DMA_DRIVE		1
 int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
 void ide_destroy_dmatable (ide_drive_t *drive);
 ide_startstop_t ide_dma_intr (ide_drive_t *drive);
 int check_drive_lists (ide_drive_t *drive, int good_bad);
-int report_drive_dmaing (ide_drive_t *drive);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
 int ide_release_dma (ide_hwif_t *hwif);
 void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
-/* FIXME spilt this up into a get and set function */
-extern unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
 #endif
 
 extern spinlock_t ide_lock;
diff -urN linux-2.5.6-pre2/include/linux/jbd.h linux-2.5.6-pre3/include/linux/jbd.h
--- linux-2.5.6-pre2/include/linux/jbd.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/include/linux/jbd.h	Wed Mar  6 17:17:56 2002
@@ -352,7 +352,7 @@
 	 */
 	struct journal_head *	t_async_datalist;
 	
-	/* Doubly-linked circular list of all forget buffers (superceded
+	/* Doubly-linked circular list of all forget buffers (superseded
            buffers which we can un-checkpoint once this transaction
            commits) */
 	struct journal_head *	t_forget;
@@ -793,7 +793,7 @@
 #define BJ_SyncData	1	/* Normal data: flush before commit */
 #define BJ_AsyncData	2	/* writepage data: wait on it before commit */
 #define BJ_Metadata	3	/* Normal journaled metadata */
-#define BJ_Forget	4	/* Buffer superceded by this transaction */
+#define BJ_Forget	4	/* Buffer superseded by this transaction */
 #define BJ_IO		5	/* Buffer is for temporary IO use */
 #define BJ_Shadow	6	/* Buffer contents being shadowed to the log */
 #define BJ_LogCtl	7	/* Buffer contains log descriptors */
diff -urN linux-2.5.6-pre2/include/linux/mm.h linux-2.5.6-pre3/include/linux/mm.h
--- linux-2.5.6-pre2/include/linux/mm.h	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/include/linux/mm.h	Wed Mar  6 17:17:56 2002
@@ -193,11 +193,6 @@
 #define page_count(p)		atomic_read(&(p)->count)
 #define set_page_count(p,v) 	atomic_set(&(p)->count, v)
 
-static inline void init_page_count(struct page *page)
-{
-	page->count.counter = 0;
-}
-
 /*
  * Various page->flags bits:
  *
diff -urN linux-2.5.6-pre2/include/linux/pci.h linux-2.5.6-pre3/include/linux/pci.h
--- linux-2.5.6-pre2/include/linux/pci.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/include/linux/pci.h	Wed Mar  6 17:17:56 2002
@@ -483,7 +483,7 @@
 	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
 	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
 	int  (*save_state) (struct pci_dev *dev, u32 state);    /* Save Device Context */
-	int  (*suspend)(struct pci_dev *dev, u32 state);	/* Device suspended */
+	int  (*suspend) (struct pci_dev *dev, u32 state);	/* Device suspended */
 	int  (*resume) (struct pci_dev *dev);	                /* Device woken up */
 	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
 };
diff -urN linux-2.5.6-pre2/include/linux/reiserfs_fs_sb.h linux-2.5.6-pre3/include/linux/reiserfs_fs_sb.h
--- linux-2.5.6-pre2/include/linux/reiserfs_fs_sb.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/include/linux/reiserfs_fs_sb.h	Wed Mar  6 17:17:56 2002
@@ -454,6 +454,5 @@
 #define SB_JOURNAL_MAX_COMMIT_AGE(s) (SB_JOURNAL(s)->s_journal_max_commit_age)
 #define SB_JOURNAL_MAX_TRANS_AGE(s)  (SB_JOURNAL(s)->s_journal_max_trans_age)
 #define SB_JOURNAL_DEV(s)            (SB_JOURNAL(s)->j_dev)
-  
 
 #endif	/* _LINUX_REISER_FS_SB */
diff -urN linux-2.5.6-pre2/include/linux/smp.h linux-2.5.6-pre3/include/linux/smp.h
--- linux-2.5.6-pre2/include/linux/smp.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre3/include/linux/smp.h	Wed Mar  6 17:17:56 2002
@@ -11,6 +11,7 @@
 #ifdef CONFIG_SMP
 
 #include <linux/kernel.h>
+#include <linux/compiler.h>
 #include <asm/smp.h>
 
 /*
@@ -71,7 +72,17 @@
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
 #define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
-#else
+#define __per_cpu_data	__attribute__((section(".data.percpu")))
+
+#ifndef __HAVE_ARCH_PER_CPU
+extern unsigned long __per_cpu_offset[NR_CPUS];
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) RELOC_HIDE(var, per_cpu_offset(cpu))
+
+#define this_cpu(var) per_cpu(var, smp_processor_id())
+#endif /* !__HAVE_ARCH_PER_CPU */
+#else /* !SMP */
 
 /*
  *	These macros fold the SMP functionality into a single CPU system
@@ -90,6 +101,9 @@
 #define cpu_online_map				1
 static inline void smp_send_reschedule(int cpu) { }
 static inline void smp_send_reschedule_all(void) { }
+#define __per_cpu_data
+#define per_cpu(var, cpu)			var
+#define this_cpu(var)				var
 
 #endif
 #endif
diff -urN linux-2.5.6-pre2/include/linux/swap.h linux-2.5.6-pre3/include/linux/swap.h
--- linux-2.5.6-pre2/include/linux/swap.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/include/linux/swap.h	Wed Mar  6 17:17:56 2002
@@ -64,7 +64,6 @@
 enum {
 	SWP_USED	= (1 << 0),	/* is slot in swap_info[] used? */
 	SWP_WRITEOK	= (1 << 1),	/* ok to write to this swap?	*/
-	SWP_BLOCKDEV	= (1 << 2),	/* is this swap a block device? */
 	SWP_ACTIVE	= (SWP_USED | SWP_WRITEOK),
 };
 
@@ -151,7 +150,6 @@
 extern int total_swap_pages;
 extern unsigned int nr_swapfiles;
 extern struct swap_info_struct swap_info[];
-extern int is_swap_partition(kdev_t);
 extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(void);
 extern void get_swaphandle_info(swp_entry_t, unsigned long *, struct inode **);
diff -urN linux-2.5.6-pre2/include/linux/telephony.h linux-2.5.6-pre3/include/linux/telephony.h
--- linux-2.5.6-pre2/include/linux/telephony.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/include/linux/telephony.h	Wed Mar  6 17:17:56 2002
@@ -228,8 +228,8 @@
 * indicate the current state of the hookswitch.  The pstn_ring bit
 * indicates that the DAA on a LineJACK card has detected ring voltage on
 * the PSTN port.  The caller_id bit indicates that caller_id data has been
-* recieved and is available.  The pstn_wink bit indicates that the DAA on
-* the LineJACK has recieved a wink from the telco switch.  The f0, f1, f2
+* received and is available.  The pstn_wink bit indicates that the DAA on
+* the LineJACK has received a wink from the telco switch.  The f0, f1, f2
 * and f3 bits indicate that the filter has been triggered by detecting the
 * frequency programmed into that filter.
 *
diff -urN linux-2.5.6-pre2/include/net/irda/irda-usb.h linux-2.5.6-pre3/include/net/irda/irda-usb.h
--- linux-2.5.6-pre2/include/net/irda/irda-usb.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/include/net/irda/irda-usb.h	Wed Mar  6 17:17:56 2002
@@ -139,10 +139,10 @@
 
 	wait_queue_head_t wait_q;	/* for timeouts */
 
-	struct urb rx_urb[IU_MAX_RX_URBS];	/* URBs used to receive data frames */
+	struct urb *rx_urb[IU_MAX_RX_URBS];	/* URBs used to receive data frames */
 	struct urb *idle_rx_urb;	/* Pointer to idle URB in Rx path */
-	struct urb tx_urb;		/* URB used to send data frames */
-	struct urb speed_urb;		/* URB used to send speed commands */
+	struct urb *tx_urb;		/* URB used to send data frames */
+	struct urb *speed_urb;		/* URB used to send speed commands */
 	
 	struct net_device *netdev;	/* Yes! we are some kind of netdev. */
 	struct net_device_stats stats;
diff -urN linux-2.5.6-pre2/include/net/irda/irlap.h linux-2.5.6-pre3/include/net/irda/irlap.h
--- linux-2.5.6-pre2/include/net/irda/irlap.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/include/net/irda/irlap.h	Wed Mar  6 17:17:56 2002
@@ -11,6 +11,7 @@
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
+ *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -44,6 +45,7 @@
 #define LAP_ADDR_HEADER 1  /* IrLAP Address Header */
 #define LAP_CTRL_HEADER 1  /* IrLAP Control Header */
 
+/* May be different when we get VFIR */
 #define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
 
 #define BROADCAST  0xffffffff /* Broadcast device address */
@@ -210,9 +212,8 @@
 void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
 void irlap_apply_default_connection_parameters(struct irlap_cb *self);
 void irlap_apply_connection_parameters(struct irlap_cb *self, int now);
-void irlap_set_local_busy(struct irlap_cb *self, int status);
 
-#define IRLAP_GET_HEADER_SIZE(self) 2 /* Will be different when we get VFIR */
+#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
 #endif
diff -urN linux-2.5.6-pre2/include/net/irda/irlap_event.h linux-2.5.6-pre3/include/net/irda/irlap_event.h
--- linux-2.5.6-pre2/include/net/irda/irlap_event.h	Tue Feb 19 18:10:52 2002
+++ linux-2.5.6-pre3/include/net/irda/irlap_event.h	Wed Mar  6 17:17:56 2002
@@ -134,7 +134,6 @@
 
 void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, 
 		    struct sk_buff *skb, struct irlap_info *info);
-void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state);
 void irlap_print_event(IRLAP_EVENT event);
 
 extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb);
diff -urN linux-2.5.6-pre2/init/main.c linux-2.5.6-pre3/init/main.c
--- linux-2.5.6-pre2/init/main.c	Wed Mar  6 17:17:38 2002
+++ linux-2.5.6-pre3/init/main.c	Wed Mar  6 17:17:56 2002
@@ -270,8 +270,35 @@
 #define smp_init()	do { } while (0)
 #endif
 
+static inline void setup_per_cpu_areas(void)
+{
+}
 #else
 
+#ifndef __HAVE_ARCH_PER_CPU
+unsigned long __per_cpu_offset[NR_CPUS];
+
+static void __init setup_per_cpu_areas(void)
+{
+	unsigned long size, i;
+	char *ptr;
+	/* Created by linker magic */
+	extern char __per_cpu_start[], __per_cpu_end[];
+
+	/* Copy section for each CPU (we discard the original) */
+	size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
+	if (!size)
+		return;
+
+	ptr = alloc_bootmem(size * NR_CPUS);
+
+	for (i = 0; i < NR_CPUS; i++, ptr += size) {
+		__per_cpu_offset[i] = ptr - __per_cpu_start;
+		memcpy(ptr, __per_cpu_start, size);
+	}
+}
+#endif /* !__HAVE_ARCH_PER_CPU */
+
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
@@ -314,6 +341,7 @@
 	lock_kernel();
 	printk(linux_banner);
 	setup_arch(&command_line);
+	setup_per_cpu_areas();
 	printk("Kernel command line: %s\n", saved_command_line);
 	parse_options(command_line);
 	trap_init();
@@ -377,6 +405,7 @@
 	printk("POSIX conformance testing by UNIFIX\n");
 
 	init_idle(current, smp_processor_id());
+
 	/* 
 	 *	We count on the initial thread going ok 
 	 *	Like idlers init is an unlocked kernel thread, which will
diff -urN linux-2.5.6-pre2/kernel/kmod.c linux-2.5.6-pre3/kernel/kmod.c
--- linux-2.5.6-pre2/kernel/kmod.c	Wed Mar  6 17:17:39 2002
+++ linux-2.5.6-pre3/kernel/kmod.c	Wed Mar  6 17:17:56 2002
@@ -159,9 +159,14 @@
 
 	ret = exec_usermodehelper(modprobe_path, argv, envp);
 	if (ret) {
-		printk(KERN_DEBUG
-		       "kmod: failed to exec %s -s -k %s, errno = %d\n",
-		       modprobe_path, (char*) module_name, errno);
+		static unsigned long last;
+		unsigned long now = jiffies;
+		if (now - last > HZ) {
+			last = now;
+			printk(KERN_DEBUG
+			       "kmod: failed to exec %s -s -k %s, errno = %d\n",
+			       modprobe_path, (char*) module_name, errno);
+		}
 	}
 	return ret;
 }
diff -urN linux-2.5.6-pre2/kernel/ksyms.c linux-2.5.6-pre3/kernel/ksyms.c
--- linux-2.5.6-pre2/kernel/ksyms.c	Wed Mar  6 17:17:39 2002
+++ linux-2.5.6-pre3/kernel/ksyms.c	Wed Mar  6 17:17:56 2002
@@ -152,6 +152,7 @@
 EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(dcache_lock);
+EXPORT_SYMBOL(dparent_lock);
 EXPORT_SYMBOL(d_alloc_root);
 EXPORT_SYMBOL(d_delete);
 EXPORT_SYMBOL(dget_locked);
@@ -197,6 +198,8 @@
 EXPORT_SYMBOL(cdput);
 EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bdput);
+EXPORT_SYMBOL(bd_claim);
+EXPORT_SYMBOL(bd_release);
 EXPORT_SYMBOL(__bread);
 EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__bforget);
diff -urN linux-2.5.6-pre2/kernel/sched.c linux-2.5.6-pre3/kernel/sched.c
--- linux-2.5.6-pre2/kernel/sched.c	Wed Mar  6 17:17:39 2002
+++ linux-2.5.6-pre3/kernel/sched.c	Wed Mar  6 17:17:56 2002
@@ -397,7 +397,7 @@
 			p->sleep_avg) / (EXIT_WEIGHT + 1);
 }
 
-#if CONFIG_SMP
+#if CONFIG_SMP || CONFIG_PREEMPT
 asmlinkage void schedule_tail(void)
 {
 	spin_unlock_irq(&this_rq()->lock);
@@ -1438,6 +1438,7 @@
 	idle->prio = MAX_PRIO;
 	idle->state = TASK_RUNNING;
 	idle->thread_info->cpu = cpu;
+	idle->thread_info->preempt_count = (idle->lock_depth >= 0);
 	double_rq_unlock(idle_rq, rq);
 	set_tsk_need_resched(idle);
 	__restore_flags(flags);
diff -urN linux-2.5.6-pre2/kernel/signal.c linux-2.5.6-pre3/kernel/signal.c
--- linux-2.5.6-pre2/kernel/signal.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre3/kernel/signal.c	Wed Mar  6 17:17:56 2002
@@ -546,7 +546,7 @@
 	if (bad_signal(sig, info, t))
 		goto out_nolock;
 
-	/* The null signal is a permissions and process existance probe.
+	/* The null signal is a permissions and process existence probe.
 	   No signal is actually delivered.  Same goes for zombies. */
 	ret = 0;
 	if (!sig || !t->sig)
diff -urN linux-2.5.6-pre2/lib/zlib_inflate/inflate.c linux-2.5.6-pre3/lib/zlib_inflate/inflate.c
--- linux-2.5.6-pre2/lib/zlib_inflate/inflate.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/lib/zlib_inflate/inflate.c	Wed Mar  6 17:17:56 2002
@@ -117,12 +117,12 @@
 z_streamp z;
 int f;
 {
-  int r;
+  int r, trv;
   uInt b;
 
   if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
     return Z_STREAM_ERROR;
-  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
   r = Z_BUF_ERROR;
   while (1) switch (z->state->mode)
   {
@@ -193,10 +193,10 @@
         break;
       }
       if (r == Z_OK)
-        r = f;
+        r = trv;
       if (r != Z_STREAM_END)
         return r;
-      r = f;
+      r = trv;
       zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
       if (z->state->nowrap)
       {
diff -urN linux-2.5.6-pre2/mm/filemap.c linux-2.5.6-pre3/mm/filemap.c
--- linux-2.5.6-pre2/mm/filemap.c	Wed Mar  6 17:17:39 2002
+++ linux-2.5.6-pre3/mm/filemap.c	Wed Mar  6 17:17:56 2002
@@ -1715,7 +1715,7 @@
 	return written;
 }
 
-asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+static ssize_t common_sendfile(int out_fd, int in_fd, loff_t *offset, size_t count, loff_t max)
 {
 	ssize_t retval;
 	struct file * in_file, * out_file;
@@ -1760,27 +1760,34 @@
 	retval = 0;
 	if (count) {
 		read_descriptor_t desc;
-		loff_t pos = 0, *ppos;
+		loff_t pos;
+
+		if (!offset)
+			offset = &in_file->f_pos;
 
-		retval = -EFAULT;
-		ppos = &in_file->f_pos;
-		if (offset) {
-			if (get_user(pos, offset))
+		pos = *offset;
+		retval = -EINVAL;
+		if (unlikely(pos < 0))
+			goto fput_out;
+		if (unlikely(pos + count > max)) {
+			retval = -EOVERFLOW;
+			if (pos >= max)
 				goto fput_out;
-			ppos = &pos;
+			count = max - pos;
 		}
 
 		desc.written = 0;
 		desc.count = count;
 		desc.buf = (char *) out_file;
 		desc.error = 0;
-		do_generic_file_read(in_file, ppos, &desc, file_send_actor);
+		do_generic_file_read(in_file, offset, &desc, file_send_actor);
 
 		retval = desc.written;
 		if (!retval)
 			retval = desc.error;
-		if (offset)
-			put_user(pos, offset);
+		pos = *offset;
+		if (pos > max)
+			retval = -EOVERFLOW;
 	}
 
 fput_out:
@@ -1791,6 +1798,38 @@
 	return retval;
 }
 
+asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+	loff_t pos, *ppos = NULL;
+	ssize_t ret;
+	if (offset) {
+		off_t off;
+		if (unlikely(get_user(off, offset)))
+			return -EFAULT;
+		pos = off;
+		ppos = &pos;
+	}
+	ret = common_sendfile(out_fd, in_fd, ppos, count, MAX_NON_LFS);
+	if (offset && put_user(pos, offset))
+		ret = -EFAULT;
+	return ret;
+}
+
+asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count)
+{
+	loff_t pos, *ppos = NULL;
+	ssize_t ret;
+	if (offset) {
+		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
+			return -EFAULT;
+		ppos = &pos;
+	}
+	ret = common_sendfile(out_fd, in_fd, ppos, count, MAX_LFS_FILESIZE);
+	if (offset && put_user(pos, offset))
+		ret = -EFAULT;
+	return ret;
+}
+
 static ssize_t do_readahead(struct file *file, unsigned long index, unsigned long nr)
 {
 	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
diff -urN linux-2.5.6-pre2/mm/page_alloc.c linux-2.5.6-pre3/mm/page_alloc.c
--- linux-2.5.6-pre2/mm/page_alloc.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre3/mm/page_alloc.c	Wed Mar  6 17:17:56 2002
@@ -811,7 +811,7 @@
 		for (i = 0; i < size; i++) {
 			struct page *page = mem_map + offset + i;
 			set_page_zone(page, nid * MAX_NR_ZONES + j);
-			init_page_count(page);
+			set_page_count(page, 0);
 			__SetPageReserved(page);
 			memlist_init(&page->list);
 			if (j != ZONE_HIGHMEM)
diff -urN linux-2.5.6-pre2/mm/slab.c linux-2.5.6-pre3/mm/slab.c
--- linux-2.5.6-pre2/mm/slab.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/mm/slab.c	Wed Mar  6 17:17:56 2002
@@ -341,7 +341,9 @@
 	{    32,	NULL, NULL},
 #endif
 	{    64,	NULL, NULL},
+	{    96,	NULL, NULL},
 	{   128,	NULL, NULL},
+	{   192,	NULL, NULL},
 	{   256,	NULL, NULL},
 	{   512,	NULL, NULL},
 	{  1024,	NULL, NULL},
@@ -364,7 +366,9 @@
 	CN("size-32"),
 #endif
 	CN("size-64"),
+	CN("size-96"),
 	CN("size-128"),
+	CN("size-192"),
 	CN("size-256"),
 	CN("size-512"),
 	CN("size-1024"),
diff -urN linux-2.5.6-pre2/mm/swapfile.c linux-2.5.6-pre3/mm/swapfile.c
--- linux-2.5.6-pre2/mm/swapfile.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre3/mm/swapfile.c	Wed Mar  6 17:17:56 2002
@@ -786,6 +786,8 @@
 	swap_device_unlock(p);
 	swap_list_unlock();
 	vfree(swap_map);
+	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode))
+		bd_release(swap_file->f_dentry->d_inode->i_bdev);
 	filp_close(swap_file, NULL);
 	err = 0;
 
@@ -807,43 +809,33 @@
 
 	len = sprintf(buf, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
-		if ((ptr->flags & SWP_USED) && ptr->swap_map) {
-			char * path = d_path(ptr->swap_file->f_dentry,
-						ptr->swap_file->f_vfsmnt,
-						page, PAGE_SIZE);
-			int j, usedswap = 0;
-			for (j = 0; j < ptr->max; ++j)
-				switch (ptr->swap_map[j]) {
-					case SWAP_MAP_BAD:
-					case 0:
-						continue;
-					default:
-						usedswap++;
-				}
-			len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
-				       path,
-				       (ptr->flags & SWP_BLOCKDEV) ?
-				       		"partition" : "file\t",
-				       ptr->pages << (PAGE_SHIFT - 10),
-				       usedswap << (PAGE_SHIFT - 10),
-				       ptr->prio);
-		}
-	}
-	free_page((unsigned long) page);
-	return len;
-}
+		int j, usedswap;
+		struct file *file;
+		char *path;
 
-int is_swap_partition(kdev_t dev) {
-	struct swap_info_struct *ptr = swap_info;
-	int i;
+		if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
+			continue;
 
-	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
-		if ((ptr->flags & SWP_USED) &&
-		    (ptr->flags & SWP_BLOCKDEV) &&
-		    (kdev_same(ptr->swap_file->f_dentry->d_inode->i_rdev, dev)))
-			return 1;
+		file = ptr->swap_file;
+		path = d_path(file->f_dentry, file->f_vfsmnt, page, PAGE_SIZE);
+		for (j = 0,usedswap = 0; j < ptr->max; ++j)
+			switch (ptr->swap_map[j]) {
+				case SWAP_MAP_BAD:
+				case 0:
+					continue;
+				default:
+					usedswap++;
+			}
+		len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
+			       path,
+			       S_ISBLK(file->f_dentry->d_inode->i_mode) ?
+					"partition" : "file\t",
+			       ptr->pages << (PAGE_SHIFT - 10),
+			       usedswap << (PAGE_SHIFT - 10),
+			       ptr->prio);
 	}
-	return 0;
+	free_page((unsigned long) page);
+	return len;
 }
 
 /*
@@ -855,6 +847,7 @@
 {
 	struct swap_info_struct * p;
 	char *name;
+	struct block_device *bdev = NULL;
 	struct file *swap_file = NULL;
 	struct address_space *mapping;
 	unsigned int type;
@@ -905,13 +898,21 @@
 	swap_file = filp_open(name, O_RDWR, 0);
 	putname(name);
 	error = PTR_ERR(swap_file);
-	if (IS_ERR(swap_file))
+	if (IS_ERR(swap_file)) {
+		swap_file = NULL;
 		goto bad_swap_2;
+	}
 
 	p->swap_file = swap_file;
 
 	error = -EINVAL;
 	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+		bdev = swap_file->f_dentry->d_inode->i_bdev;
+		error = bd_claim(bdev, sys_swapon);
+		if (error < 0) {
+			bdev = NULL;
+			goto bad_swap;
+		}
 		error = set_blocksize(swap_file->f_dentry->d_inode->i_rdev,
 				      PAGE_SIZE);
 		if (error < 0)
@@ -1039,8 +1040,6 @@
 	swap_device_lock(p);
 	p->max = maxpages;
 	p->flags = SWP_ACTIVE;
-	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode))
-		p->flags |= SWP_BLOCKDEV;
 	p->pages = nr_good_pages;
 	nr_swap_pages += nr_good_pages;
 	total_swap_pages += nr_good_pages;
@@ -1066,6 +1065,8 @@
 	error = 0;
 	goto out;
 bad_swap:
+	if (bdev)
+		bd_release(bdev);
 bad_swap_2:
 	swap_list_lock();
 	swap_map = p->swap_map;
diff -urN linux-2.5.6-pre2/net/core/dev.c linux-2.5.6-pre3/net/core/dev.c
--- linux-2.5.6-pre2/net/core/dev.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre3/net/core/dev.c	Wed Mar  6 17:17:56 2002
@@ -445,7 +445,7 @@
 
 /* 
    Return value is changed to int to prevent illegal usage in future.
-   It is still legal to use to check for device existance.
+   It is still legal to use to check for device existence.
 
    User should understand, that the result returned by this function
    is meaningless, if it was not issued under rtnl semaphore.
diff -urN linux-2.5.6-pre2/net/irda/af_irda.c linux-2.5.6-pre3/net/irda/af_irda.c
--- linux-2.5.6-pre2/net/irda/af_irda.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre3/net/irda/af_irda.c	Wed Mar  6 17:17:56 2002
@@ -1022,29 +1022,27 @@
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
-		
-	cli();	/* To avoid races on the sleep */
-	
-	/* A Connect Ack with Choke or timeout or failed routing will go to
-	 * closed.  */
+
+	/* Here, there is a race condition : the state may change between
+	 * our test and the sleep, via irda_connect_confirm().
+	 * The way to workaround that is to sleep with a timeout, so that
+	 * we don't sleep forever and check the state when waking up.
+	 * 50ms is plenty good enough, because the LAP is already connected.
+	 * Jean II */
 	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on(sk->sleep);
+		interruptible_sleep_on_timeout(sk->sleep, HZ/20);
 		if (signal_pending(current)) {
-			sti();
 			return -ERESTARTSYS;
 		}
 	}
 	
 	if (sk->state != TCP_ESTABLISHED) {
-		sti();
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
 	
 	sock->state = SS_CONNECTED;
 	
-	sti();
-	
 	/* At this point, IrLMP has assigned our source address */
 	self->saddr = irttp_get_saddr(self->tsap);
 
diff -urN linux-2.5.6-pre2/net/irda/irda_device.c linux-2.5.6-pre3/net/irda/irda_device.c
--- linux-2.5.6-pre2/net/irda/irda_device.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/net/irda/irda_device.c	Wed Mar  6 17:17:56 2002
@@ -598,7 +598,7 @@
 	disable_dma(channel);
 	clear_dma_ff(channel);
 	set_dma_mode(channel, mode);
-	set_dma_addr(channel, virt_to_bus(buffer));
+	set_dma_addr(channel, isa_virt_to_bus(buffer));
 	set_dma_count(channel, count);
 	enable_dma(channel);
 
diff -urN linux-2.5.6-pre2/net/irda/irlap.c linux-2.5.6-pre3/net/irda/irlap.c
--- linux-2.5.6-pre2/net/irda/irlap.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre3/net/irda/irlap.c	Wed Mar  6 17:17:56 2002
@@ -131,7 +131,7 @@
 	/* FIXME: should we get our own field? */
 	dev->atalk_ptr = self;
 
-	irlap_next_state(self, LAP_OFFLINE);
+	self->state = LAP_OFFLINE;
 
 	/* Initialize transmit queue */
 	skb_queue_head_init(&self->txq);
@@ -155,7 +155,7 @@
 
 	self->N3 = 3; /* # connections attemts to try before giving up */
 	
-	irlap_next_state(self, LAP_NDM);
+	self->state = LAP_NDM;
 
 	hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);
 
@@ -346,25 +346,21 @@
 	else
 		skb->data[1] = I_FRAME;
 
+	/* Add at the end of the queue (keep ordering) - Jean II */
+	skb_queue_tail(&self->txq, skb);
+
 	/* 
 	 *  Send event if this frame only if we are in the right state 
 	 *  FIXME: udata should be sent first! (skb_queue_head?)
 	 */
   	if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
-		/*
-		 *  Check if the transmit queue contains some unsent frames,
-		 *  and if so, make sure they are sent first
-		 */
-		if (!skb_queue_empty(&self->txq)) {
-			skb_queue_tail(&self->txq, skb);
-			skb = skb_dequeue(&self->txq);
-			
-			ASSERT(skb != NULL, return;);
-		}
-		irlap_do_event(self, SEND_I_CMD, skb, NULL);
-		kfree_skb(skb);
-	} else
-		skb_queue_tail(&self->txq, skb);
+		/* If we are not already processing the Tx queue, trigger
+		 * transmission immediately - Jean II */
+		if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy))
+			irlap_do_event(self, DATA_REQUEST, skb, NULL);
+		/* Otherwise, the packets will be sent normally at the
+		 * next pf-poll - Jean II */
+	}
 }
 
 /*
@@ -1013,6 +1009,7 @@
 	self->window_size = self->qos_tx.window_size.value;
 	self->window      = self->qos_tx.window_size.value;
 
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 	/*
 	 *  Calculate how many bytes it is possible to transmit before the
 	 *  link must be turned around
@@ -1020,6 +1017,8 @@
 	self->line_capacity = 
 		irlap_max_line_capacity(self->qos_tx.baud_rate.value,
 					self->qos_tx.max_turn_time.value);
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 
 	
 	/* 
@@ -1082,24 +1081,6 @@
 	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
 }
 
-/*
- * Function irlap_set_local_busy (self, status)
- *
- *    
- *
- */
-void irlap_set_local_busy(struct irlap_cb *self, int status)
-{
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
-	self->local_busy = status;
-	
-	if (status)
-		IRDA_DEBUG(0, __FUNCTION__ "(), local busy ON\n");
-	else
-		IRDA_DEBUG(0, __FUNCTION__ "(), local busy OFF\n");
-}
-
 #ifdef CONFIG_PROC_FS
 /*
  * Function irlap_proc_read (buf, start, offset, len, unused)
diff -urN linux-2.5.6-pre2/net/irda/irlap_event.c linux-2.5.6-pre3/net/irda/irlap_event.c
--- linux-2.5.6-pre2/net/irda/irlap_event.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/net/irda/irlap_event.c	Wed Mar  6 17:17:56 2002
@@ -252,6 +252,9 @@
 		 * that will change the state away form XMIT
 		 */
 		if (skb_queue_len(&self->txq)) {
+			/* Prevent race conditions with irlap_data_request() */
+			self->local_busy = TRUE;
+
 			/* Try to send away all queued data frames */
 			while ((skb = skb_dequeue(&self->txq)) != NULL) {
 				ret = (*state[self->state])(self, SEND_I_CMD,
@@ -260,6 +263,8 @@
 				if (ret == -EPROTO)
 					break; /* Try again later! */
 			}
+			/* Finished transmitting */
+			self->local_busy = FALSE;
 		} else if (self->disconnect_pending) {
 			self->disconnect_pending = FALSE;
 			
@@ -282,25 +287,15 @@
  *    Switches state and provides debug information
  *
  */
-void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
+static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
 {	
+	/*
 	if (!self || self->magic != LAP_MAGIC)
 		return;
 	
 	IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
-
+	*/
 	self->state = state;
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
-	/*
-	 *  If we are swithing away from a XMIT state then we are allowed to 
-	 *  transmit a maximum number of bytes again when we enter the XMIT 
-	 *  state again. Since its possible to "switch" from XMIT to XMIT,
-	 *  we cannot do this when swithing into the XMIT state :-)
-	 */
-	if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
-		self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 }
 
 /*
@@ -1017,6 +1012,12 @@
 		IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n",
 			   jiffies);
 		irlap_send_rr_frame(self, CMD_FRAME);
+		/* Return to NRM properly - Jean II  */
+		self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+		/* Allowed to transmit a maximum number of bytes again. */
+		self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 		irlap_start_final_timer(self, self->final_timeout);
 		irlap_next_state(self, LAP_NRM_P);
 		break;
@@ -1029,6 +1030,10 @@
 		self->retry_count = 0;
 		irlap_next_state(self, LAP_PCLOSE);
 		break;
+	case DATA_REQUEST:
+		/* Nothing to do, irlap_do_event() will send the packet
+		 * when we return... - Jean II */
+		break;
 	default:
 		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
 			   irlap_event[event]);
@@ -1645,12 +1650,17 @@
 			 */
 			if (skb->len > self->bytes_left) {
 				skb_queue_head(&self->txq, skb_get(skb));
+
 				/*
 				 *  Switch to NRM_S, this is only possible
 				 *  when we are in secondary mode, since we 
 				 *  must be sure that we don't miss any RR
 				 *  frames
 				 */
+				self->window = self->window_size;
+				self->bytes_left = self->line_capacity;
+				irlap_start_wd_timer(self, self->wd_timeout);
+
 				irlap_next_state(self, LAP_NRM_S);
 
 				return -EPROTO; /* Try again later */
@@ -1688,6 +1698,10 @@
 		irlap_start_wd_timer(self, self->wd_timeout);
 		irlap_next_state(self, LAP_SCLOSE);
 		break;
+	case DATA_REQUEST:
+		/* Nothing to do, irlap_do_event() will send the packet
+		 * when we return... - Jean II */
+		break;
 	default:
 		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", 
 			   irlap_event[event]);
diff -urN linux-2.5.6-pre2/net/irda/irlap_frame.c linux-2.5.6-pre3/net/irda/irlap_frame.c
--- linux-2.5.6-pre2/net/irda/irlap_frame.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre3/net/irda/irlap_frame.c	Wed Mar  6 17:17:56 2002
@@ -768,6 +768,9 @@
 {
 	struct sk_buff *tx_skb;
 
+	/* Stop P timer */
+	del_timer(&self->poll_timer);
+		
 	/* Is this reliable or unreliable data? */
 	if (skb->data[1] == I_FRAME) {
 		
@@ -793,23 +796,15 @@
 		 *  skb, since retransmitted need to set or clear the poll
 		 *  bit depending on when they are sent.  
 		 */
-		/* Stop P timer */
-		del_timer(&self->poll_timer);
-		
 		tx_skb->data[1] |= PF_BIT;
 		
 		self->vs = (self->vs + 1) % 8;
 		self->ack_required = FALSE;
-		self->window = self->window_size;
-
-		irlap_start_final_timer(self, self->final_timeout);
 
 		irlap_send_i_frame(self, tx_skb, CMD_FRAME);
 	} else {
 		IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
 
-		del_timer(&self->poll_timer);
-
 		if (self->ack_required) {
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
 			irlap_send_rr_frame(self, CMD_FRAME);
@@ -818,9 +813,15 @@
 			skb->data[1] |= PF_BIT;
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
 		}
-		self->window = self->window_size;
-		irlap_start_final_timer(self, self->final_timeout);
 	}
+
+	self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	/* We are allowed to transmit a maximum number of bytes again. */
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+
+	irlap_start_final_timer(self, self->final_timeout);
 }
 
 /*
@@ -858,11 +859,8 @@
 		tx_skb->data[1] |= PF_BIT;
 		
 		self->vs = (self->vs + 1) % 8; 
-		self->window = self->window_size;
 		self->ack_required = FALSE;
 		
-		irlap_start_wd_timer(self, self->wd_timeout);
-
 		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
 	} else {
 		if (self->ack_required) {
@@ -873,10 +871,15 @@
 			skb->data[1] |= PF_BIT;
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
 		}
-		self->window = self->window_size;
-
-		irlap_start_wd_timer(self, self->wd_timeout);
 	}
+
+	self->window = self->window_size;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+	/* We are allowed to transmit a maximum number of bytes again. */
+	self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+
+	irlap_start_wd_timer(self, self->wd_timeout);
 }
 
 /*
diff -urN linux-2.5.6-pre2/net/irda/irnet/irnet.h linux-2.5.6-pre3/net/irda/irnet/irnet.h
--- linux-2.5.6-pre2/net/irda/irnet/irnet.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/net/irda/irnet/irnet.h	Wed Mar  6 17:17:56 2002
@@ -206,6 +206,11 @@
  *	  just after clearing it. *blush*.
  *	o Use newly created irttp_listen() to fix potential crash when LAP
  *	  destroyed before irnet module removed.
+ *
+ * v10 - 4.3.2 - Jean II
+ *	o When receiving a disconnect indication, don't reenable the
+ *	  PPP Tx queue, this will trigger a reconnect. Instead, close
+ *	  the channel, which will kill pppd...
  */
 
 /***************************** INCLUDES *****************************/
diff -urN linux-2.5.6-pre2/net/irda/irnet/irnet_irda.c linux-2.5.6-pre3/net/irda/irnet/irnet_irda.c
--- linux-2.5.6-pre2/net/irda/irnet/irnet_irda.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre3/net/irda/irnet/irnet_irda.c	Wed Mar  6 17:17:56 2002
@@ -1122,9 +1122,10 @@
       irttp_close_tsap(self->tsap);
       self->tsap = NULL;
 
-      /* Flush (drain) ppp_generic Tx queue (most often we have blocked it) */
+      /* Cleanup & close the PPP channel, which will kill pppd and the rest */
       if(self->ppp_open)
-	ppp_output_wakeup(&self->chan);
+	ppp_unregister_channel(&self->chan);
+      self->ppp_open = 0;
     }
   /* Cleanup the socket in case we want to reconnect */
   self->stsap_sel = 0;
diff -urN linux-2.5.6-pre2/net/unix/af_unix.c linux-2.5.6-pre3/net/unix/af_unix.c
--- linux-2.5.6-pre2/net/unix/af_unix.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre3/net/unix/af_unix.c	Wed Mar  6 17:17:57 2002
@@ -603,9 +603,7 @@
 	int err = 0;
 	
 	if (sunname->sun_path[0]) {
-		if (path_init(sunname->sun_path, 
-			      LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
-			err = path_walk(sunname->sun_path, &nd);
+		err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
 		if (err)
 			goto fail;
 		err = permission(nd.dentry->d_inode,MAY_WRITE);
@@ -691,8 +689,7 @@
 		 * Get the parent directory, calculate the hash for last
 		 * component.
 		 */
-		if (path_init(sunaddr->sun_path, LOOKUP_PARENT, &nd))
-			err = path_walk(sunaddr->sun_path, &nd);
+		err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
 		if (err)
 			goto out_mknod_parent;
 		/*
diff -urN linux-2.5.6-pre2/net/wanrouter/af_wanpipe.c linux-2.5.6-pre3/net/wanrouter/af_wanpipe.c
--- linux-2.5.6-pre2/net/wanrouter/af_wanpipe.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre3/net/wanrouter/af_wanpipe.c	Wed Mar  6 17:17:57 2002
@@ -110,7 +110,7 @@
  *         passes the packet to the driver. Before each send(), a poll
  *         routine checks the sock resources The maximum value of
  *         packet sent counter is 1, thus if one packet is queued, the
- *         application will block untill that packet is passed to the
+ *         application will block until that packet is passed to the
  *         driver.
  *
  *   RECEIVE:
@@ -121,7 +121,7 @@
  *      return code, the driver knows whether the packet was
  *      sucessfully queued.  If the socket queue is full, 
  *      protocol flow control is used by the driver, if any, 
- *      to slow down the traffic untill the sock queue is free.
+ *      to slow down the traffic until the sock queue is free.
  *
  *      Every time a packet arrives into a socket queue the 
  *      socket wakes up processes which are waiting to receive
@@ -2396,7 +2396,7 @@
 
 
 			/* Check if data buffers are pending for transmission,
-                         * if so, check wheter user wants to wait untill data
+                         * if so, check whether user wants to wait until data
                          * is transmitted, or clear a call and drop packets */
                           
 			if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){
@@ -2432,7 +2432,7 @@
 
 
 			/* Check if data buffers are pending for transmission,
-                         * if so, check wheter user wants to wait untill data
+                         * if so, check whether user wants to wait until data
                          * is transmitted, or reset a call and drop packets */
                           
 			if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){
diff -urN linux-2.5.6-pre2/scripts/tkgen.c linux-2.5.6-pre3/scripts/tkgen.c
--- linux-2.5.6-pre2/scripts/tkgen.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre3/scripts/tkgen.c	Wed Mar  6 17:17:57 2002
@@ -620,11 +620,11 @@
 	case token_int:
 	    if ( cfg->value && *cfg->value == '$' )
 	    {
-		int index = get_varnum( cfg->value+1 );
+		int i = get_varnum( cfg->value+1 );
 		printf( "\n" );
-		if ( ! vartable[index].global_written )
+		if ( ! vartable[i].global_written )
 		{
-		    global( vartable[index].name );
+		    global( vartable[i].name );
 		}
 		printf( "\t" );
 	    }
@@ -989,7 +989,6 @@
 static void end_proc( struct kconfig * scfg, int menu_num )
 {
     struct kconfig * cfg;
-    int i;
 
     printf( "\n\n\n" );
     printf( "\tfocus $w\n" );
@@ -1084,6 +1083,7 @@
 	    {
 		if ( cfg->token == token_tristate )
 		{
+		    int i;
 		    if ( ! vartable[cfg->nameindex].global_written )
 		    {
 			vartable[cfg->nameindex].global_written = 1;
