## Automatically generated incremental diff
## From:   linux-2.4.25-pre7
## To:     linux-2.4.25-pre8
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.4.25-pre7/Documentation/Configure.help linux-2.4.25-pre8/Documentation/Configure.help
--- linux-2.4.25-pre7/Documentation/Configure.help	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/Documentation/Configure.help	2004-01-29 10:58:20.000000000 -0800
@@ -15620,24 +15620,6 @@
   The module will be called catc.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-USB ASIX AX88172 based ethernet device support
-CONFIG_USB_AX8817X
-  Say Y if you want to use one of the following 10/100 USB2 Ethernet
-  devices based on the ASIX AX88172 chip.  Supported devices are:
-    Linksys USB200M
-    Netgear FA120
-    D-Link DUB-E100
-    Hawking UF200
-
-  This driver makes the adapter appear as a normal Ethernet interface,
-  typically on eth0, if it is the only ethernet device, or perhaps on
-  eth1, if you have a PCI or ISA ethernet card installed.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ax8817x.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
 USB Kodak DC-2xx Camera support
 CONFIG_USB_DC2XX
   Say Y here if you want to connect this type of still camera to your
@@ -17674,6 +17656,17 @@
 
   smbmount from samba 2.2.0 or later supports this.
 
+Enable Unix Extensions
+CONFIG_SMB_UNIX
+  Enabling this will make smbfs use the CIFS Unix Extensions if
+  supported by the server. These extensions allows use of unix user
+  ids, permissions, file modes, symlinks, etc that normally do not
+  work on smbfs.
+
+  Samba 3.0 servers supports these extensions.
+
+  If you don't know what all this is about, it is safe to say Y.
+
 Coda file system support (advanced network fs)
 CONFIG_CODA_FS
   Coda is an advanced network file system, similar to NFS in that it
diff -urN linux-2.4.25-pre7/Makefile linux-2.4.25-pre8/Makefile
--- linux-2.4.25-pre7/Makefile	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/Makefile	2004-01-29 10:58:20.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 25
-EXTRAVERSION = -pre7
+EXTRAVERSION = -pre8
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.25-pre7/arch/alpha/config.in linux-2.4.25-pre8/arch/alpha/config.in
--- linux-2.4.25-pre7/arch/alpha/config.in	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/alpha/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -341,7 +341,6 @@
   int '  Maximum IDE interfaces' MAX_HWIFS 4
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/alpha/defconfig linux-2.4.25-pre8/arch/alpha/defconfig
--- linux-2.4.25-pre7/arch/alpha/defconfig	2003-06-13 07:51:29.000000000 -0700
+++ linux-2.4.25-pre8/arch/alpha/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -270,7 +270,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/config.in linux-2.4.25-pre8/arch/arm/config.in
--- linux-2.4.25-pre7/arch/arm/config.in	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/arm/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -585,7 +585,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/a5k linux-2.4.25-pre8/arch/arm/def-configs/a5k
--- linux-2.4.25-pre7/arch/arm/def-configs/a5k	2000-11-27 17:07:59.000000000 -0800
+++ linux-2.4.25-pre8/arch/arm/def-configs/a5k	2004-01-29 10:58:20.000000000 -0800
@@ -287,7 +287,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/accelent_sa linux-2.4.25-pre8/arch/arm/def-configs/accelent_sa
--- linux-2.4.25-pre7/arch/arm/def-configs/accelent_sa	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/accelent_sa	2004-01-29 10:58:20.000000000 -0800
@@ -506,7 +506,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/adsagc linux-2.4.25-pre8/arch/arm/def-configs/adsagc
--- linux-2.4.25-pre7/arch/arm/def-configs/adsagc	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/adsagc	2004-01-29 10:58:20.000000000 -0800
@@ -535,7 +535,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/adsbitsy linux-2.4.25-pre8/arch/arm/def-configs/adsbitsy
--- linux-2.4.25-pre7/arch/arm/def-configs/adsbitsy	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/adsbitsy	2004-01-29 10:58:20.000000000 -0800
@@ -535,7 +535,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/adsbitsyplus linux-2.4.25-pre8/arch/arm/def-configs/adsbitsyplus
--- linux-2.4.25-pre7/arch/arm/def-configs/adsbitsyplus	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/adsbitsyplus	2004-01-29 10:58:20.000000000 -0800
@@ -535,7 +535,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/anakin linux-2.4.25-pre8/arch/arm/def-configs/anakin
--- linux-2.4.25-pre7/arch/arm/def-configs/anakin	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/anakin	2004-01-29 10:58:20.000000000 -0800
@@ -259,7 +259,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/assabet linux-2.4.25-pre8/arch/arm/def-configs/assabet
--- linux-2.4.25-pre7/arch/arm/def-configs/assabet	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/assabet	2004-01-29 10:58:20.000000000 -0800
@@ -493,7 +493,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/at91rm9200dk linux-2.4.25-pre8/arch/arm/def-configs/at91rm9200dk
--- linux-2.4.25-pre7/arch/arm/def-configs/at91rm9200dk	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/at91rm9200dk	2004-01-29 10:58:20.000000000 -0800
@@ -426,7 +426,6 @@
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/badge4 linux-2.4.25-pre8/arch/arm/def-configs/badge4
--- linux-2.4.25-pre7/arch/arm/def-configs/badge4	2003-06-13 07:51:29.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/badge4	2004-01-29 10:58:20.000000000 -0800
@@ -527,7 +527,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/brutus linux-2.4.25-pre8/arch/arm/def-configs/brutus
--- linux-2.4.25-pre7/arch/arm/def-configs/brutus	2001-08-12 11:13:59.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/brutus	2004-01-29 10:58:20.000000000 -0800
@@ -123,7 +123,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/cep linux-2.4.25-pre8/arch/arm/def-configs/cep
--- linux-2.4.25-pre7/arch/arm/def-configs/cep	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/cep	2004-01-29 10:58:20.000000000 -0800
@@ -303,7 +303,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/cerfcube linux-2.4.25-pre8/arch/arm/def-configs/cerfcube
--- linux-2.4.25-pre7/arch/arm/def-configs/cerfcube	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/cerfcube	2004-01-29 10:58:20.000000000 -0800
@@ -474,7 +474,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/cerfpda linux-2.4.25-pre8/arch/arm/def-configs/cerfpda
--- linux-2.4.25-pre7/arch/arm/def-configs/cerfpda	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/cerfpda	2004-01-29 10:58:20.000000000 -0800
@@ -504,7 +504,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/cerfpod linux-2.4.25-pre8/arch/arm/def-configs/cerfpod
--- linux-2.4.25-pre7/arch/arm/def-configs/cerfpod	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/cerfpod	2004-01-29 10:58:20.000000000 -0800
@@ -475,7 +475,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/clps7500 linux-2.4.25-pre8/arch/arm/def-configs/clps7500
--- linux-2.4.25-pre7/arch/arm/def-configs/clps7500	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/clps7500	2004-01-29 10:58:20.000000000 -0800
@@ -298,7 +298,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/ebsa110 linux-2.4.25-pre8/arch/arm/def-configs/ebsa110
--- linux-2.4.25-pre7/arch/arm/def-configs/ebsa110	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/ebsa110	2004-01-29 10:58:20.000000000 -0800
@@ -387,7 +387,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/edb7211 linux-2.4.25-pre8/arch/arm/def-configs/edb7211
--- linux-2.4.25-pre7/arch/arm/def-configs/edb7211	2001-10-25 13:53:44.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/edb7211	2004-01-29 10:58:20.000000000 -0800
@@ -225,7 +225,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/epxa10db linux-2.4.25-pre8/arch/arm/def-configs/epxa10db
--- linux-2.4.25-pre7/arch/arm/def-configs/epxa10db	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/epxa10db	2004-01-29 10:58:20.000000000 -0800
@@ -422,7 +422,6 @@
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/epxa1db linux-2.4.25-pre8/arch/arm/def-configs/epxa1db
--- linux-2.4.25-pre7/arch/arm/def-configs/epxa1db	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/epxa1db	2004-01-29 10:58:20.000000000 -0800
@@ -404,7 +404,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/flexanet linux-2.4.25-pre8/arch/arm/def-configs/flexanet
--- linux-2.4.25-pre7/arch/arm/def-configs/flexanet	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/flexanet	2004-01-29 10:58:20.000000000 -0800
@@ -479,7 +479,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/footbridge linux-2.4.25-pre8/arch/arm/def-configs/footbridge
--- linux-2.4.25-pre7/arch/arm/def-configs/footbridge	2003-06-13 07:51:29.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/footbridge	2004-01-29 10:58:20.000000000 -0800
@@ -437,7 +437,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/fortunet linux-2.4.25-pre8/arch/arm/def-configs/fortunet
--- linux-2.4.25-pre7/arch/arm/def-configs/fortunet	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/fortunet	2004-01-29 10:58:20.000000000 -0800
@@ -295,7 +295,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/freebird linux-2.4.25-pre8/arch/arm/def-configs/freebird
--- linux-2.4.25-pre7/arch/arm/def-configs/freebird	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/freebird	2004-01-29 10:58:20.000000000 -0800
@@ -384,7 +384,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/freebird_new linux-2.4.25-pre8/arch/arm/def-configs/freebird_new
--- linux-2.4.25-pre7/arch/arm/def-configs/freebird_new	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/freebird_new	2004-01-29 10:58:20.000000000 -0800
@@ -398,7 +398,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/frodo linux-2.4.25-pre8/arch/arm/def-configs/frodo
--- linux-2.4.25-pre7/arch/arm/def-configs/frodo	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/frodo	2004-01-29 10:58:20.000000000 -0800
@@ -462,7 +462,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/graphicsclient linux-2.4.25-pre8/arch/arm/def-configs/graphicsclient
--- linux-2.4.25-pre7/arch/arm/def-configs/graphicsclient	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/graphicsclient	2004-01-29 10:58:20.000000000 -0800
@@ -533,7 +533,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/graphicsmaster linux-2.4.25-pre8/arch/arm/def-configs/graphicsmaster
--- linux-2.4.25-pre7/arch/arm/def-configs/graphicsmaster	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/graphicsmaster	2004-01-29 10:58:20.000000000 -0800
@@ -535,7 +535,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/h3600 linux-2.4.25-pre8/arch/arm/def-configs/h3600
--- linux-2.4.25-pre7/arch/arm/def-configs/h3600	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/h3600	2004-01-29 10:58:20.000000000 -0800
@@ -482,7 +482,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/huw_webpanel linux-2.4.25-pre8/arch/arm/def-configs/huw_webpanel
--- linux-2.4.25-pre7/arch/arm/def-configs/huw_webpanel	2001-08-12 11:13:59.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/huw_webpanel	2004-01-29 10:58:20.000000000 -0800
@@ -227,7 +227,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/integrator linux-2.4.25-pre8/arch/arm/def-configs/integrator
--- linux-2.4.25-pre7/arch/arm/def-configs/integrator	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/integrator	2004-01-29 10:58:20.000000000 -0800
@@ -410,7 +410,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/jornada720 linux-2.4.25-pre8/arch/arm/def-configs/jornada720
--- linux-2.4.25-pre7/arch/arm/def-configs/jornada720	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/jornada720	2004-01-29 10:58:20.000000000 -0800
@@ -482,7 +482,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/lart linux-2.4.25-pre8/arch/arm/def-configs/lart
--- linux-2.4.25-pre7/arch/arm/def-configs/lart	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/lart	2004-01-29 10:58:20.000000000 -0800
@@ -484,7 +484,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/lusl7200 linux-2.4.25-pre8/arch/arm/def-configs/lusl7200
--- linux-2.4.25-pre7/arch/arm/def-configs/lusl7200	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/lusl7200	2004-01-29 10:58:20.000000000 -0800
@@ -161,7 +161,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/nanoengine linux-2.4.25-pre8/arch/arm/def-configs/nanoengine
--- linux-2.4.25-pre7/arch/arm/def-configs/nanoengine	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/nanoengine	2004-01-29 10:58:20.000000000 -0800
@@ -413,7 +413,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/neponset linux-2.4.25-pre8/arch/arm/def-configs/neponset
--- linux-2.4.25-pre7/arch/arm/def-configs/neponset	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/neponset	2004-01-29 10:58:20.000000000 -0800
@@ -455,7 +455,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/omaha linux-2.4.25-pre8/arch/arm/def-configs/omaha
--- linux-2.4.25-pre7/arch/arm/def-configs/omaha	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/omaha	2004-01-29 10:58:20.000000000 -0800
@@ -358,7 +358,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/omnimeter linux-2.4.25-pre8/arch/arm/def-configs/omnimeter
--- linux-2.4.25-pre7/arch/arm/def-configs/omnimeter	2001-08-12 11:13:59.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/omnimeter	2004-01-29 10:58:20.000000000 -0800
@@ -314,7 +314,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pangolin linux-2.4.25-pre8/arch/arm/def-configs/pangolin
--- linux-2.4.25-pre7/arch/arm/def-configs/pangolin	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pangolin	2004-01-29 10:58:20.000000000 -0800
@@ -434,7 +434,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pfs168_mqtft linux-2.4.25-pre8/arch/arm/def-configs/pfs168_mqtft
--- linux-2.4.25-pre7/arch/arm/def-configs/pfs168_mqtft	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pfs168_mqtft	2004-01-29 10:58:20.000000000 -0800
@@ -458,7 +458,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pfs168_mqvga linux-2.4.25-pre8/arch/arm/def-configs/pfs168_mqvga
--- linux-2.4.25-pre7/arch/arm/def-configs/pfs168_mqvga	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pfs168_mqvga	2004-01-29 10:58:20.000000000 -0800
@@ -458,7 +458,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pfs168_sastn linux-2.4.25-pre8/arch/arm/def-configs/pfs168_sastn
--- linux-2.4.25-pre7/arch/arm/def-configs/pfs168_sastn	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pfs168_sastn	2004-01-29 10:58:20.000000000 -0800
@@ -459,7 +459,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pfs168_satft linux-2.4.25-pre8/arch/arm/def-configs/pfs168_satft
--- linux-2.4.25-pre7/arch/arm/def-configs/pfs168_satft	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pfs168_satft	2004-01-29 10:58:20.000000000 -0800
@@ -458,7 +458,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/pleb linux-2.4.25-pre8/arch/arm/def-configs/pleb
--- linux-2.4.25-pre7/arch/arm/def-configs/pleb	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/pleb	2004-01-29 10:58:20.000000000 -0800
@@ -331,7 +331,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/riscstation linux-2.4.25-pre8/arch/arm/def-configs/riscstation
--- linux-2.4.25-pre7/arch/arm/def-configs/riscstation	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/riscstation	2004-01-29 10:58:20.000000000 -0800
@@ -372,7 +372,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/rpc linux-2.4.25-pre8/arch/arm/def-configs/rpc
--- linux-2.4.25-pre7/arch/arm/def-configs/rpc	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/rpc	2004-01-29 10:58:20.000000000 -0800
@@ -412,7 +412,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/shannon linux-2.4.25-pre8/arch/arm/def-configs/shannon
--- linux-2.4.25-pre7/arch/arm/def-configs/shannon	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/shannon	2004-01-29 10:58:20.000000000 -0800
@@ -387,7 +387,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/shark linux-2.4.25-pre8/arch/arm/def-configs/shark
--- linux-2.4.25-pre7/arch/arm/def-configs/shark	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/shark	2004-01-29 10:58:20.000000000 -0800
@@ -391,7 +391,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/def-configs/system3 linux-2.4.25-pre8/arch/arm/def-configs/system3
--- linux-2.4.25-pre7/arch/arm/def-configs/system3	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/def-configs/system3	2004-01-29 10:58:20.000000000 -0800
@@ -496,7 +496,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/arm/defconfig linux-2.4.25-pre8/arch/arm/defconfig
--- linux-2.4.25-pre7/arch/arm/defconfig	2001-05-19 17:43:05.000000000 -0700
+++ linux-2.4.25-pre8/arch/arm/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -303,7 +303,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/cris/config.in linux-2.4.25-pre8/arch/cris/config.in
--- linux-2.4.25-pre7/arch/cris/config.in	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/cris/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -184,7 +184,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/cris/defconfig linux-2.4.25-pre8/arch/cris/defconfig
--- linux-2.4.25-pre7/arch/cris/defconfig	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.25-pre8/arch/cris/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -282,7 +282,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/i386/config.in linux-2.4.25-pre8/arch/i386/config.in
--- linux-2.4.25-pre7/arch/i386/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/i386/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -371,7 +371,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
    source drivers/ide/Config.in
 else
-   define_bool CONFIG_BLK_DEV_IDE_MODES n
    define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/i386/defconfig linux-2.4.25-pre8/arch/i386/defconfig
--- linux-2.4.25-pre7/arch/i386/defconfig	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/i386/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -288,7 +288,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/i386/kernel/setup.c linux-2.4.25-pre8/arch/i386/kernel/setup.c
--- linux-2.4.25-pre7/arch/i386/kernel/setup.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/i386/kernel/setup.c	2004-01-29 10:58:20.000000000 -0800
@@ -3191,7 +3191,7 @@
 	set_tss_desc(nr,t);
 	gdt_table[__TSS(nr)].b &= 0xfffffdff;
 	load_TR(nr);
-	load_LDT(&init_mm);
+	load_LDT(&init_mm.context);
 
 	/*
 	 * Clear all 6 debug registers:
diff -urN linux-2.4.25-pre7/arch/i386/kernel/time.c linux-2.4.25-pre8/arch/i386/kernel/time.c
--- linux-2.4.25-pre7/arch/i386/kernel/time.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/i386/kernel/time.c	2004-01-29 10:58:20.000000000 -0800
@@ -432,7 +432,6 @@
 
 const int use_cyclone = 0;
 static void mark_timeoffset_cyclone(void) {}
-static unsigned long do_gettimeoffset_cyclone(void) {return 0;}
 static void init_cyclone_clock(void) {}
 void __cyclone_delay(unsigned long loops) {}
 #endif /* CONFIG_X86_SUMMIT */
diff -urN linux-2.4.25-pre7/arch/ia64/config.in linux-2.4.25-pre8/arch/ia64/config.in
--- linux-2.4.25-pre7/arch/ia64/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -171,7 +171,6 @@
   if [ "$CONFIG_IDE" != "n" ]; then
     source drivers/ide/Config.in
   else
-    define_bool CONFIG_BLK_DEV_IDE_MODES n
     define_bool CONFIG_BLK_DEV_HD n
   fi
   endmenu
diff -urN linux-2.4.25-pre7/arch/ia64/configs/dig linux-2.4.25-pre8/arch/ia64/configs/dig
--- linux-2.4.25-pre7/arch/ia64/configs/dig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/configs/dig	2004-01-29 10:58:20.000000000 -0800
@@ -290,7 +290,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ia64/configs/generic linux-2.4.25-pre8/arch/ia64/configs/generic
--- linux-2.4.25-pre7/arch/ia64/configs/generic	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/configs/generic	2004-01-29 10:58:20.000000000 -0800
@@ -291,7 +291,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ia64/configs/numa linux-2.4.25-pre8/arch/ia64/configs/numa
--- linux-2.4.25-pre7/arch/ia64/configs/numa	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/configs/numa	2004-01-29 10:58:20.000000000 -0800
@@ -293,7 +293,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ia64/configs/zx1 linux-2.4.25-pre8/arch/ia64/configs/zx1
--- linux-2.4.25-pre7/arch/ia64/configs/zx1	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/configs/zx1	2004-01-29 10:58:20.000000000 -0800
@@ -291,7 +291,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ia64/defconfig linux-2.4.25-pre8/arch/ia64/defconfig
--- linux-2.4.25-pre7/arch/ia64/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ia64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -291,7 +291,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/m68k/config.in linux-2.4.25-pre8/arch/m68k/config.in
--- linux-2.4.25-pre7/arch/m68k/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/m68k/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -185,7 +185,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/m68k/defconfig linux-2.4.25-pre8/arch/m68k/defconfig
--- linux-2.4.25-pre7/arch/m68k/defconfig	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/m68k/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -124,7 +124,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/config-shared.in linux-2.4.25-pre8/arch/mips/config-shared.in
--- linux-2.4.25-pre7/arch/mips/config-shared.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/config-shared.in	2004-01-29 10:58:20.000000000 -0800
@@ -995,7 +995,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
    source drivers/ide/Config.in
 else
-   define_bool CONFIG_BLK_DEV_IDE_MODES n
    define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/mips/defconfig linux-2.4.25-pre8/arch/mips/defconfig
--- linux-2.4.25-pre7/arch/mips/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -267,7 +267,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-atlas linux-2.4.25-pre8/arch/mips/defconfig-atlas
--- linux-2.4.25-pre7/arch/mips/defconfig-atlas	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-atlas	2004-01-29 10:58:20.000000000 -0800
@@ -265,7 +265,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-bosporus linux-2.4.25-pre8/arch/mips/defconfig-bosporus
--- linux-2.4.25-pre7/arch/mips/defconfig-bosporus	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-bosporus	2004-01-29 10:58:20.000000000 -0800
@@ -401,7 +401,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-capcella linux-2.4.25-pre8/arch/mips/defconfig-capcella
--- linux-2.4.25-pre7/arch/mips/defconfig-capcella	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-capcella	2004-01-29 10:58:20.000000000 -0800
@@ -291,7 +291,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-cobalt linux-2.4.25-pre8/arch/mips/defconfig-cobalt
--- linux-2.4.25-pre7/arch/mips/defconfig-cobalt	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-cobalt	2004-01-29 10:58:20.000000000 -0800
@@ -320,7 +320,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-csb250 linux-2.4.25-pre8/arch/mips/defconfig-csb250
--- linux-2.4.25-pre7/arch/mips/defconfig-csb250	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-csb250	2004-01-29 10:58:20.000000000 -0800
@@ -367,7 +367,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-db1000 linux-2.4.25-pre8/arch/mips/defconfig-db1000
--- linux-2.4.25-pre7/arch/mips/defconfig-db1000	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-db1000	2004-01-29 10:58:20.000000000 -0800
@@ -403,7 +403,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-db1100 linux-2.4.25-pre8/arch/mips/defconfig-db1100
--- linux-2.4.25-pre7/arch/mips/defconfig-db1100	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-db1100	2004-01-29 10:58:20.000000000 -0800
@@ -402,7 +402,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-db1500 linux-2.4.25-pre8/arch/mips/defconfig-db1500
--- linux-2.4.25-pre7/arch/mips/defconfig-db1500	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-db1500	2004-01-29 10:58:20.000000000 -0800
@@ -366,7 +366,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ddb5476 linux-2.4.25-pre8/arch/mips/defconfig-ddb5476
--- linux-2.4.25-pre7/arch/mips/defconfig-ddb5476	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ddb5476	2004-01-29 10:58:20.000000000 -0800
@@ -325,7 +325,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ddb5477 linux-2.4.25-pre8/arch/mips/defconfig-ddb5477
--- linux-2.4.25-pre7/arch/mips/defconfig-ddb5477	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ddb5477	2004-01-29 10:58:20.000000000 -0800
@@ -258,7 +258,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-decstation linux-2.4.25-pre8/arch/mips/defconfig-decstation
--- linux-2.4.25-pre7/arch/mips/defconfig-decstation	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-decstation	2004-01-29 10:58:20.000000000 -0800
@@ -254,7 +254,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-e55 linux-2.4.25-pre8/arch/mips/defconfig-e55
--- linux-2.4.25-pre7/arch/mips/defconfig-e55	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-e55	2004-01-29 10:58:20.000000000 -0800
@@ -284,7 +284,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-eagle linux-2.4.25-pre8/arch/mips/defconfig-eagle
--- linux-2.4.25-pre7/arch/mips/defconfig-eagle	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-eagle	2004-01-29 10:58:20.000000000 -0800
@@ -385,7 +385,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ev64120 linux-2.4.25-pre8/arch/mips/defconfig-ev64120
--- linux-2.4.25-pre7/arch/mips/defconfig-ev64120	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ev64120	2004-01-29 10:58:20.000000000 -0800
@@ -260,7 +260,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ev96100 linux-2.4.25-pre8/arch/mips/defconfig-ev96100
--- linux-2.4.25-pre7/arch/mips/defconfig-ev96100	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ev96100	2004-01-29 10:58:20.000000000 -0800
@@ -263,7 +263,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-hp-lj linux-2.4.25-pre8/arch/mips/defconfig-hp-lj
--- linux-2.4.25-pre7/arch/mips/defconfig-hp-lj	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-hp-lj	2004-01-29 10:58:20.000000000 -0800
@@ -402,7 +402,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-hydrogen3 linux-2.4.25-pre8/arch/mips/defconfig-hydrogen3
--- linux-2.4.25-pre7/arch/mips/defconfig-hydrogen3	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-hydrogen3	2004-01-29 10:58:20.000000000 -0800
@@ -400,7 +400,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ip22 linux-2.4.25-pre8/arch/mips/defconfig-ip22
--- linux-2.4.25-pre7/arch/mips/defconfig-ip22	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ip22	2004-01-29 10:58:20.000000000 -0800
@@ -267,7 +267,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-it8172 linux-2.4.25-pre8/arch/mips/defconfig-it8172
--- linux-2.4.25-pre7/arch/mips/defconfig-it8172	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-it8172	2004-01-29 10:58:20.000000000 -0800
@@ -404,7 +404,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ivr linux-2.4.25-pre8/arch/mips/defconfig-ivr
--- linux-2.4.25-pre7/arch/mips/defconfig-ivr	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ivr	2004-01-29 10:58:20.000000000 -0800
@@ -327,7 +327,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-jmr3927 linux-2.4.25-pre8/arch/mips/defconfig-jmr3927
--- linux-2.4.25-pre7/arch/mips/defconfig-jmr3927	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-jmr3927	2004-01-29 10:58:20.000000000 -0800
@@ -257,7 +257,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-lasat linux-2.4.25-pre8/arch/mips/defconfig-lasat
--- linux-2.4.25-pre7/arch/mips/defconfig-lasat	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-lasat	2004-01-29 10:58:20.000000000 -0800
@@ -399,7 +399,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-malta linux-2.4.25-pre8/arch/mips/defconfig-malta
--- linux-2.4.25-pre7/arch/mips/defconfig-malta	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-malta	2004-01-29 10:58:20.000000000 -0800
@@ -267,7 +267,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-mirage linux-2.4.25-pre8/arch/mips/defconfig-mirage
--- linux-2.4.25-pre7/arch/mips/defconfig-mirage	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-mirage	2004-01-29 10:58:20.000000000 -0800
@@ -290,7 +290,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-mpc30x linux-2.4.25-pre8/arch/mips/defconfig-mpc30x
--- linux-2.4.25-pre7/arch/mips/defconfig-mpc30x	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-mpc30x	2004-01-29 10:58:20.000000000 -0800
@@ -261,7 +261,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-mtx-1 linux-2.4.25-pre8/arch/mips/defconfig-mtx-1
--- linux-2.4.25-pre7/arch/mips/defconfig-mtx-1	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-mtx-1	2004-01-29 10:58:20.000000000 -0800
@@ -425,7 +425,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-nino linux-2.4.25-pre8/arch/mips/defconfig-nino
--- linux-2.4.25-pre7/arch/mips/defconfig-nino	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-nino	2004-01-29 10:58:20.000000000 -0800
@@ -258,7 +258,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ocelot linux-2.4.25-pre8/arch/mips/defconfig-ocelot
--- linux-2.4.25-pre7/arch/mips/defconfig-ocelot	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ocelot	2004-01-29 10:58:20.000000000 -0800
@@ -336,7 +336,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-osprey linux-2.4.25-pre8/arch/mips/defconfig-osprey
--- linux-2.4.25-pre7/arch/mips/defconfig-osprey	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-osprey	2004-01-29 10:58:20.000000000 -0800
@@ -257,7 +257,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-pb1000 linux-2.4.25-pre8/arch/mips/defconfig-pb1000
--- linux-2.4.25-pre7/arch/mips/defconfig-pb1000	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-pb1000	2004-01-29 10:58:20.000000000 -0800
@@ -385,7 +385,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-pb1100 linux-2.4.25-pre8/arch/mips/defconfig-pb1100
--- linux-2.4.25-pre7/arch/mips/defconfig-pb1100	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-pb1100	2004-01-29 10:58:20.000000000 -0800
@@ -386,7 +386,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-pb1500 linux-2.4.25-pre8/arch/mips/defconfig-pb1500
--- linux-2.4.25-pre7/arch/mips/defconfig-pb1500	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-pb1500	2004-01-29 10:58:20.000000000 -0800
@@ -439,7 +439,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-pb1550 linux-2.4.25-pre8/arch/mips/defconfig-pb1550
--- linux-2.4.25-pre7/arch/mips/defconfig-pb1550	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-pb1550	2004-01-29 10:58:20.000000000 -0800
@@ -350,7 +350,6 @@
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_PDC202XX=y
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-rbtx4927 linux-2.4.25-pre8/arch/mips/defconfig-rbtx4927
--- linux-2.4.25-pre7/arch/mips/defconfig-rbtx4927	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-rbtx4927	2004-01-29 10:58:20.000000000 -0800
@@ -255,7 +255,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-rm200 linux-2.4.25-pre8/arch/mips/defconfig-rm200
--- linux-2.4.25-pre7/arch/mips/defconfig-rm200	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-rm200	2004-01-29 10:58:20.000000000 -0800
@@ -259,7 +259,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-sb1250-swarm linux-2.4.25-pre8/arch/mips/defconfig-sb1250-swarm
--- linux-2.4.25-pre7/arch/mips/defconfig-sb1250-swarm	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-sb1250-swarm	2004-01-29 10:58:20.000000000 -0800
@@ -315,7 +315,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-sead linux-2.4.25-pre8/arch/mips/defconfig-sead
--- linux-2.4.25-pre7/arch/mips/defconfig-sead	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-sead	2004-01-29 10:58:20.000000000 -0800
@@ -200,7 +200,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-tb0226 linux-2.4.25-pre8/arch/mips/defconfig-tb0226
--- linux-2.4.25-pre7/arch/mips/defconfig-tb0226	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-tb0226	2004-01-29 10:58:20.000000000 -0800
@@ -260,7 +260,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-tb0229 linux-2.4.25-pre8/arch/mips/defconfig-tb0229
--- linux-2.4.25-pre7/arch/mips/defconfig-tb0229	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-tb0229	2004-01-29 10:58:20.000000000 -0800
@@ -262,7 +262,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-ti1500 linux-2.4.25-pre8/arch/mips/defconfig-ti1500
--- linux-2.4.25-pre7/arch/mips/defconfig-ti1500	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-ti1500	2004-01-29 10:58:20.000000000 -0800
@@ -400,7 +400,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-workpad linux-2.4.25-pre8/arch/mips/defconfig-workpad
--- linux-2.4.25-pre7/arch/mips/defconfig-workpad	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-workpad	2004-01-29 10:58:20.000000000 -0800
@@ -284,7 +284,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-xxs1500 linux-2.4.25-pre8/arch/mips/defconfig-xxs1500
--- linux-2.4.25-pre7/arch/mips/defconfig-xxs1500	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-xxs1500	2004-01-29 10:58:20.000000000 -0800
@@ -437,7 +437,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/mips/defconfig-yosemite linux-2.4.25-pre8/arch/mips/defconfig-yosemite
--- linux-2.4.25-pre7/arch/mips/defconfig-yosemite	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips/defconfig-yosemite	2004-01-29 10:58:20.000000000 -0800
@@ -256,7 +256,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig linux-2.4.25-pre8/arch/mips64/defconfig
--- linux-2.4.25-pre7/arch/mips64/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -247,7 +247,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-atlas linux-2.4.25-pre8/arch/mips64/defconfig-atlas
--- linux-2.4.25-pre7/arch/mips64/defconfig-atlas	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-atlas	2004-01-29 10:58:20.000000000 -0800
@@ -262,7 +262,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-decstation linux-2.4.25-pre8/arch/mips64/defconfig-decstation
--- linux-2.4.25-pre7/arch/mips64/defconfig-decstation	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-decstation	2004-01-29 10:58:20.000000000 -0800
@@ -255,7 +255,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-ip22 linux-2.4.25-pre8/arch/mips64/defconfig-ip22
--- linux-2.4.25-pre7/arch/mips64/defconfig-ip22	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-ip22	2004-01-29 10:58:20.000000000 -0800
@@ -267,7 +267,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-ip27 linux-2.4.25-pre8/arch/mips64/defconfig-ip27
--- linux-2.4.25-pre7/arch/mips64/defconfig-ip27	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-ip27	2004-01-29 10:58:20.000000000 -0800
@@ -247,7 +247,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-jaguar linux-2.4.25-pre8/arch/mips64/defconfig-jaguar
--- linux-2.4.25-pre7/arch/mips64/defconfig-jaguar	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-jaguar	2004-01-29 10:58:20.000000000 -0800
@@ -256,7 +256,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-malta linux-2.4.25-pre8/arch/mips64/defconfig-malta
--- linux-2.4.25-pre7/arch/mips64/defconfig-malta	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-malta	2004-01-29 10:58:20.000000000 -0800
@@ -265,7 +265,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-ocelotc linux-2.4.25-pre8/arch/mips64/defconfig-ocelotc
--- linux-2.4.25-pre7/arch/mips64/defconfig-ocelotc	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-ocelotc	2004-01-29 10:58:20.000000000 -0800
@@ -261,7 +261,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-sb1250-swarm linux-2.4.25-pre8/arch/mips64/defconfig-sb1250-swarm
--- linux-2.4.25-pre7/arch/mips64/defconfig-sb1250-swarm	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-sb1250-swarm	2004-01-29 10:58:20.000000000 -0800
@@ -284,7 +284,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/mips64/defconfig-sead linux-2.4.25-pre8/arch/mips64/defconfig-sead
--- linux-2.4.25-pre7/arch/mips64/defconfig-sead	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/mips64/defconfig-sead	2004-01-29 10:58:20.000000000 -0800
@@ -198,7 +198,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/parisc/config.in linux-2.4.25-pre8/arch/parisc/config.in
--- linux-2.4.25-pre7/arch/parisc/config.in	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/parisc/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -116,7 +116,6 @@
     if [ "$CONFIG_IDE" != "n" ]; then
       source drivers/ide/Config.in
     else
-      define_bool CONFIG_BLK_DEV_IDE_MODES n
       define_bool CONFIG_BLK_DEV_HD n
     fi
     endmenu
diff -urN linux-2.4.25-pre7/arch/parisc/defconfig linux-2.4.25-pre8/arch/parisc/defconfig
--- linux-2.4.25-pre7/arch/parisc/defconfig	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.25-pre8/arch/parisc/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -245,7 +245,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/config.in linux-2.4.25-pre8/arch/ppc/config.in
--- linux-2.4.25-pre7/arch/ppc/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -445,7 +445,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/ppc/configs/IVMS8_defconfig linux-2.4.25-pre8/arch/ppc/configs/IVMS8_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/IVMS8_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/IVMS8_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -215,7 +215,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/SM850_defconfig linux-2.4.25-pre8/arch/ppc/configs/SM850_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/SM850_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/SM850_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -182,7 +182,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/SPD823TS_defconfig linux-2.4.25-pre8/arch/ppc/configs/SPD823TS_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/SPD823TS_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/SPD823TS_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -181,7 +181,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/TQM823L_defconfig linux-2.4.25-pre8/arch/ppc/configs/TQM823L_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/TQM823L_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/TQM823L_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -182,7 +182,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/TQM850L_defconfig linux-2.4.25-pre8/arch/ppc/configs/TQM850L_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/TQM850L_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/TQM850L_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -182,7 +182,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/TQM860L_defconfig linux-2.4.25-pre8/arch/ppc/configs/TQM860L_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/TQM860L_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/TQM860L_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -216,7 +216,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/apus_defconfig linux-2.4.25-pre8/arch/ppc/configs/apus_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/apus_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/apus_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -291,7 +291,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/briq_defconfig linux-2.4.25-pre8/arch/ppc/configs/briq_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/briq_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/briq_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -301,7 +301,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/bseip_defconfig linux-2.4.25-pre8/arch/ppc/configs/bseip_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/bseip_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/bseip_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -181,7 +181,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/common_defconfig linux-2.4.25-pre8/arch/ppc/configs/common_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/common_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/common_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -309,7 +309,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/cpci405_defconfig linux-2.4.25-pre8/arch/ppc/configs/cpci405_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/cpci405_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/cpci405_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -259,7 +259,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/ebony_defconfig linux-2.4.25-pre8/arch/ppc/configs/ebony_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/ebony_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/ebony_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -183,7 +183,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/est8260_defconfig linux-2.4.25-pre8/arch/ppc/configs/est8260_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/est8260_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/est8260_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -164,7 +164,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/gemini_defconfig linux-2.4.25-pre8/arch/ppc/configs/gemini_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/gemini_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/gemini_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -183,7 +183,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/ibmchrp_defconfig linux-2.4.25-pre8/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/ibmchrp_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/ibmchrp_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -227,7 +227,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/mbx_defconfig linux-2.4.25-pre8/arch/ppc/configs/mbx_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/mbx_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/mbx_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -178,7 +178,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/oak_defconfig linux-2.4.25-pre8/arch/ppc/configs/oak_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/oak_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/oak_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -165,7 +165,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/ocotea_defconfig linux-2.4.25-pre8/arch/ppc/configs/ocotea_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/ocotea_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/ocotea_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -184,7 +184,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/pal4_defconfig linux-2.4.25-pre8/arch/ppc/configs/pal4_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/pal4_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/pal4_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -226,7 +226,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/pmac_defconfig linux-2.4.25-pre8/arch/ppc/configs/pmac_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/pmac_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/pmac_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -313,7 +313,6 @@
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_PDC202XX=y
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/power3_defconfig linux-2.4.25-pre8/arch/ppc/configs/power3_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/power3_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/power3_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -181,7 +181,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/pplus_defconfig linux-2.4.25-pre8/arch/ppc/configs/pplus_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/pplus_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/pplus_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -300,7 +300,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/prpmc750_defconfig linux-2.4.25-pre8/arch/ppc/configs/prpmc750_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/prpmc750_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/prpmc750_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -245,7 +245,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/rpxcllf_defconfig linux-2.4.25-pre8/arch/ppc/configs/rpxcllf_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/rpxcllf_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/rpxcllf_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -191,7 +191,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/rpxlite_defconfig linux-2.4.25-pre8/arch/ppc/configs/rpxlite_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/rpxlite_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/rpxlite_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -191,7 +191,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/sandpoint_defconfig linux-2.4.25-pre8/arch/ppc/configs/sandpoint_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/sandpoint_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/sandpoint_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -262,7 +262,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc/configs/spruce_defconfig linux-2.4.25-pre8/arch/ppc/configs/spruce_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/spruce_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/spruce_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -173,7 +173,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/configs/walnut_defconfig linux-2.4.25-pre8/arch/ppc/configs/walnut_defconfig
--- linux-2.4.25-pre7/arch/ppc/configs/walnut_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/configs/walnut_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -173,7 +173,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc/defconfig linux-2.4.25-pre8/arch/ppc/defconfig
--- linux-2.4.25-pre7/arch/ppc/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -309,7 +309,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc64/config.in linux-2.4.25-pre8/arch/ppc64/config.in
--- linux-2.4.25-pre7/arch/ppc64/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc64/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -122,7 +122,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/ppc64/configs/iSeries_devfs_defconfig linux-2.4.25-pre8/arch/ppc64/configs/iSeries_devfs_defconfig
--- linux-2.4.25-pre7/arch/ppc64/configs/iSeries_devfs_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc64/configs/iSeries_devfs_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -160,7 +160,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linux-2.4.25-pre8/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig
--- linux-2.4.25-pre7/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -168,7 +168,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/ppc64/configs/pSeries_defconfig linux-2.4.25-pre8/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.25-pre7/arch/ppc64/configs/pSeries_defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc64/configs/pSeries_defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -235,7 +235,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/ppc64/defconfig linux-2.4.25-pre8/arch/ppc64/defconfig
--- linux-2.4.25-pre7/arch/ppc64/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/ppc64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -235,7 +235,6 @@
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -urN linux-2.4.25-pre7/arch/sh/config.in linux-2.4.25-pre8/arch/sh/config.in
--- linux-2.4.25-pre7/arch/sh/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sh/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -309,7 +309,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/sh/defconfig linux-2.4.25-pre8/arch/sh/defconfig
--- linux-2.4.25-pre7/arch/sh/defconfig	2001-10-15 13:36:48.000000000 -0700
+++ linux-2.4.25-pre8/arch/sh/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -121,7 +121,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
diff -urN linux-2.4.25-pre7/arch/sh64/config.in linux-2.4.25-pre8/arch/sh64/config.in
--- linux-2.4.25-pre7/arch/sh64/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sh64/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -177,7 +177,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-   define_bool CONFIG_BLK_DEV_IDE_MODES n
    define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/sh64/defconfig linux-2.4.25-pre8/arch/sh64/defconfig
--- linux-2.4.25-pre7/arch/sh64/defconfig	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/sh64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -171,7 +171,6 @@
 # ATA/IDE/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/sparc/config.in linux-2.4.25-pre8/arch/sparc/config.in
--- linux-2.4.25-pre7/arch/sparc/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sparc/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -127,14 +127,12 @@
   if [ "$CONFIG_IDE" != "n" ]; then
     source drivers/ide/Config.in
   else
-    define_bool CONFIG_BLK_DEV_IDE_MODES n
     define_bool CONFIG_BLK_DEV_HD n
   fi
   endmenu
 else
 
   define_bool CONFIG_IDE n
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 
diff -urN linux-2.4.25-pre7/arch/sparc/defconfig linux-2.4.25-pre8/arch/sparc/defconfig
--- linux-2.4.25-pre7/arch/sparc/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sparc/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -201,7 +201,6 @@
 #
 CONFIG_NET_PKTGEN=m
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -urN linux-2.4.25-pre7/arch/sparc64/config.in linux-2.4.25-pre8/arch/sparc64/config.in
--- linux-2.4.25-pre7/arch/sparc64/config.in	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sparc64/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -132,7 +132,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
@@ -306,6 +305,7 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
    bool '  D-cache flush debugging' CONFIG_DEBUG_DCFLUSH
+   bool '  Debug BOOTMEM initialization' CONFIG_DEBUG_BOOTMEM
 fi
 bool 'Stack Overflow Detection Support' CONFIG_STACK_DEBUG
 if [ "$CONFIG_STACK_DEBUG" = "y" ] ; then
diff -urN linux-2.4.25-pre7/arch/sparc64/defconfig linux-2.4.25-pre8/arch/sparc64/defconfig
--- linux-2.4.25-pre7/arch/sparc64/defconfig	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sparc64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -450,7 +450,6 @@
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_PDC202XX=y
-CONFIG_BLK_DEV_IDE_MODES=y
 CONFIG_BLK_DEV_ATARAID=m
 CONFIG_BLK_DEV_ATARAID_PDC=m
 CONFIG_BLK_DEV_ATARAID_HPT=m
diff -urN linux-2.4.25-pre7/arch/sparc64/kernel/head.S linux-2.4.25-pre8/arch/sparc64/kernel/head.S
--- linux-2.4.25-pre7/arch/sparc64/kernel/head.S	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/sparc64/kernel/head.S	2004-01-29 10:58:20.000000000 -0800
@@ -54,7 +54,14 @@
 
         .ascii  "HdrS"
         .word   LINUX_VERSION_CODE
-        .half   0x0203          /* HdrS version */
+
+	/* History:
+	 *
+	 * 0x0202 : Supports kernel params string
+	 * 0x0300 : Supports being located at other than 0x4000
+	 */
+        .half   0x0300          /* HdrS version */
+
 root_flags:
         .half   1
 root_dev:
@@ -345,7 +352,8 @@
 	nop
 	nop
 	and	%g1, %g3, %g1		/* Mask to just get paddr bits.       */
-	sub	%g1, %g2, %g1		/* Get rid of %pc offset to get base. */
+	set	0x5fff, %l3		/* Mask offset to get phys base.      */
+	andn	%g1, %l3, %g1
 
 	/* NOTE: We hold on to %g1 paddr base as we need it below to lock
 	 * NOTE: the PROM cif code into the TLB.
diff -urN linux-2.4.25-pre7/arch/sparc64/mm/init.c linux-2.4.25-pre8/arch/sparc64/mm/init.c
--- linux-2.4.25-pre7/arch/sparc64/mm/init.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.25-pre8/arch/sparc64/mm/init.c	2004-01-29 10:58:20.000000000 -0800
@@ -1202,6 +1202,10 @@
 	unsigned long bootmap_pfn, bytes_avail, size;
 	int i;
 
+#ifdef CONFIG_DEBUG_BOOTMEM
+	prom_printf("bootmem_init: Scan sp_banks, ");
+#endif
+
 	bytes_avail = 0UL;
 	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 		end_of_phys_memory = sp_banks[i].base_addr +
@@ -1268,19 +1272,32 @@
 	/* Initialize the boot-time allocator. */
 	max_pfn = max_low_pfn = end_pfn;
 	min_low_pfn = phys_base >> PAGE_SHIFT;
+
+#ifdef CONFIG_DEBUG_BOOTMEM
+	prom_printf("init_bootmem(spfn[%lx], bpfn[%lx], mlpfn[%lx])\n",
+		    start_pfn, bootmap_pfn, max_low_pfn);
+#endif
 	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn);
 
 	/* Now register the available physical memory with the
 	 * allocator.
 	 */
-	for (i = 0; sp_banks[i].num_bytes != 0; i++)
+	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+#ifdef CONFIG_DEBUG_BOOTMEM
+		prom_printf("free_bootmem(sp_banks:%d): base[%lx] size[%lx]\n",
+			    i, sp_banks[i].base_addr, sp_banks[i].num_bytes);
+#endif
 		free_bootmem(sp_banks[i].base_addr,
 			     sp_banks[i].num_bytes);
+	}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start) {
 		size = initrd_end - initrd_start;
-
+#ifdef CONFIG_DEBUG_BOOTMEM
+		prom_printf("reserve_bootmem(initrd): base[%lx] size[%lx]\n",
+			    initrd_start, size);
+#endif
 		/* Resert the initrd image area. */
 		reserve_bootmem(initrd_start, size);
 		*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
@@ -1291,6 +1308,9 @@
 #endif
 	/* Reserve the kernel text/data/bss. */
 	size = (start_pfn << PAGE_SHIFT) - phys_base;
+#ifdef CONFIG_DEBUG_BOOTMEM
+	prom_printf("reserve_bootmem(kernel): base[%lx] size[%lx]\n", phys_base, size);
+#endif
 	reserve_bootmem(phys_base, size);
 	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -1299,6 +1319,10 @@
 	 * in free_all_bootmem.
 	 */
 	size = bootmap_size;
+#ifdef CONFIG_DEBUG_BOOTMEM
+	prom_printf("reserve_bootmem(bootmap): base[%lx] size[%lx]\n",
+		    (bootmap_pfn << PAGE_SHIFT), size);
+#endif
 	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
 	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -1630,6 +1654,9 @@
 	max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT);
 	high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
+#ifdef CONFIG_DEBUG_BOOTMEM
+	prom_printf("mem_init: Calling free_all_bootmem().\n");
+#endif
 	num_physpages = free_all_bootmem() - 1;
 
 	/*
diff -urN linux-2.4.25-pre7/arch/x86_64/config.in linux-2.4.25-pre8/arch/x86_64/config.in
--- linux-2.4.25-pre7/arch/x86_64/config.in	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/config.in	2004-01-29 10:58:20.000000000 -0800
@@ -70,10 +70,12 @@
 fi
 
 bool 'Machine check support' CONFIG_MCE
-bool 'K8 NUMA support' CONFIG_K8_NUMA
-if [ "$CONFIG_K8_NUMA" = "y" ]; then
+if [ "$CONFIG_SMP" = "y" ]; then
+   bool 'K8 NUMA support' CONFIG_K8_NUMA
+   if [ "$CONFIG_K8_NUMA" = "y" ]; then
    define_bool CONFIG_DISCONTIGMEM y 
    define_bool CONFIG_NUMA y
+   fi
 fi
 
 endmenu
@@ -139,7 +141,6 @@
 if [ "$CONFIG_IDE" != "n" ]; then
   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_IDE_MODES n
   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
diff -urN linux-2.4.25-pre7/arch/x86_64/defconfig linux-2.4.25-pre8/arch/x86_64/defconfig
--- linux-2.4.25-pre7/arch/x86_64/defconfig	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/defconfig	2004-01-29 10:58:20.000000000 -0800
@@ -272,7 +272,6 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -477,6 +476,7 @@
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -528,6 +528,7 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_AMD_RNG is not set
 # CONFIG_INTEL_RNG is not set
@@ -560,6 +561,7 @@
 #
 # CONFIG_DRM is not set
 # CONFIG_MWAVE is not set
+# CONFIG_OBMOUSE is not set
 
 #
 # Multimedia devices
@@ -620,6 +622,11 @@
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
 # CONFIG_SIMICSFS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
diff -urN linux-2.4.25-pre7/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.25-pre8/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.25-pre7/arch/x86_64/ia32/ia32_ioctl.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/ia32/ia32_ioctl.c	2004-01-29 10:58:20.000000000 -0800
@@ -1,4 +1,4 @@
-/* $Id: ia32_ioctl.c,v 1.37 2003/08/20 11:00:23 ak Exp $
+/* $Id: ia32_ioctl.c,v 1.39 2004/01/29 03:01:57 ak Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -59,6 +59,7 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/if_tun.h>
 #include <linux/ctype.h>
+#include <linux/wireless.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/rfcomm.h>
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
@@ -112,10 +113,16 @@
 
 #include <asm/mtrr.h>
 
-
 #define A(__x) ((void *)(unsigned long)(__x))
 #define AA(__x)	A(__x)
 
+/* Allocate memory on the user stack */
+static __inline__ void *compat_alloc_user_space(long len)
+{
+	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
+	return (void *)regs->rsp - len; 
+}
+
 /* Aiee. Someone does not find a difference between int and long */
 #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
 #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
@@ -2917,7 +2924,7 @@
 	return ret; 
 
 	case RTC_IRQP_SET32: 
-		cmd = RTC_EPOCH_SET; 
+		cmd = RTC_IRQP_SET; 
 		break; 
 
 	case RTC_EPOCH_READ32:
@@ -3484,6 +3491,50 @@
 	return err;
 } 
 
+
+struct compat_iw_point {
+        __u32 pointer;
+	__u16 length;
+	__u16 flags;
+};
+
+static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct iwreq *iwr, *iwr_u;
+	struct iw_point *iwp;
+	struct compat_iw_point *iwp_u;
+	__u32 pointer;
+	__u16 length, flags;
+
+	iwr_u = (struct iwreq *) (u64)arg;
+	iwp_u = (struct compat_iw_point *) &iwr_u->u.data;
+	iwr = compat_alloc_user_space(sizeof(*iwr));
+	if (iwr == NULL)
+		return -ENOMEM;
+
+	iwp = &iwr->u.data;
+
+	if (verify_area(VERIFY_WRITE, iwr, sizeof(*iwr)))
+		return -EFAULT;
+
+	if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
+			   &iwr_u->ifr_ifrn.ifrn_name[0],
+			   sizeof(iwr->ifr_ifrn.ifrn_name)))
+		return -EFAULT;
+
+	if (__get_user(pointer, &iwp_u->pointer) ||
+	    __get_user(length, &iwp_u->length) ||
+	    __get_user(flags, &iwp_u->flags))
+		return -EFAULT;
+
+	if (__put_user((u64)pointer, &iwp->pointer) ||
+	    __put_user(length, &iwp->length) ||
+	    __put_user(flags, &iwp->flags))
+		return -EFAULT;
+
+	return sys_ioctl(fd, cmd, (unsigned long) iwr);
+}
+
 struct ioctl_trans {
 	unsigned long cmd;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
@@ -4357,6 +4408,21 @@
 HANDLE_IOCTL(MTRRIOC32_DEL_PAGE_ENTRY, mtrr_ioctl32)
 HANDLE_IOCTL(MTRRIOC32_GET_PAGE_ENTRY, mtrr_ioctl32)
 HANDLE_IOCTL(MTRRIOC32_KILL_PAGE_ENTRY, mtrr_ioctl32)
+/* wireless */
+HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
+COMPATIBLE_IOCTL(SIOCGIWNAME)
 IOCTL_TABLE_END
 
 #define IOCTL_HASHSIZE 256
diff -urN linux-2.4.25-pre7/arch/x86_64/ia32/ia32entry.S linux-2.4.25-pre8/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.25-pre7/arch/x86_64/ia32/ia32entry.S	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/ia32/ia32entry.S	2004-01-29 10:58:20.000000000 -0800
@@ -3,7 +3,7 @@
  * 		
  * Copyright 2000,2001 Andi Kleen, SuSE Labs.
  * 
- * $Id: ia32entry.S,v 1.41 2003/09/22 04:25:53 ak Exp $ 		
+ * $Id: ia32entry.S,v 1.42 2003/11/27 00:55:43 ak Exp $ 		
  */		 
 
 #include <asm/calling.h>
diff -urN linux-2.4.25-pre7/arch/x86_64/ia32/ptrace32.c linux-2.4.25-pre8/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.25-pre7/arch/x86_64/ia32/ptrace32.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/ia32/ptrace32.c	2004-01-29 10:58:20.000000000 -0800
@@ -8,7 +8,7 @@
  * This allows to access 64bit processes too; but there is no way to see the extended 
  * register contents.
  *
- * $Id: ptrace32.c,v 1.17 2003/03/24 09:25:15 ak Exp $
+ * $Id: ptrace32.c,v 1.18 2004/01/29 00:50:29 ak Exp $
  */ 
 
 #include <linux/kernel.h>
@@ -73,12 +73,9 @@
 	R32(eip, rip);
 	R32(esp, rsp);
 
-	case offsetof(struct user32, regs.eflags): { 
-		__u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
-		val &= FLAG_MASK;
-		*flags = val | (*flags & ~FLAG_MASK);
+	case offsetof(struct user32, regs.eflags): 
+		stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; 
 		break;
-	}
 
 	case offsetof(struct user32, u_debugreg[4]): 
 	case offsetof(struct user32, u_debugreg[5]):
diff -urN linux-2.4.25-pre7/arch/x86_64/ia32/sys_ia32.c linux-2.4.25-pre8/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.25-pre7/arch/x86_64/ia32/sys_ia32.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/ia32/sys_ia32.c	2004-01-29 10:58:20.000000000 -0800
@@ -16,7 +16,7 @@
  *
  * This file assumes that there is a hole at the end of user address space.
  *
- * $Id: sys_ia32.c,v 1.66 2003/11/10 13:09:54 ak Exp $
+ * $Id: sys_ia32.c,v 1.69 2004/01/29 02:52:13 ak Exp $
  */
 
 #include <linux/config.h>
@@ -174,12 +174,15 @@
 	return putstat(statbuf, &s);
 }
 
+extern long sys_truncate(char *, loff_t); 
+
 asmlinkage long
 sys32_truncate64(char * filename, unsigned long offset_low, unsigned long offset_high)
 {
        return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
 }
 
+extern long sys_ftruncate(int, loff_t); 
 
 asmlinkage long
 sys32_ftruncate64(unsigned int fd, unsigned long offset_low, unsigned long offset_high)
@@ -1453,8 +1456,12 @@
 
 asmlinkage long sys32_ni_syscall(int call)
 { 
+	/* Disable for now because the emulation should be pretty complete 
+	   and we miss some syscalls from 2.6. */
+#if 0
 	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,
 	       current->comm);
+#endif		   
 	return -ENOSYS;	       
 } 
 
@@ -3035,7 +3042,7 @@
 
 static int __init ia32_init (void)
 {
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.66 2003/11/10 13:09:54 ak Exp $\n");  
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.69 2004/01/29 02:52:13 ak Exp $\n");  
 	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
 	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
 	register_exec_domain(&ia32_exec_domain);
diff -urN linux-2.4.25-pre7/arch/x86_64/kernel/bluesmoke.c linux-2.4.25-pre8/arch/x86_64/kernel/bluesmoke.c
--- linux-2.4.25-pre7/arch/x86_64/kernel/bluesmoke.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/kernel/bluesmoke.c	2004-01-29 10:58:20.000000000 -0800
@@ -25,14 +25,6 @@
 static int banks;
 static unsigned long ignored_banks, disabled_banks;
 
-/* Machine Check on everything dubious. This is a good setting
-   for device driver testing. */
-#define K8_DRIVER_DEBUG ((1<<13)-1)
-/* Report RAM errors and Hyper Transport Problems, but ignore Device
-   aborts and GART errors. */
-#define K8_NORMAL_OP    0xff
-static u32 k8_nb_flags __initdata = K8_NORMAL_OP;
-
 static void generic_machine_check(struct pt_regs * regs, long error_code)
 {
 	int recover=1;
@@ -201,53 +193,48 @@
 	if (header) 
 		printk(KERN_ERR "CPU %d: Silent Northbridge MCE\n", smp_processor_id());
 
-	printk(KERN_ERR "Northbridge status %08x%08x\n",
+	printk(KERN_ERR "Northbridge status %08x:%08x\n",
 	       statushigh,statuslow); 
 
+	printk(KERN_ERR "    Error %s\n", extendederr[(statuslow >> 16) & 0xf]); 
+
 	unsigned short errcode = statuslow & 0xffff;	
-	switch (errcode >> 8) { 
-	case 0: 					
+	switch ((statuslow >> 16) & 0xF) { 
+	case 5: 					
 		printk(KERN_ERR "    GART TLB error %s %s\n", 
 		       transaction[(errcode >> 2) & 3], 
 		       cachelevel[errcode & 3]);
 		break;
-	case 1: 
-		if (errcode & (1<<11)) { 
-			printk(KERN_ERR "    bus error %s %s %s %s %s\n",
-			       partproc[(errcode >> 10) & 0x3],
-			       timeout[(errcode >> 9) & 1],
+	case 8:
+		printk(KERN_ERR "    ECC error syndrome %x\n", 
+		       (((statuslow >> 24) & 0xff)  << 8) | ((statushigh >> 15) & 0x7f));		
+		/*FALL THROUGH*/
+	default:
+		printk(KERN_ERR "    bus error %s, %s\n    %s\n    %s, %s\n",
+		       partproc[(errcode >> 9) & 0x3],
+		       timeout[(errcode >> 8) & 1],
 			       memtrans[(errcode >> 4) & 0xf],
 			       memoryio[(errcode >> 2) & 0x3], 
 			       cachelevel[(errcode & 0x3)]); 
-		} else if (errcode & (1<<8)) { 
-			printk(KERN_ERR "    memory error %s %s %s\n",
-			       memtrans[(errcode >> 4) & 0xf],
-			       transaction[(errcode >> 2) & 0x3],
-			       cachelevel[(errcode & 0x3)]);
-		} else {
-			printk(KERN_ERR "    unknown error code %x\n", errcode); 
-		}
+		/* should only print when it was a HyperTransport related error. */
+		printk(KERN_ERR "    link number %x\n", (statushigh >> 4) & 3);
 		break;
 	} 
-	if (statushigh & ((1<<14)|(1<<13)))
-		printk(KERN_ERR "    ECC syndrome bits %x\n", 
-		       (((statuslow >> 24) & 0xff)  << 8) | ((statushigh >> 15) & 0x7f));
-	errcode = (statuslow >> 16) & 0xf;
-	printk(KERN_ERR "    extended error %s\n", extendederr[(statuslow >> 16) & 0xf]); 
 	
-	/* should only print when it was a HyperTransport related error. */
-	printk(KERN_ERR "    link number %x\n", (statushigh >> 4) & 3);
 
 	int i;
-	for (i = 0; i < 32; i++) 
+	for (i = 0; i < 32; i++) { 
+		if (i == 26 || i == 28) 
+			continue;
 		if (highbits[i] && (statushigh & (1<<i)))
 			printk(KERN_ERR "    %s\n", highbits[i]); 
+	}
 
 	if (statushigh & (1<<26)) { 
 		u32 addrhigh, addrlow; 
 		pci_read_config_dword(nb, 0x54, &addrhigh); 
 		pci_read_config_dword(nb, 0x50, &addrlow); 
-		printk(KERN_ERR "    error address %08x%08x\n", addrhigh,addrlow); 
+		printk(KERN_ERR "    NB error address %08x%08x\n", addrhigh,addrlow); 
 	}
 	statushigh &= ~(1<<31); 
 	pci_write_config_dword(nb, 0x4c, statushigh); 		
@@ -293,9 +280,6 @@
 	wrmsrl(MSR_IA32_MC0_STATUS+4*4, 0); 
 	wrmsrl(MSR_IA32_MCG_STATUS, 0);
        
-	if (regs && (status & (1<<1)))
-		printk(KERN_EMERG "MCE at EIP %lx ESP %lx\n", regs->rip, regs->rsp); 
-
  others:
 	generic_machine_check(regs, error_code); 
 } 
@@ -353,12 +337,13 @@
 	machine_check_vector = k8_machine_check; 
 	for (i = 0; i < banks; i++) { 
 		u64 val = ((1UL<<i) & disabled_banks) ? 0 : ~0UL; 
-		if (val && i == 4)
-			val = k8_nb_flags;
 		wrmsrl(MSR_IA32_MC0_CTL+4*i, val);
 		wrmsrl(MSR_IA32_MC0_STATUS+4*i,0); 
 	}
 
+	if (cap & (1<<8))
+		wrmsrl(MSR_IA32_MCG_CTL, 0xffffffffffffffffULL);
+
 	set_in_cr4(X86_CR4_MCE);	   	
 
 	if (mcheck_interval && (smp_processor_id() == 0)) { 
@@ -455,7 +440,6 @@
    mce=nok8 disable k8 specific features
    mce=disable<NUMBER> disable bank NUMBER
    mce=enable<NUMBER> enable bank number
-   mce=device	Enable device driver test reporting in NB
    mce=NUMBER mcheck timer interval number seconds. 
    Can be also comma separated in a single mce= */
 static int __init mcheck_enable(char *str)
@@ -472,8 +456,6 @@
 			disabled_banks |= ~(1<<simple_strtol(p+7,NULL,0));
 		else if (!strcmp(p,"nok8"))
 			nok8 = 1;
-		else if (!strcmp(p,"device"))
-			k8_nb_flags = K8_DRIVER_DEBUG;
 	}
 	return 0;
 }
diff -urN linux-2.4.25-pre7/arch/x86_64/kernel/e820.c linux-2.4.25-pre8/arch/x86_64/kernel/e820.c
--- linux-2.4.25-pre7/arch/x86_64/kernel/e820.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/kernel/e820.c	2004-01-29 10:58:20.000000000 -0800
@@ -1,7 +1,7 @@
 /* 
  * Handle the memory map.
  * The functions here do the job until bootmem takes over.
- * $Id: e820.c,v 1.11 2003/10/11 15:16:35 ak Exp $
+ * $Id: e820.c,v 1.12 2004/01/13 10:13:30 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
diff -urN linux-2.4.25-pre7/arch/x86_64/kernel/mtrr.c linux-2.4.25-pre8/arch/x86_64/kernel/mtrr.c
--- linux-2.4.25-pre7/arch/x86_64/kernel/mtrr.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/kernel/mtrr.c	2004-01-29 10:58:20.000000000 -0800
@@ -70,6 +70,9 @@
 
 #define MTRR_VERSION "2.02 (20020716)"
 
+#define MTRR_BEG_BIT 12
+#define MTRR_END_BIT 7
+
 #undef Dprintk
 
 #define Dprintk(...) 
@@ -192,8 +195,9 @@
 
 static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type)
 {
-	u32 mask_lo, mask_hi, base_lo, base_hi;
-	u64 newsize;
+	u32 count, tmp, mask_lo, mask_hi;
+	int i;
+	u32 base_lo, base_hi;
 
 	rdmsr (MSR_MTRRphysMask(reg), mask_lo, mask_hi);
 	if ((mask_lo & 0x800) == 0) {
@@ -206,10 +210,16 @@
 
 	rdmsr (MSR_MTRRphysBase(reg), base_lo, base_hi);
 
-	/* Work out the shifted address mask. */
-	newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800);
-	newsize = ~newsize+1;
-	*size = (u32) newsize >> PAGE_SHIFT;
+	count = 0;
+	tmp = mask_lo >> MTRR_BEG_BIT;
+	for (i = MTRR_BEG_BIT; i <= 31; i++, tmp = tmp >> 1)
+		count = (count << (~tmp & 1)) | (~tmp & 1);
+	
+	tmp = mask_hi;
+	for (i = 0; i <= MTRR_END_BIT; i++, tmp = tmp >> 1)
+		count = (count << (~tmp & 1)) | (~tmp & 1);
+	
+	*size = (count+1); 
 	*base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
 	*type = base_lo & 0xff;
 }
@@ -243,7 +253,7 @@
 		base64 = (base << PAGE_SHIFT) & size_and_mask;
 		wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32);
 
-		size64 = ~((size << PAGE_SHIFT) - 1);
+		size64 = ~(((u64)size << PAGE_SHIFT) - 1);
 		size64 = size64 & size_and_mask;
 		wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32));
 	}
diff -urN linux-2.4.25-pre7/arch/x86_64/kernel/pci-gart.c linux-2.4.25-pre8/arch/x86_64/kernel/pci-gart.c
--- linux-2.4.25-pre7/arch/x86_64/kernel/pci-gart.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/kernel/pci-gart.c	2004-01-29 10:58:20.000000000 -0800
@@ -8,7 +8,7 @@
  * See Documentation/DMA-mapping.txt for the interface specification.
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: pci-gart.c,v 1.28 2003/09/19 07:01:58 ak Exp $
+ * $Id: pci-gart.c,v 1.30 2004/01/13 09:09:32 ak Exp $
  */
 
 #include <linux/config.h>
@@ -42,6 +42,7 @@
 #else
 int force_mmu = 0;
 #endif
+int iommu_fullflush = 1;
 
 extern int fallback_aper_order;
 extern int fallback_aper_force;
@@ -97,6 +98,8 @@
 			next_bit = 0;
 	} 
 	} 
+	if (iommu_fullflush)
+		need_flush = 1;
 	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);      
 	return offset;
 } 
@@ -123,8 +126,12 @@
 	/* recheck flush count inside lock */
 	if (need_flush) { 
 		for (i = 0; northbridges[i]; i++) { 
+			u32 w;
 			pci_write_config_dword(northbridges[i], 0x9c, 
 					       northbridge_flush_word[i] | 1); 
+			do { 
+				pci_read_config_dword(northbridges[i], 0x9c, &w);
+			} while (w & 1);
 			flushed++;
 		} 
 		if (!flushed) 
@@ -463,6 +470,7 @@
 
  nommu:
 	/* XXX: reject 0xffffffff mask now in pci mapping functions */
+	if (end_pfn >= 0xffffffff>>PAGE_SHIFT)
 		printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
 	       KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction."); 
 	return -1; 
@@ -570,6 +578,8 @@
    memaper[=order] allocate an own aperture over RAM with size 32MB^order.
    noforce don't force IOMMU usage. Default
    force  Force IOMMU for all devices.
+   nofullflush use optimized IOMMU flushing (may break on some devices).
+               default off.
 */
 __init int iommu_setup(char *opt) 
 { 
@@ -585,6 +595,8 @@
 		    force_mmu = 1;
 	    if (!memcmp(p,"noforce", 7))
 		    force_mmu = 0;
+	    if (!memcmp(p,"nofullflush", 11))
+		    iommu_fullflush = 0;
 	    if (!memcmp(p, "memaper", 7)) { 
 		    fallback_aper_force = 1; 
 		    p += 7; 
diff -urN linux-2.4.25-pre7/arch/x86_64/kernel/process.c linux-2.4.25-pre8/arch/x86_64/kernel/process.c
--- linux-2.4.25-pre7/arch/x86_64/kernel/process.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/kernel/process.c	2004-01-29 10:58:20.000000000 -0800
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.74 2003/08/13 13:43:16 ak Exp $
+ *  $Id: process.c,v 1.75 2004/01/13 09:04:32 ak Exp $
  */
 
 /*
@@ -159,7 +159,7 @@
 
 __setup("idle=", idle_setup);
 
-static long no_idt[3];
+static struct { long x; } no_idt[3];
 static enum { 
 	BOOT_BIOS = 'b',
 	BOOT_TRIPLE = 't', 
diff -urN linux-2.4.25-pre7/arch/x86_64/mm/k8topology.c linux-2.4.25-pre8/arch/x86_64/mm/k8topology.c
--- linux-2.4.25-pre7/arch/x86_64/mm/k8topology.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/arch/x86_64/mm/k8topology.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  * Instead the northbridge registers are read directly. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: k8topology.c,v 1.11 2003/09/12 01:55:37 ak Exp $
+ * $Id: k8topology.c,v 1.12 2004/01/29 00:51:01 ak Exp $
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -100,7 +100,7 @@
 
 	printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); 
 
-	numnodes = (read_pci_config(0, nb, 0, 0x60 ) >> 4) & 3; 
+	numnodes = (read_pci_config(0, nb, 0, 0x60 ) >> 4) & 7; 
 
 	memset(&nodes,0,sizeof(nodes)); 
 	prevbase = 0;
@@ -111,7 +111,7 @@
 		base = read_pci_config(0, nb, 1, 0x40 + i*8);
 		limit = read_pci_config(0, nb, 1, 0x44 + i*8);
 
-		nodeid = limit & 3; 
+		nodeid = limit & 7; 
 		if ((base & 3) == 0) { 
 			continue;
 		} 
diff -urN linux-2.4.25-pre7/drivers/acpi/ac.c linux-2.4.25-pre8/drivers/acpi/ac.c
--- linux-2.4.25-pre7/drivers/acpi/ac.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/ac.c	2004-01-29 10:58:20.000000000 -0800
@@ -93,7 +93,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_ac_dir = NULL;
+struct proc_dir_entry		*acpi_ac_dir;
 
 static int
 acpi_ac_read_state (
diff -urN linux-2.4.25-pre7/drivers/acpi/asus_acpi.c linux-2.4.25-pre8/drivers/acpi/asus_acpi.c
--- linux-2.4.25-pre7/drivers/acpi/asus_acpi.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/asus_acpi.c	2004-01-29 10:58:20.000000000 -0800
@@ -73,8 +73,8 @@
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
-static uid_t asus_uid = 0;
-static gid_t asus_gid = 0;
+static uid_t asus_uid;
+static gid_t asus_gid;
 MODULE_PARM(asus_uid, "i");
 MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n");
 MODULE_PARM(asus_gid, "i");
@@ -192,14 +192,14 @@
 };
 
 /* procdir we use */
-static struct proc_dir_entry *asus_proc_dir = NULL;
+static struct proc_dir_entry *asus_proc_dir;
 
 /*
  * This header is made available to allow proper configuration given model,
  * revision number , ... this info cannot go in struct asus_hotk because it is
  * available before the hotk
  */
-static struct acpi_table_header *asus_info = NULL;
+static struct acpi_table_header *asus_info;
 
 /*
  * The hotkey driver declaration
diff -urN linux-2.4.25-pre7/drivers/acpi/battery.c linux-2.4.25-pre8/drivers/acpi/battery.c
--- linux-2.4.25-pre7/drivers/acpi/battery.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/battery.c	2004-01-29 10:58:20.000000000 -0800
@@ -328,7 +328,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_battery_dir = NULL;
+struct proc_dir_entry		*acpi_battery_dir;
 
 static int
 acpi_battery_read_info (
diff -urN linux-2.4.25-pre7/drivers/acpi/button.c linux-2.4.25-pre8/drivers/acpi/button.c
--- linux-2.4.25-pre7/drivers/acpi/button.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/button.c	2004-01-29 10:58:20.000000000 -0800
@@ -68,7 +68,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-static struct proc_dir_entry	*acpi_button_dir = NULL;
+static struct proc_dir_entry	*acpi_button_dir;
 
 static int
 acpi_button_read_info (
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsfield.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsfield.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsfield.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsfield.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsinit.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsinit.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsinit.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsinit.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsmethod.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsmethod.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsmethod.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsmethod.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsmthdat.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsmthdat.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsmthdat.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsmthdat.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -601,7 +601,6 @@
 	new_obj_desc = obj_desc;
 	if (obj_desc->common.reference_count > 1) {
 		status = acpi_ut_copy_iobject_to_iobject (obj_desc, &new_obj_desc, walk_state);
-		new_obj_desc;
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
 		}
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsobject.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsobject.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsobject.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsobject.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsopcode.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsopcode.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsopcode.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsopcode.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dsutils.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dsutils.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dsutils.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dsutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dswexec.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dswexec.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dswexec.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dswexec.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dswload.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dswload.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dswload.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dswload.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dswscope.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dswscope.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dswscope.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dswscope.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/dispatcher/dswstate.c linux-2.4.25-pre8/drivers/acpi/dispatcher/dswstate.c
--- linux-2.4.25-pre7/drivers/acpi/dispatcher/dswstate.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/dispatcher/dswstate.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/ec.c linux-2.4.25-pre8/drivers/acpi/ec.c
--- linux-2.4.25-pre7/drivers/acpi/ec.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/ec.c	2004-01-29 10:58:20.000000000 -0800
@@ -471,7 +471,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_ec_dir = NULL;
+struct proc_dir_entry		*acpi_ec_dir;
 
 
 static int
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evevent.c linux-2.4.25-pre8/drivers/acpi/events/evevent.c
--- linux-2.4.25-pre7/drivers/acpi/events/evevent.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/events/evevent.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evgpe.c linux-2.4.25-pre8/drivers/acpi/events/evgpe.c
--- linux-2.4.25-pre7/drivers/acpi/events/evgpe.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evgpe.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evgpeblk.c linux-2.4.25-pre8/drivers/acpi/events/evgpeblk.c
--- linux-2.4.25-pre7/drivers/acpi/events/evgpeblk.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evgpeblk.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evmisc.c linux-2.4.25-pre8/drivers/acpi/events/evmisc.c
--- linux-2.4.25-pre7/drivers/acpi/events/evmisc.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evmisc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evregion.c linux-2.4.25-pre8/drivers/acpi/events/evregion.c
--- linux-2.4.25-pre7/drivers/acpi/events/evregion.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evregion.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,7 @@
 
 #define ACPI_NUM_DEFAULT_SPACES     4
 
-u8                              acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
+static u8                   acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
 			 ACPI_ADR_SPACE_SYSTEM_MEMORY,
 			 ACPI_ADR_SPACE_SYSTEM_IO,
 			 ACPI_ADR_SPACE_PCI_CONFIG,
@@ -699,9 +699,6 @@
 	acpi_status                     status;
 
 
-	ACPI_FUNCTION_NAME ("ev_reg_run");
-
-
 	handler_obj = (union acpi_operand_object   *) context;
 
 	/* Parameter validation */
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evrgnini.c linux-2.4.25-pre8/drivers/acpi/events/evrgnini.c
--- linux-2.4.25-pre7/drivers/acpi/events/evrgnini.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evrgnini.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evsci.c linux-2.4.25-pre8/drivers/acpi/events/evsci.c
--- linux-2.4.25-pre7/drivers/acpi/events/evsci.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/events/evsci.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evxface.c linux-2.4.25-pre8/drivers/acpi/events/evxface.c
--- linux-2.4.25-pre7/drivers/acpi/events/evxface.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/events/evxface.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evxfevnt.c linux-2.4.25-pre8/drivers/acpi/events/evxfevnt.c
--- linux-2.4.25-pre7/drivers/acpi/events/evxfevnt.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/events/evxfevnt.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/events/evxfregn.c linux-2.4.25-pre8/drivers/acpi/events/evxfregn.c
--- linux-2.4.25-pre7/drivers/acpi/events/evxfregn.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/events/evxfregn.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exconfig.c linux-2.4.25-pre8/drivers/acpi/executer/exconfig.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exconfig.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exconfig.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exconvrt.c linux-2.4.25-pre8/drivers/acpi/executer/exconvrt.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exconvrt.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exconvrt.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/excreate.c linux-2.4.25-pre8/drivers/acpi/executer/excreate.c
--- linux-2.4.25-pre7/drivers/acpi/executer/excreate.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/excreate.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exdump.c linux-2.4.25-pre8/drivers/acpi/executer/exdump.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exdump.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exdump.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exfield.c linux-2.4.25-pre8/drivers/acpi/executer/exfield.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exfield.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exfield.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exfldio.c linux-2.4.25-pre8/drivers/acpi/executer/exfldio.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exfldio.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exfldio.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exmisc.c linux-2.4.25-pre8/drivers/acpi/executer/exmisc.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exmisc.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exmisc.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exmutex.c linux-2.4.25-pre8/drivers/acpi/executer/exmutex.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exmutex.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exmutex.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exnames.c linux-2.4.25-pre8/drivers/acpi/executer/exnames.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exnames.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exnames.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exoparg1.c linux-2.4.25-pre8/drivers/acpi/executer/exoparg1.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exoparg1.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exoparg1.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exoparg2.c linux-2.4.25-pre8/drivers/acpi/executer/exoparg2.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exoparg2.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exoparg2.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exoparg3.c linux-2.4.25-pre8/drivers/acpi/executer/exoparg3.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exoparg3.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exoparg3.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exoparg6.c linux-2.4.25-pre8/drivers/acpi/executer/exoparg6.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exoparg6.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exoparg6.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exprep.c linux-2.4.25-pre8/drivers/acpi/executer/exprep.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exprep.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exprep.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exregion.c linux-2.4.25-pre8/drivers/acpi/executer/exregion.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exregion.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exregion.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exresnte.c linux-2.4.25-pre8/drivers/acpi/executer/exresnte.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exresnte.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exresnte.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exresolv.c linux-2.4.25-pre8/drivers/acpi/executer/exresolv.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exresolv.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exresolv.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exresop.c linux-2.4.25-pre8/drivers/acpi/executer/exresop.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exresop.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exresop.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exstore.c linux-2.4.25-pre8/drivers/acpi/executer/exstore.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exstore.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exstore.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exstoren.c linux-2.4.25-pre8/drivers/acpi/executer/exstoren.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exstoren.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exstoren.c	2004-01-29 10:58:20.000000000 -0800
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exstorob.c linux-2.4.25-pre8/drivers/acpi/executer/exstorob.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exstorob.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exstorob.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exsystem.c linux-2.4.25-pre8/drivers/acpi/executer/exsystem.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exsystem.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/executer/exsystem.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/executer/exutils.c linux-2.4.25-pre8/drivers/acpi/executer/exutils.c
--- linux-2.4.25-pre7/drivers/acpi/executer/exutils.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/executer/exutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/fan.c linux-2.4.25-pre8/drivers/acpi/fan.c
--- linux-2.4.25-pre7/drivers/acpi/fan.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/fan.c	2004-01-29 10:58:20.000000000 -0800
@@ -65,7 +65,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_fan_dir = NULL;
+struct proc_dir_entry		*acpi_fan_dir;
 
 
 static int
diff -urN linux-2.4.25-pre7/drivers/acpi/hardware/hwacpi.c linux-2.4.25-pre8/drivers/acpi/hardware/hwacpi.c
--- linux-2.4.25-pre7/drivers/acpi/hardware/hwacpi.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/hardware/hwacpi.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/hardware/hwgpe.c linux-2.4.25-pre8/drivers/acpi/hardware/hwgpe.c
--- linux-2.4.25-pre7/drivers/acpi/hardware/hwgpe.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/hardware/hwgpe.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -348,17 +348,14 @@
 	struct acpi_gpe_block_info      *gpe_block)
 {
 	u32                             i;
-	struct acpi_gpe_register_info   *gpe_register_info;
 	acpi_status                     status;
 
 
-	/* Get the register info for the entire GPE block */
-
-	gpe_register_info = gpe_block->register_info;
-
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+		/* Disable all GPEs in this register */
+
 		status = acpi_hw_low_level_write (8, 0x00,
 				 &gpe_block->register_info[i].enable_address);
 		if (ACPI_FAILURE (status)) {
@@ -389,17 +386,14 @@
 	struct acpi_gpe_block_info      *gpe_block)
 {
 	u32                             i;
-	struct acpi_gpe_register_info   *gpe_register_info;
 	acpi_status                     status;
 
 
-	/* Get the register info for the entire GPE block */
-
-	gpe_register_info = gpe_block->register_info;
-
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
+		/* Clear all GPEs in this register */
+
 		status = acpi_hw_low_level_write (8, 0xFF,
 				 &gpe_block->register_info[i].status_address);
 		if (ACPI_FAILURE (status)) {
diff -urN linux-2.4.25-pre7/drivers/acpi/hardware/hwregs.c linux-2.4.25-pre8/drivers/acpi/hardware/hwregs.c
--- linux-2.4.25-pre7/drivers/acpi/hardware/hwregs.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/hardware/hwregs.c	2004-01-29 10:58:20.000000000 -0800
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/hardware/hwsleep.c linux-2.4.25-pre8/drivers/acpi/hardware/hwsleep.c
--- linux-2.4.25-pre7/drivers/acpi/hardware/hwsleep.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/hardware/hwsleep.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -251,7 +251,7 @@
 		}
 	}
 
-	status = acpi_hw_disable_non_wakeup_gpes();
+	status = acpi_hw_disable_non_wakeup_gpes ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -274,6 +274,11 @@
 	PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
 	PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
 
+	/*
+	 * We split the writes of SLP_TYP and SLP_EN to workaround
+	 * poorly implemented hardware.
+	 */
+
 	/* Write #1: fill in SLP_TYP data */
 
 	status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
@@ -313,7 +318,7 @@
 		 * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
 		 *
 		 * We wait so long to allow chipsets that poll this reg very slowly to
-		 * still read the right value. Ideally, this entire block would go
+		 * still read the right value. Ideally, this block would go
 		 * away entirely.
 		 */
 		acpi_os_stall (10000000);
@@ -365,12 +370,22 @@
 	ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios");
 
 
-	acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
-	acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+	status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
 
-	acpi_hw_disable_non_wakeup_gpes();
+	status = acpi_hw_disable_non_wakeup_gpes ();
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
 
-	ACPI_FLUSH_CPU_CACHE();
+	ACPI_FLUSH_CPU_CACHE ();
 
 	status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
 
@@ -407,30 +422,47 @@
 	acpi_status                     status;
 	struct acpi_bit_register_info   *sleep_type_reg_info;
 	struct acpi_bit_register_info   *sleep_enable_reg_info;
-	u32                             pm1x_control;
+	u32                             PM1Acontrol;
+	u32                             PM1Bcontrol;
 
 
 	ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state");
 
-	/* Some machines require SLP_TYPE and SLP_EN to be cleared */
 
-	sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
-	sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
+	/*
+	 * Set SLP_TYPE and SLP_EN to state S0.
+	 * This is unclear from the ACPI Spec, but it is required
+	 * by some machines.
+	 */
+	status = acpi_get_sleep_type_data (ACPI_STATE_S0,
+			  &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
+	if (ACPI_SUCCESS (status)) {
+		sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
+		sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
 
-	/* Get current value of PM1A control */
+		/* Get current value of PM1A control */
 
-	status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
-			 ACPI_REGISTER_PM1_CONTROL, &pm1x_control);
-	if (ACPI_SUCCESS (status)) {
-		/* Clear SLP_TYP and SLP_EN */
+		status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+				 ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+		if (ACPI_SUCCESS (status)) {
+			/* Clear SLP_EN and SLP_TYP fields */
+
+			PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
+					   sleep_enable_reg_info->access_bit_mask);
+			PM1Bcontrol = PM1Acontrol;
 
-		pm1x_control &= ~(sleep_type_reg_info->access_bit_mask |
-				   sleep_enable_reg_info->access_bit_mask);
+			/* Insert SLP_TYP bits */
 
-		acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
-				ACPI_REGISTER_PM1A_CONTROL, pm1x_control);
-		acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
-				ACPI_REGISTER_PM1B_CONTROL, pm1x_control);
+			PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
+			PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
+
+			/* Just ignore any errors */
+
+			(void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+					  ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+			(void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+					  ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+		}
 	}
 
 	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
@@ -464,7 +496,7 @@
 
 	/* _WAK returns stuff - do we want to look at it? */
 
-	status = acpi_hw_enable_non_wakeup_gpes();
+	status = acpi_hw_enable_non_wakeup_gpes ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
diff -urN linux-2.4.25-pre7/drivers/acpi/hardware/hwtimer.c linux-2.4.25-pre8/drivers/acpi/hardware/hwtimer.c
--- linux-2.4.25-pre7/drivers/acpi/hardware/hwtimer.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/hardware/hwtimer.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsaccess.c linux-2.4.25-pre8/drivers/acpi/namespace/nsaccess.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsaccess.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsaccess.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsalloc.c linux-2.4.25-pre8/drivers/acpi/namespace/nsalloc.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsalloc.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsalloc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsdump.c linux-2.4.25-pre8/drivers/acpi/namespace/nsdump.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsdump.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsdump.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsdumpdv.c linux-2.4.25-pre8/drivers/acpi/namespace/nsdumpdv.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsdumpdv.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsdumpdv.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nseval.c linux-2.4.25-pre8/drivers/acpi/namespace/nseval.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nseval.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nseval.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsinit.c linux-2.4.25-pre8/drivers/acpi/namespace/nsinit.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsinit.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsinit.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsload.c linux-2.4.25-pre8/drivers/acpi/namespace/nsload.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsload.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsload.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsnames.c linux-2.4.25-pre8/drivers/acpi/namespace/nsnames.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsnames.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsnames.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsobject.c linux-2.4.25-pre8/drivers/acpi/namespace/nsobject.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsobject.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsobject.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsparse.c linux-2.4.25-pre8/drivers/acpi/namespace/nsparse.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsparse.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsparse.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nssearch.c linux-2.4.25-pre8/drivers/acpi/namespace/nssearch.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nssearch.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nssearch.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsutils.c linux-2.4.25-pre8/drivers/acpi/namespace/nsutils.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsutils.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nswalk.c linux-2.4.25-pre8/drivers/acpi/namespace/nswalk.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nswalk.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nswalk.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsxfeval.c linux-2.4.25-pre8/drivers/acpi/namespace/nsxfeval.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsxfeval.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsxfeval.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsxfname.c linux-2.4.25-pre8/drivers/acpi/namespace/nsxfname.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsxfname.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsxfname.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/namespace/nsxfobj.c linux-2.4.25-pre8/drivers/acpi/namespace/nsxfobj.c
--- linux-2.4.25-pre7/drivers/acpi/namespace/nsxfobj.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/namespace/nsxfobj.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/osl.c linux-2.4.25-pre8/drivers/acpi/osl.c
--- linux-2.4.25-pre7/drivers/acpi/osl.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/osl.c	2004-01-29 10:58:20.000000000 -0800
@@ -60,13 +60,13 @@
 #ifdef ENABLE_DEBUGGER
 #include <linux/kdb.h>
 /* stuff for debugger support */
-int acpi_in_debugger = 0;
+int acpi_in_debugger;
 extern char line_buf[80];
 #endif /*ENABLE_DEBUGGER*/
 
-static int acpi_irq_irq = 0;
-static OSD_HANDLER acpi_irq_handler = NULL;
-static void *acpi_irq_context = NULL;
+static int acpi_irq_irq;
+static OSD_HANDLER acpi_irq_handler;
+static void *acpi_irq_context;
 
 
 acpi_status
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psargs.c linux-2.4.25-pre8/drivers/acpi/parser/psargs.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psargs.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/parser/psargs.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psopcode.c linux-2.4.25-pre8/drivers/acpi/parser/psopcode.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psopcode.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/parser/psopcode.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psparse.c linux-2.4.25-pre8/drivers/acpi/parser/psparse.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psparse.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/parser/psparse.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psscope.c linux-2.4.25-pre8/drivers/acpi/parser/psscope.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psscope.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/parser/psscope.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/pstree.c linux-2.4.25-pre8/drivers/acpi/parser/pstree.c
--- linux-2.4.25-pre7/drivers/acpi/parser/pstree.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/parser/pstree.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psutils.c linux-2.4.25-pre8/drivers/acpi/parser/psutils.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psutils.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/parser/psutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/pswalk.c linux-2.4.25-pre8/drivers/acpi/parser/pswalk.c
--- linux-2.4.25-pre7/drivers/acpi/parser/pswalk.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/parser/pswalk.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/parser/psxface.c linux-2.4.25-pre8/drivers/acpi/parser/psxface.c
--- linux-2.4.25-pre7/drivers/acpi/parser/psxface.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/parser/psxface.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/power.c linux-2.4.25-pre8/drivers/acpi/power.c
--- linux-2.4.25-pre7/drivers/acpi/power.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/power.c	2004-01-29 10:58:20.000000000 -0800
@@ -373,7 +373,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_power_dir = NULL;
+struct proc_dir_entry		*acpi_power_dir;
 
 
 static int
diff -urN linux-2.4.25-pre7/drivers/acpi/processor.c linux-2.4.25-pre8/drivers/acpi/processor.c
--- linux-2.4.25-pre7/drivers/acpi/processor.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/processor.c	2004-01-29 10:58:20.000000000 -0800
@@ -214,7 +214,7 @@
 
 static struct acpi_processor	*processors[NR_CPUS];
 static struct acpi_processor_errata errata;
-static void (*pm_idle_save)(void) = NULL;
+static void (*pm_idle_save)(void);
 
 
 /* --------------------------------------------------------------------------
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsaddr.c linux-2.4.25-pre8/drivers/acpi/resources/rsaddr.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsaddr.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsaddr.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rscalc.c linux-2.4.25-pre8/drivers/acpi/resources/rscalc.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rscalc.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rscalc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rscreate.c linux-2.4.25-pre8/drivers/acpi/resources/rscreate.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rscreate.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rscreate.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsdump.c linux-2.4.25-pre8/drivers/acpi/resources/rsdump.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsdump.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsdump.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsio.c linux-2.4.25-pre8/drivers/acpi/resources/rsio.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsio.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsio.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsirq.c linux-2.4.25-pre8/drivers/acpi/resources/rsirq.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsirq.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsirq.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rslist.c linux-2.4.25-pre8/drivers/acpi/resources/rslist.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rslist.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/resources/rslist.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsmemory.c linux-2.4.25-pre8/drivers/acpi/resources/rsmemory.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsmemory.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsmemory.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsmisc.c linux-2.4.25-pre8/drivers/acpi/resources/rsmisc.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsmisc.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsmisc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsutils.c linux-2.4.25-pre8/drivers/acpi/resources/rsutils.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsutils.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/resources/rsxface.c linux-2.4.25-pre8/drivers/acpi/resources/rsxface.c
--- linux-2.4.25-pre7/drivers/acpi/resources/rsxface.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/resources/rsxface.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbconvrt.c linux-2.4.25-pre8/drivers/acpi/tables/tbconvrt.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbconvrt.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbconvrt.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -138,11 +138,11 @@
 	for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
 		if (acpi_gbl_RSDP->revision < 2) {
 			ACPI_STORE_ADDRESS (new_table->table_offset_entry[i],
-				((struct rsdt_descriptor_rev1 *) table_info->pointer)->table_offset_entry[i]);
+				(ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]);
 		}
 		else {
 			new_table->table_offset_entry[i] =
-				((XSDT_DESCRIPTOR *) table_info->pointer)->table_offset_entry[i];
+				(ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i];
 		}
 	}
 
@@ -152,7 +152,7 @@
 
 	/* Point the table descriptor to the new table */
 
-	table_info->pointer     = (struct acpi_table_header *) new_table;
+	table_info->pointer     = ACPI_CAST_PTR (struct acpi_table_header, new_table);
 	table_info->length      = table_size;
 	table_info->allocation  = ACPI_MEM_ALLOCATED;
 
@@ -469,7 +469,7 @@
 
 	/* Install the new table */
 
-	table_desc->pointer     = (struct acpi_table_header *) acpi_gbl_FADT;
+	table_desc->pointer     = ACPI_CAST_PTR (struct acpi_table_header, acpi_gbl_FADT);
 	table_desc->allocation  = ACPI_MEM_ALLOCATED;
 	table_desc->length      = sizeof (struct fadt_descriptor_rev2);
 
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbget.c linux-2.4.25-pre8/drivers/acpi/tables/tbget.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbget.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbget.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbgetall.c linux-2.4.25-pre8/drivers/acpi/tables/tbgetall.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbgetall.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbgetall.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbinstal.c linux-2.4.25-pre8/drivers/acpi/tables/tbinstal.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbinstal.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbinstal.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbrsdt.c linux-2.4.25-pre8/drivers/acpi/tables/tbrsdt.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbrsdt.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbrsdt.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -233,6 +233,15 @@
 			acpi_gbl_RSDP->rsdt_physical_address,
 			(void *) (acpi_native_uint) acpi_gbl_RSDP->rsdt_physical_address));
 
+		if (acpi_gbl_RSDP->revision < 2) {
+			ACPI_REPORT_ERROR (("Looking for RSDT (RSDP->Rev < 2)\n"))
+		}
+		else {
+			ACPI_REPORT_ERROR (("Looking for XSDT (RSDP->Rev >= 2)\n"))
+		}
+
+		ACPI_DUMP_BUFFER ((char *) table_ptr, 48);
+
 		return (AE_BAD_SIGNATURE);
 	}
 
@@ -305,7 +314,7 @@
 		return_ACPI_STATUS (status);
 	}
 
-	acpi_gbl_XSDT = (XSDT_DESCRIPTOR *) table_info.pointer;
+	acpi_gbl_XSDT = ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info.pointer);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
 	return_ACPI_STATUS (status);
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbutils.c linux-2.4.25-pre8/drivers/acpi/tables/tbutils.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbutils.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbutils.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbxface.c linux-2.4.25-pre8/drivers/acpi/tables/tbxface.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbxface.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbxface.c	2004-01-29 10:58:20.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/tables/tbxfroot.c linux-2.4.25-pre8/drivers/acpi/tables/tbxfroot.c
--- linux-2.4.25-pre7/drivers/acpi/tables/tbxfroot.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables/tbxfroot.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -241,11 +241,11 @@
 		/* Get the next table pointer, handle RSDT vs. XSDT */
 
 		if (acpi_gbl_RSDP->revision < 2) {
-			address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i];
+			address.pointer.value = (ACPI_CAST_PTR (RSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i];
 		}
 		else {
 			address.pointer.value =
-				((XSDT_DESCRIPTOR *) rsdt_info.pointer)->table_offset_entry[i];
+				(ACPI_CAST_PTR (XSDT_DESCRIPTOR, rsdt_info.pointer))->table_offset_entry[i];
 		}
 
 		/* Get the table header */
diff -urN linux-2.4.25-pre7/drivers/acpi/tables.c linux-2.4.25-pre8/drivers/acpi/tables.c
--- linux-2.4.25-pre7/drivers/acpi/tables.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/tables.c	2004-01-29 10:58:20.000000000 -0800
@@ -276,10 +276,17 @@
 
 	/* Map the DSDT header via the pointer in the FADT */
 	if (id == ACPI_DSDT) {
-		struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header;
+		struct fadt_descriptor_rev2 *fadt = (struct fadt_descriptor_rev2 *) *header;
+
+		if (fadt->revision == 3 && fadt->Xdsdt) {
+			*header = (void *) __acpi_map_table(fadt->Xdsdt,
+					sizeof(struct acpi_table_header));
+		} else if (fadt->V1_dsdt) {
+			*header = (void *) __acpi_map_table(fadt->V1_dsdt,
+					sizeof(struct acpi_table_header));
+		} else
+			*header = 0;
 
-		*header = (void *) __acpi_map_table(fadt->dsdt_addr,
-				sizeof(struct acpi_table_header));
 		if (!*header) {
 			printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
 			return -ENODEV;
diff -urN linux-2.4.25-pre7/drivers/acpi/thermal.c linux-2.4.25-pre8/drivers/acpi/thermal.c
--- linux-2.4.25-pre7/drivers/acpi/thermal.c	2004-01-29 10:58:17.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/thermal.c	2004-01-29 10:58:20.000000000 -0800
@@ -50,7 +50,7 @@
 MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-static int tzp = 0;
+static int tzp;
 MODULE_PARM(tzp, "i");
 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
 
@@ -704,7 +704,7 @@
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-struct proc_dir_entry		*acpi_thermal_dir = NULL;
+struct proc_dir_entry		*acpi_thermal_dir;
 
 
 static int
diff -urN linux-2.4.25-pre7/drivers/acpi/toshiba_acpi.c linux-2.4.25-pre8/drivers/acpi/toshiba_acpi.c
--- linux-2.4.25-pre7/drivers/acpi/toshiba_acpi.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/toshiba_acpi.c	2004-01-29 10:58:20.000000000 -0800
@@ -216,7 +216,7 @@
 	return status;
 }
 
-static struct proc_dir_entry*	toshiba_proc_dir = NULL;
+static struct proc_dir_entry*	toshiba_proc_dir;
 static int			force_fan;
 static int			last_key_event;
 static int			key_event_valid;
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utalloc.c linux-2.4.25-pre8/drivers/acpi/utilities/utalloc.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utalloc.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utalloc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utcopy.c linux-2.4.25-pre8/drivers/acpi/utilities/utcopy.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utcopy.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utcopy.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utdebug.c linux-2.4.25-pre8/drivers/acpi/utilities/utdebug.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utdebug.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utdebug.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utdelete.c linux-2.4.25-pre8/drivers/acpi/utilities/utdelete.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utdelete.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utdelete.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/uteval.c linux-2.4.25-pre8/drivers/acpi/utilities/uteval.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/uteval.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/uteval.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utglobal.c linux-2.4.25-pre8/drivers/acpi/utilities/utglobal.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utglobal.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utglobal.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utinit.c linux-2.4.25-pre8/drivers/acpi/utilities/utinit.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utinit.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utinit.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utmath.c linux-2.4.25-pre8/drivers/acpi/utilities/utmath.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utmath.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utmath.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utmisc.c linux-2.4.25-pre8/drivers/acpi/utilities/utmisc.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utmisc.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utmisc.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -304,16 +304,20 @@
 	u32                             name)
 {
 	char                            *name_ptr = (char *) &name;
-	u32                             i;
+	char                            character;
+	acpi_native_uint                i;
 
 
 	ACPI_FUNCTION_ENTRY ();
 
 
 	for (i = 0; i < ACPI_NAME_SIZE; i++) {
-		if (!((name_ptr[i] == '_') ||
-			  (name_ptr[i] >= 'A' && name_ptr[i] <= 'Z') ||
-			  (name_ptr[i] >= '0' && name_ptr[i] <= '9'))) {
+		character = *name_ptr;
+		name_ptr++;
+
+		if (!((character == '_') ||
+			  (character >= 'A' && character <= 'Z') ||
+			  (character >= '0' && character <= '9'))) {
 			return (FALSE);
 		}
 	}
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utobject.c linux-2.4.25-pre8/drivers/acpi/utilities/utobject.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utobject.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utobject.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/acpi/utilities/utxface.c linux-2.4.25-pre8/drivers/acpi/utilities/utxface.c
--- linux-2.4.25-pre7/drivers/acpi/utilities/utxface.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/acpi/utilities/utxface.c	2004-01-29 10:58:20.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/drivers/atm/horizon.c linux-2.4.25-pre8/drivers/atm/horizon.c
--- linux-2.4.25-pre7/drivers/atm/horizon.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.25-pre8/drivers/atm/horizon.c	2004-01-29 10:58:20.000000000 -0800
@@ -359,8 +359,8 @@
 
 static unsigned short debug = 0;
 static unsigned short vpi_bits = 0;
-static unsigned short max_tx_size = 9000;
-static unsigned short max_rx_size = 9000;
+static int max_tx_size = 9000;
+static int max_rx_size = 9000;
 static unsigned char pci_lat = 0;
 
 /********** access functions **********/
@@ -2919,11 +2919,11 @@
     PRINTK (KERN_ERR, "vpi_bits has been limited to %hu",
 	    vpi_bits = HRZ_MAX_VPI);
   
-  if (max_tx_size > TX_AAL5_LIMIT)
+  if (max_tx_size < 0 || max_tx_size > TX_AAL5_LIMIT)
     PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu",
 	    max_tx_size = TX_AAL5_LIMIT);
   
-  if (max_rx_size > RX_AAL5_LIMIT)
+  if (max_rx_size < 0 || max_rx_size > RX_AAL5_LIMIT)
     PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu",
 	    max_rx_size = RX_AAL5_LIMIT);
   
@@ -2938,8 +2938,8 @@
 MODULE_LICENSE("GPL");
 MODULE_PARM(debug, "h");
 MODULE_PARM(vpi_bits, "h");
-MODULE_PARM(max_tx_size, "h");
-MODULE_PARM(max_rx_size, "h");
+MODULE_PARM(max_tx_size, "i");
+MODULE_PARM(max_rx_size, "i");
 MODULE_PARM(pci_lat, "b");
 MODULE_PARM_DESC(debug, "debug bitmap, see .h file");
 MODULE_PARM_DESC(vpi_bits, "number of bits (0..4) to allocate to VPIs");
diff -urN linux-2.4.25-pre7/drivers/block/cpqarray.c linux-2.4.25-pre8/drivers/block/cpqarray.c
--- linux-2.4.25-pre7/drivers/block/cpqarray.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.25-pre8/drivers/block/cpqarray.c	2004-01-29 10:58:20.000000000 -0800
@@ -41,13 +41,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.28)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,28)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.28");
 MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -180,6 +180,7 @@
 
 static int deregister_disk(int ctlr, int logvol);
 static int register_new_disk(int cltr,int logvol);
+static int cpqarray_register_ctlr(int ctlr, int type);
 
 #ifdef CONFIG_PROC_FS
 static void ida_procinit(int i);
@@ -470,10 +471,111 @@
 	return 1;
 }
 
+static int cpqarray_register_ctlr(int ctlr, int type)
+{
+	request_queue_t *q;
+	int j;
+	
+	/*
+	 * register block devices
+	 * Find disks and fill in structs
+	 * Get an interrupt, set the Q depth and get into /proc
+	 */
+
+	/* If this successful it should insure that we are the only */
+	/* instance of the driver for this card */
+	if (register_blkdev(MAJOR_NR+ctlr, hba[ctlr]->devname, &ida_fops)) {
+		printk(KERN_ERR "cpqarray: Unable to get major number %d\n", MAJOR_NR+ctlr);
+		goto err_out;
+	}
+
+	hba[ctlr]->access.set_intr_mask(hba[ctlr], 0);
+	if (request_irq(hba[ctlr]->intr, do_ida_intr,
+		SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,
+		hba[ctlr]->devname, hba[ctlr])) {
+		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
+			hba[ctlr]->intr, hba[ctlr]->devname);
+		unregister_blkdev(MAJOR_NR+ctlr, hba[ctlr]->devname);
+		goto err_out;
+	}
+	hba[ctlr]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
+		hba[ctlr]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
+		&(hba[ctlr]->cmd_pool_dhandle));
+	hba[ctlr]->cmd_pool_bits = (__u32*)kmalloc(
+		((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+
+	if (hba[ctlr]->cmd_pool_bits == NULL || hba[ctlr]->cmd_pool == NULL) {
+		if (hba[ctlr]->cmd_pool_bits)
+			kfree(hba[ctlr]->cmd_pool_bits);
+		if (hba[ctlr]->cmd_pool)
+			pci_free_consistent(hba[ctlr]->pci_dev,
+				NR_CMDS * sizeof(cmdlist_t),
+				hba[ctlr]->cmd_pool,
+				hba[ctlr]->cmd_pool_dhandle);
+
+		free_irq(hba[ctlr]->intr, hba[ctlr]);
+		unregister_blkdev(MAJOR_NR+ctlr, hba[ctlr]->devname);
+		printk( KERN_ERR "cpqarray: out of memory");
+		goto err_out;
+	}
+	memset(hba[ctlr]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
+	memset(hba[ctlr]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
+	printk(KERN_INFO "cpqarray: Finding drives on %s", hba[ctlr]->devname);
+	getgeometry(ctlr);
+	start_fwbk(ctlr);
+
+	hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY);
+
+	ida_procinit(ctlr);
+
+	q = BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr);
+	q->queuedata = hba[ctlr];
+	blk_init_queue(q, do_ida_request);
+	if (type)
+		blk_queue_bounce_limit(q, hba[ctlr]->pci_dev->dma_mask);
+	blk_queue_headactive(q, 0);
+	blksize_size[MAJOR_NR+ctlr] = hba[ctlr]->blocksizes;
+	hardsect_size[MAJOR_NR+ctlr] = hba[ctlr]->hardsizes;
+	read_ahead[MAJOR_NR+ctlr] = READ_AHEAD;
+
+	q->back_merge_fn = cpq_back_merge_fn;
+	q->front_merge_fn = cpq_front_merge_fn;
+	q->merge_requests_fn = cpq_merge_requests_fn;
+
+	hba[ctlr]->gendisk.major = MAJOR_NR + ctlr;
+	hba[ctlr]->gendisk.major_name = "ida";
+	hba[ctlr]->gendisk.minor_shift = NWD_SHIFT;
+	hba[ctlr]->gendisk.max_p = IDA_MAX_PART;
+	hba[ctlr]->gendisk.part = hba[ctlr]->hd;
+	hba[ctlr]->gendisk.sizes = hba[ctlr]->sizes;
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
+	hba[ctlr]->gendisk.fops = &ida_fops;
+
+	/* Get on the disk list */
+	add_gendisk(&(hba[ctlr]->gendisk));
+
+	init_timer(&hba[ctlr]->timer);
+	hba[ctlr]->timer.expires = jiffies + IDA_TIMER;
+	hba[ctlr]->timer.data = (unsigned long)hba[ctlr];
+	hba[ctlr]->timer.function = ida_timer;
+	add_timer(&hba[ctlr]->timer);
+
+	ida_geninit(ctlr);
+	for(j=0; j<NWD; j++)
+		register_disk(&(hba[ctlr]->gendisk), MKDEV(MAJOR_NR+ctlr,j<<4),
+			IDA_MAX_PART, &ida_fops, hba[ctlr]->drv[j].nr_blks);
+	return(ctlr);
+
+err_out:
+	release_io_mem(hba[ctlr]);
+	free_hba(ctlr);
+	return (-1);
+}
+
+
 static int __init cpqarray_init_one( struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
-	request_queue_t *q;
         int i,j;
 
 
@@ -500,102 +602,7 @@
 		return (-1);
 	}
 			
-	/* 
-	 * register block devices
-	 * Find disks and fill in structs
-	 * Get an interrupt, set the Q depth and get into /proc
-	 */
-	
-	/* If this successful it should insure that we are the only */
-	/* instance of the driver */	
-	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
-        	printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
-                                MAJOR_NR+i);
-                release_io_mem(hba[i]);
-                free_hba(i);
-                return (-1);
-        }
-
-	
-	hba[i]->access.set_intr_mask(hba[i], 0);
-	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-				hba[i]->devname, hba[i])) {
-
-		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
-				hba[i]->intr, hba[i]->devname);
-		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
-		release_io_mem(hba[i]);
-                free_hba(i);
-                return (-1);
-	}
-	hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
-	hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), 
-				&(hba[i]->cmd_pool_dhandle));
-	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
-				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
-		
-	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
-		if(hba[i]->cmd_pool_bits)
-			kfree(hba[i]->cmd_pool_bits);
-		if(hba[i]->cmd_pool)
-			pci_free_consistent(hba[i]->pci_dev, 
-				NR_CMDS * sizeof(cmdlist_t), 
-				hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-		free_irq(hba[i]->intr, hba[i]);
-		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
-                printk( KERN_ERR "cpqarray: out of memory");
-		release_io_mem(hba[i]);
-                free_hba(i);
-                return (-1);
-	}
-	memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
-	memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
-	printk(KERN_INFO "cpqarray: Finding drives on %s", hba[i]->devname);
-	getgeometry(i);
-	start_fwbk(i); 
-
-	hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
-
-	ida_procinit(i);
-
-	q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
-	q->queuedata = hba[i];
-	blk_init_queue(q, do_ida_request);
-	blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
-	blk_queue_headactive(q, 0);
-	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
-	hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
-	read_ahead[MAJOR_NR+i] = READ_AHEAD;
-
-	q->back_merge_fn = cpq_back_merge_fn;
-	q->front_merge_fn = cpq_front_merge_fn;
-	q->merge_requests_fn = cpq_merge_requests_fn;
-
-	hba[i]->gendisk.major = MAJOR_NR + i;
-	hba[i]->gendisk.major_name = "ida";
-	hba[i]->gendisk.minor_shift = NWD_SHIFT;
-	hba[i]->gendisk.max_p = IDA_MAX_PART;
-	hba[i]->gendisk.part = hba[i]->hd;
-	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; 
-	hba[i]->gendisk.fops = &ida_fops;
-	
-		/* Get on the disk list */
-	add_gendisk(&(hba[i]->gendisk));
-
-	init_timer(&hba[i]->timer);
-	hba[i]->timer.expires = jiffies + IDA_TIMER;
-	hba[i]->timer.data = (unsigned long)hba[i];
-	hba[i]->timer.function = ida_timer;
-	add_timer(&hba[i]->timer);
-
-	ida_geninit(i);
-	for(j=0; j<NWD; j++)	
-		register_disk(&(hba[i]->gendisk), MKDEV(MAJOR_NR+i,j<<4),
-			IDA_MAX_PART, &ida_fops, hba[i]->drv[j].nr_blks);
-
-	return(i);
+	return (cpqarray_register_ctlr(i, 1));
 }
 static struct pci_driver cpqarray_pci_driver = {
         name:   "cpqarray",
@@ -616,7 +623,7 @@
 
 	/* detect controllers */
 	printk(DRIVER_NAME "\n");
-	pci_register_driver(&cpqarray_pci_driver);
+	pci_module_init(&cpqarray_pci_driver);
 	cpqarray_eisa_detect();
 
 	for(i=0; i< MAX_CTLR; i++) {
@@ -868,6 +875,11 @@
 
 		num_ctlr++;
 		i++;
+
+		if (cpqarray_register_ctlr(ctlr, 0) == -1)
+			printk(KERN_WARNING 
+				"cpqarray%d: Can't register EISA controller\n",
+				ctlr);
 	}
 
 	return num_ctlr;
@@ -1377,6 +1389,7 @@
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
+	case BLKSSZGET:
 	case BLKROSET:
 	case BLKROGET:
 	case BLKRASET:
diff -urN linux-2.4.25-pre7/drivers/char/alim7101_wdt.c linux-2.4.25-pre8/drivers/char/alim7101_wdt.c
--- linux-2.4.25-pre7/drivers/char/alim7101_wdt.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.25-pre8/drivers/char/alim7101_wdt.c	2004-01-29 10:58:20.000000000 -0800
@@ -209,7 +209,7 @@
 
 static int fop_close(struct inode * inode, struct file * file)
 {
-	if(wdt_expect_close)
+	if ((wdt_expect_close) || (! nowayout))
 		wdt_turnoff();
 	else {
 		printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
diff -urN linux-2.4.25-pre7/drivers/i2c/i2c-philips-par.c linux-2.4.25-pre8/drivers/i2c/i2c-philips-par.c
--- linux-2.4.25-pre7/drivers/i2c/i2c-philips-par.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/i2c/i2c-philips-par.c	2004-01-29 10:58:20.000000000 -0800
@@ -212,8 +212,8 @@
 
 	/* reset hardware to sane state */
 	parport_claim_or_block(adapter->pdev);
-	bit_lp_setsda(port, 1);
-	bit_lp_setscl(port, 1);
+	adapter->bit_lp_data.setsda(port, 1);
+	adapter->bit_lp_data.setscl(port, 1);
 	parport_release(adapter->pdev);
 
 	if (i2c_bit_add_bus(&adapter->adapter) < 0)
diff -urN linux-2.4.25-pre7/drivers/ide/Config.in linux-2.4.25-pre8/drivers/ide/Config.in
--- linux-2.4.25-pre7/drivers/ide/Config.in	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/ide/Config.in	2004-01-29 10:58:20.000000000 -0800
@@ -187,41 +187,6 @@
 ##  dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK
 ##fi
 
-if [ "$CONFIG_BLK_DEV_4DRIVES" = "y" -o \
-     "$CONFIG_BLK_DEV_ALI14XX" != "n" -o \
-     "$CONFIG_BLK_DEV_DTC2278" != "n" -o \
-     "$CONFIG_BLK_DEV_HT6560B" != "n" -o \
-     "$CONFIG_BLK_DEV_PDC4030" != "n" -o \
-     "$CONFIG_BLK_DEV_QD65XX" != "n" -o \
-     "$CONFIG_BLK_DEV_UMC8672" != "n" -o \
-     "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
-     "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
-     "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
-     "$CONFIG_BLK_DEV_CMD640" = "y" -o \
-     "$CONFIG_BLK_DEV_CMD64X" = "y" -o \
-     "$CONFIG_BLK_DEV_CS5530" = "y" -o \
-     "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
-     "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
-     "$CONFIG_BLK_DEV_HPT366" = "y" -o \
-     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
-     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
-     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" -o \
-     "$CONFIG_BLK_DEV_NFORCE" = "y" -o \
-     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
-     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
-     "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
-     "$CONFIG_BLK_DEV_PIIX" = "y" -o \
-     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
-     "$CONFIG_BLK_DEV_SIIMAGE" = "y" -o \
-     "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
-     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
-     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
-   define_bool CONFIG_BLK_DEV_IDE_MODES y
-else
-   define_bool CONFIG_BLK_DEV_IDE_MODES n
-fi
-
 dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
 dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
diff -urN linux-2.4.25-pre7/drivers/ide/raid/hptraid.c linux-2.4.25-pre8/drivers/ide/raid/hptraid.c
--- linux-2.4.25-pre7/drivers/ide/raid/hptraid.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/ide/raid/hptraid.c	2004-01-29 10:58:20.000000000 -0800
@@ -146,7 +146,7 @@
 	make_request:		hptraid01_make_request
 };
 
-static __init struct {
+static __initdata struct {
 	struct raid_device_operations *op;
 	u_int8_t type;
 	char label[8];
diff -urN linux-2.4.25-pre7/drivers/message/fusion/isense.c linux-2.4.25-pre8/drivers/message/fusion/isense.c
--- linux-2.4.25-pre7/drivers/message/fusion/isense.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/isense.c	2004-01-29 10:58:21.000000000 -0800
@@ -9,7 +9,7 @@
  *  Written By: Steven J. Ralston
  *  (yes I wrote some of the orig. code back in 1991!)
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: isense.c,v 1.34 2003/03/18 22:49:48 pdelaney Exp $
  */
diff -urN linux-2.4.25-pre7/drivers/message/fusion/linux_compat.h linux-2.4.25-pre8/drivers/message/fusion/linux_compat.h
--- linux-2.4.25-pre7/drivers/message/fusion/linux_compat.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/message/fusion/linux_compat.h	2004-01-29 10:58:21.000000000 -0800
@@ -11,6 +11,11 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+
+#if (defined(__sparc__) && defined(__sparc_v9__)) || defined(__x86_64__) || defined(__ia64__)
+#define MPT_CONFIG_COMPAT
+#endif
+
 #ifndef rwlock_init
 #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #endif
@@ -267,9 +272,9 @@
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_sync_irq(_irq) synchronize_irq(_irq)
+#define mpt_sync_irq(_irq) synchronize_irq(_irq)
 #else
-#define mptscsih_sync_irq(_irq) synchronize_irq()
+#define mpt_sync_irq(_irq) synchronize_irq()
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58)
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
  *           Name:  MPI.H
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI.H Version:  01.02.07
+ *    MPI.H Version:  01.02.10
  *
  *  Version History
  *  ---------------
@@ -48,6 +48,10 @@
  *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
  *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
  *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
+ *  11-15-02  01.02.08  Added define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX and
+ *                      obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX.
+ *  04-01-03  01.02.09  New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED
+ *  06-26-03  01.02.10  Bumped MPI_HEADER_VERSION_UNIT value.
  *  --------------------------------------------------------------------------
  */
 
@@ -76,7 +80,7 @@
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x09)
+#define MPI_HEADER_VERSION_UNIT             (0x0C)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
@@ -618,7 +622,8 @@
 
 #define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
 #define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
-#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)   /* obsolete */
+#define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX    (0x0062)
 #define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
 #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
 #define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
@@ -642,6 +647,7 @@
 #define MPI_IOCSTATUS_FC_RX_ID_INVALID          (0x0067)
 #define MPI_IOCSTATUS_FC_DID_INVALID            (0x0068)
 #define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT        (0x0069)
+#define MPI_IOCSTATUS_FC_EXCHANGE_CANCELED      (0x006C)
 
 /****************************************************************************/
 /*  LAN values                                                              */
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_cnfg.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_cnfg.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_cnfg.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_CNFG.H
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI_CNFG.H Version:  01.02.09
+ *    MPI_CNFG.H Version:  01.02.12
  *
  *  Version History
  *  ---------------
@@ -127,7 +127,24 @@
  *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
  *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
  *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
- *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  09-16-02 01.02.09   Added MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  11-15-02 01.02.10   Added ConnectedID defines for CONFIG_PAGE_SCSI_PORT_0.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_DEVICE_0.
+ *  04-01-03 01.02.11   Added RR_TOV field and additional Flags defines for
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added define MPI_FCPORTPAGE5_FLAGS_DISABLE to disable
+ *                      an alias.
+ *                      Added more device id defines.
+ *  06-26-03 01.02.12   Added MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID define.
+ *                      Added TargetConfig and IDConfig fields to
+ *                      CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added more PortFlags defines for CONFIG_PAGE_SCSI_PORT_2
+ *                      to control DV.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      In CONFIG_PAGE_FC_DEVICE_0, replaced Reserved1 field
+ *                      with ADISCHardALPA.
+ *                      Added MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY define.
  *  --------------------------------------------------------------------------
  */
 
@@ -281,6 +298,9 @@
 /****************************************************************************
 *   Manufacturing Config pages
 ****************************************************************************/
+#define MPI_MANUFACTPAGE_VENDORID_LSILOGIC          (0x1000)
+#define MPI_MANUFACTPAGE_VENDORID_TREBIA            (0x1783)
+
 #define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
@@ -299,6 +319,10 @@
 #define MPI_MANUFACTPAGE_DEVID_SA2020               (0x0806)
 #define MPI_MANUFACTPAGE_DEVID_SA2020ZC             (0x0807)
 
+#define MPI_MANUFACTPAGE_DEVID_SNP1000              (0x0010)
+#define MPI_MANUFACTPAGE_DEVID_SNP500               (0x0020)
+
+
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
 {
@@ -422,6 +446,7 @@
 #define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
 #define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
 #define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
+#define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID         (0x00000004)
 #define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
 
@@ -694,6 +719,10 @@
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD                (0x01)
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE                 (0x02)
 #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD                (0x03)
+#define MPI_SCSIPORTPAGE0_PHY_MASK_CONNECTED_ID         (0xFF000000)
+#define MPI_SCSIPORTPAGE0_PHY_SHIFT_CONNECTED_ID        (24)
+#define MPI_SCSIPORTPAGE0_PHY_BUS_FREE_CONNECTED_ID     (0xFE)
+#define MPI_SCSIPORTPAGE0_PHY_UNKNOWN_CONNECTED_ID      (0xFF)
 
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_1
@@ -701,14 +730,22 @@
     fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Configuration;              /* 04h */
     U32                     OnBusTimerValue;            /* 08h */
+    U8                      TargetConfig;               /* 0Ch */
+    U8                      Reserved1;                  /* 0Dh */
+    U16                     IDConfig;                   /* 0Eh */
 } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
   SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
 
 #define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x02)
 
+/* Configuration values */
 #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
 #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
 
+/* TargetConfig values */
+#define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY        (0x01)
+#define MPI_SCSIPORTPAGE1_TARGCONFIG_INIT_TARG        (0x02)
+
 
 typedef struct _MPI_DEVICE_INFO
 {
@@ -727,13 +764,20 @@
 } fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
   SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
 
-#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
+#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x02)
 
+/* PortFlags values */
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
 
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK                (0x00000060)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_FULL_DV                (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY          (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV                 (0x00000060)
+
+/* PortSettings values */
 #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK                 (0x0000000F)
 #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA                (0x00000030)
 #define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA             (0x00000000)
@@ -915,7 +959,7 @@
 
 #define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED      (0x00000010)
 #define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED       (0x00000020)
-#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000030)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000040)
 
 #define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK          (0x00000F00)
 #define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT            (0x00000000)
@@ -974,15 +1018,23 @@
     U8                      TopologyConfig;             /* 1Ah */
     U8                      AltConnector;               /* 1Bh */
     U8                      NumRequestedAliases;        /* 1Ch */
-    U8                      Reserved1;                  /* 1Dh */
+    U8                      RR_TOV;                     /* 1Dh */
     U16                     Reserved2;                  /* 1Eh */
 } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
   FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
 
-#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x04)
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x05)
 
 #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
 #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
+#define MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS  (0x02000000)
+#define MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS     (0x01000000)
+#define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID          (0x00800000)
+#define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE              (0x00400000)
+#define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS         (0x00000070)
+#define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG         (0x00000008)
+#define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO             (0x00000004)
+#define MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS           (0x00000002)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
 
@@ -993,6 +1045,11 @@
 #define MPI_FCPORTPAGE1_FLAGS_PROT_LAN                  ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
 #define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR           ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
 
+#define MPI_FCPORTPAGE1_FLAGS_NONE_RR_TOV_UNITS         (0x00000000)
+#define MPI_FCPORTPAGE1_FLAGS_THOUSANDTH_RR_TOV_UNITS   (0x00000010)
+#define MPI_FCPORTPAGE1_FLAGS_TENTH_RR_TOV_UNITS        (0x00000030)
+#define MPI_FCPORTPAGE1_FLAGS_TEN_RR_TOV_UNITS          (0x00000050)
+
 #define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED              (0xFF)
 
 #define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK              (0x0F)
@@ -1108,12 +1165,13 @@
 } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
   FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
 
-#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x01)
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x02)
 
 #define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED             (0x01)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA                 (0x02)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN                 (0x04)
 #define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN                 (0x08)
+#define MPI_FCPORTPAGE5_FLAGS_DISABLE                   (0x10)
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
@@ -1322,7 +1380,7 @@
     U8                      Flags;                      /* 19h */
     U16                     BBCredit;                   /* 1Ah */
     U16                     MaxRxFrameSize;             /* 1Ch */
-    U8                      Reserved1;                  /* 1Eh */
+    U8                      ADISCHardALPA;              /* 1Eh */
     U8                      PortNumber;                 /* 1Fh */
     U8                      FcPhLowestVersion;          /* 20h */
     U8                      FcPhHighestVersion;         /* 21h */
@@ -1331,13 +1389,16 @@
 } fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
   FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
 
-#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x02)
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x03)
 
 #define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID    (0x01)
+#define MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID         (0x02)
+#define MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID          (0x04)
 
 #define MPI_FC_DEVICE_PAGE0_PROT_IP                     (0x01)
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
 #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY              (0x08)
 
 #define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK      (MPI_FC_DEVICE_PGAD_PORT_MASK)
 #define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK      (MPI_FC_DEVICE_PGAD_FORM_MASK)
@@ -1348,6 +1409,7 @@
 #define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT      (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
 #define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK       (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
 
+#define MPI_FC_DEVICE_PAGE0_HARD_ALPA_UNKNOWN   (0xFF)
 
 /****************************************************************************
 *   RAID Volume Config Pages
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_init.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_init.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_init.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_init.h	2004-01-29 10:58:21.000000000 -0800
@@ -6,7 +6,7 @@
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI_INIT.H Version:  01.02.05
+ *    MPI_INIT.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -31,6 +31,8 @@
  *  10-04-01  01.02.04  Added defines for SEP request Action field.
  *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
  *                      for SCSI IO requests.
+ *  11-15-02  01.02.06  Added special extended SCSI Status defines for FCP.
+ *  06-26-03  01.02.07  Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define.
  *  --------------------------------------------------------------------------
  */
 
@@ -153,6 +155,10 @@
 #define MPI_SCSI_STATUS_TASK_SET_FULL           (0x28)
 #define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
 
+#define MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT    (0x80)
+#define MPI_SCSI_STATUS_FCPEXT_NO_LINK              (0x81)
+#define MPI_SCSI_STATUS_FCPEXT_UNASSIGNED           (0x82)
+
 
 /* SCSI IO Reply SCSIState values */
 
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_ioc.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_ioc.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_ioc.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_IOC.H
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI_IOC.H Version:  01.02.06
+ *    MPI_IOC.H Version:  01.02.08
  *
  *  Version History
  *  ---------------
@@ -55,6 +55,8 @@
  *  05-31-02  01.02.06  Added define for
  *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
  *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
+ *  04-01-03  01.02.07  Added defines for MPI_FW_HEADER_SIGNATURE_.
+ *  06-26-03  01.02.08  Added new values to the product family defines.
  *  --------------------------------------------------------------------------
  */
 
@@ -654,6 +656,10 @@
 #define MPI_FW_HEADER_PID_TYPE_SCSI             (0x0000)
 #define MPI_FW_HEADER_PID_TYPE_FC               (0x1000)
 
+#define MPI_FW_HEADER_SIGNATURE_0               (0x5AEAA55A)
+#define MPI_FW_HEADER_SIGNATURE_1               (0xA55AEAA5)
+#define MPI_FW_HEADER_SIGNATURE_2               (0x5AA55AEA)
+
 #define MPI_FW_HEADER_PID_PROD_MASK                     (0x0F00)
 #define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI           (0x0100)
 #define MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI    (0x0200)
@@ -673,6 +679,8 @@
 #define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI    (0x0008)
 #define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI    (0x0009)
 #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI    (0x000A)
+#define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI   (0x000B)
+#define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI   (0x000C)
 #define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
 #define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
 #define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_raid.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_raid.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_raid.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001-2002 LSI Logic Corporation.
+ *  Copyright (c) 2001-2003 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_RAID.H
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    MPI_RAID.H Version:  01.02.07
+ *    MPI_RAID.H Version:  01.02.09
  *
  *  Version History
  *  ---------------
@@ -25,6 +25,9 @@
  *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
  *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
  *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
+ *  11-15-02  01.02.08  Added missing MsgContext field to MSG_MAILBOX_REQUEST.
+ *  04-01-03  01.02.09  New action data option flag for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME.
  *  --------------------------------------------------------------------------
  */
 
@@ -90,6 +93,9 @@
 #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
 #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
 
+#define MPI_RAID_ACTION_ADATA_KEEP_LBA0             (0x00000000)
+#define MPI_RAID_ACTION_ADATA_ZERO_LBA0             (0x00000002)
+
 /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
 
@@ -195,6 +201,7 @@
     U16                     Reserved2;
     U8                      Reserved3;
     U8                      MsgFlags;
+    U32                     MsgContext;
     U8                      Command[10];
     U16                     Reserved4;
     SGE_IO_UNION            SGL;
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_targ.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_targ.h	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_targ.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *  Copyright (c) 2000-2003 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_TARG.H
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI_TARG.H Version:  01.02.07
+ *    MPI_TARG.H Version:  01.02.09
  *
  *  Version History
  *  ---------------
@@ -41,6 +41,8 @@
  *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
  *  09-16-02  01.02.07  Added flags for confirmed completion.
  *                      Added PRIORITY_REASON_TARGET_BUSY.
+ *  11-15-02  01.02.08  Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER.
+ *  04-01-03  01.02.09  Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER.
  *  --------------------------------------------------------------------------
  */
 
@@ -171,7 +173,7 @@
     U32     FcpDl;                                      /* 1Ch */
     U8      AliasIndex;                                 /* 20h */
     U8      Reserved1;                                  /* 21h */
-    U16     Reserved2;                                  /* 22h */
+    U16     OptionalOxid;                               /* 22h */
 } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
   MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
 
@@ -190,6 +192,10 @@
     U8      TaskManagementFlags;                        /* 12h */
     U8      AdditionalCDBLength;                        /* 13h */
     U8      CDB[16];                                    /* 14h */
+    /* Alias ID */
+    U8      AliasID;                                    /* 24h */
+    U8      Reserved1;                                  /* 25h */
+    U16     Reserved2;                                  /* 26h */
 } MPI_TARGET_SCSI_SPI_CMD_BUFFER,
   MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
   MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
diff -urN linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_tool.h linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_tool.h
--- linux-2.4.25-pre7/drivers/message/fusion/lsi/mpi_tool.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/drivers/message/fusion/lsi/mpi_tool.h	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,129 @@
+/*
+ *  Copyright (c) 2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TOOL.H
+ *          Title:  MPI Toolbox structures and definitions
+ *  Creation Date:  July 30, 2001
+ *
+ *    MPI Version:  01.02.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  08-08-01  01.02.01  Original release.
+ *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TOOL_H
+#define MPI_TOOL_H
+
+#define MPI_TOOLBOX_CLEAN_TOOL                      (0x00)
+#define MPI_TOOLBOX_MEMORY_MOVE_TOOL                (0x01)
+#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL           (0x02)
+
+
+/****************************************************************************/
+/* Toolbox reply                                                            */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_REPLY
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved3;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY,
+  ToolboxReply_t, MPI_POINTER pToolboxReply_t;
+
+
+/****************************************************************************/
+/* Toolbox Clean Tool request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_CLEAN_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST,
+  ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t;
+
+#define MPI_TOOLBOX_CLEAN_NVSRAM                    (0x00000001)
+#define MPI_TOOLBOX_CLEAN_SEEPROM                   (0x00000002)
+#define MPI_TOOLBOX_CLEAN_FLASH                     (0x00000004)
+
+
+/****************************************************************************/
+/* Toolbox Memory Move request                                              */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    SGE_SIMPLE_UNION        SGL;                        /* 0Ch */
+} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST,
+  ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t;
+
+
+/****************************************************************************/
+/* Toolbox Diagnostic Data Upload request                                   */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Flags;                      /* 0Ch */
+    U32                     Reserved3;                  /* 10h */
+    SGE_SIMPLE_UNION        SGL;                        /* 14h */
+} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t;
+
+typedef struct _DIAG_DATA_UPLOAD_HEADER
+{
+    U32                     DiagDataLength;             /* 00h */
+    U8                      FormatCode;                 /* 04h */
+    U8                      Reserved;                   /* 05h */
+    U16                     Reserved1;                  /* 06h */
+} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER,
+  DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t;
+
+#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1            (0x01)
+#define MPI_TB_DIAG_FORMAT_SCSI_2                   (0x02)
+#define MPI_TB_DIAG_FORMAT_SCSI_3                   (0x03)
+#define MPI_TB_DIAG_FORMAT_FC_TRACE_1               (0x04)
+
+
+#endif
+
+
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptbase.c linux-2.4.25-pre8/drivers/message/fusion/mptbase.c
--- linux-2.4.25-pre7/drivers/message/fusion/mptbase.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptbase.c	2004-01-29 10:58:21.000000000 -0800
@@ -47,7 +47,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptbase.c,v 1.130 2003/05/07 14:08:30 pdelaney Exp $
  */
@@ -211,6 +211,7 @@
 static int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
 static int	mpt_findImVolumes(MPT_ADAPTER *ioc);
 static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
+static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
 static void	mpt_timer_expired(unsigned long data);
 static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
@@ -319,14 +320,14 @@
 	MPT_FRAME_HDR	*mf;
 	MPT_FRAME_HDR	*mr;
 	u32		 pa;
-	int		 req_idx = -1;
+	int		 req_idx;
 	int		 cb_idx;
 	int		 type;
 	int		 freeme;
-	int		 count = 0;
 
 	ioc = bus_id;
 
+#ifdef MPT_DEBUG_IRQ
 	/*
 	 * Verify ioc pointer is ok
 	 */
@@ -341,6 +342,7 @@
 			return;
 		}
 	}
+#endif
 
 	/*
 	 *  Drain the reply FIFO!
@@ -493,17 +495,7 @@
 			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 		}
 
-		count++;
-		dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count));
 		mb();
-
-		if (count >= MPT_MAX_REPLIES_PER_ISR) {
-			dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
-					ioc->name, count));
-			dirqprintk((" Giving this ISR a break!\n"));
-			return;
-		}
-
 	}	/* drain reply FIFO */
 }
 
@@ -814,7 +806,7 @@
 MPT_FRAME_HDR*
 mpt_get_msg_frame(int handle, int iocid)
 {
-	MPT_FRAME_HDR *mf = NULL;
+	MPT_FRAME_HDR *mf;
 	MPT_ADAPTER *iocp;
 	unsigned long flags;
 
@@ -846,6 +838,8 @@
 		iocp->mfcnt++;
 #endif
 	}
+	else
+		mf = NULL;
 	spin_unlock_irqrestore(&iocp->FreeQlock, flags);
 
 #ifdef MFCNT
@@ -1114,10 +1108,12 @@
 MPT_ADAPTER *
 mpt_adapter_find_first(void)
 {
-	MPT_ADAPTER *this = NULL;
+	MPT_ADAPTER *this;
 
 	if (! Q_IS_EMPTY(&MptAdapters))
 		this = MptAdapters.head;
+	else
+		this = NULL;
 
 	return this;
 }
@@ -1132,10 +1128,12 @@
 MPT_ADAPTER *
 mpt_adapter_find_next(MPT_ADAPTER *prev)
 {
-	MPT_ADAPTER *next = NULL;
+	MPT_ADAPTER *next;
 
 	if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
 		next = prev->forw;
+	else
+		next = NULL;
 
 	return next;
 }
@@ -1285,7 +1283,11 @@
 	if (pci_enable_device(pdev))
 		return r;
 
-	if (!pci_set_dma_mask(pdev, mask)) {
+	/* For some kernels, broken kernel limits memory allocation for target mode
+	 * driver. Shirron. Fixed in 2.4.20-8
+	 * if ((sizeof(dma_addr_t) == sizeof(u64)) && (!pci_set_dma_mask(pdev, mask))) {
+	 */
+	if ((!pci_set_dma_mask(pdev, mask))) {
 		dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
 	} else {
 		if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
@@ -1300,10 +1302,10 @@
 		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
 		return -ENOMEM;
 	}
-	memset(ioc, 0, sizeof(*ioc));
+	memset(ioc, 0, sizeof(MPT_ADAPTER));
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
-	ioc->reply_sz = ioc->req_sz;
+	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 
 	ioc->pcidev = pdev;
 	ioc->diagPending = 0;
@@ -1419,13 +1421,12 @@
 		ioc->prod_name = "LSIFC929X";
 		{
 			/* 929X Chip Fix. Set Split transactions level
-			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 * for PCIX. Set MOST bits to zero.
 			 */
-			u16 pcixcmd = 0;
-			pci_read_config_word(pdev, 0x6a, &pcixcmd);
-			pcixcmd &= 0xFF9F;
-			pcixcmd |= 0x0010;
-			pci_write_config_word(pdev, 0x6a, pcixcmd);
+			u8 pcixcmd;
+			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0x8F;
+			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
@@ -1433,13 +1434,12 @@
 		ioc->prod_name = "LSIFC919X";
 		{
 			/* 919X Chip Fix. Set Split transactions level
-			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 * for PCIX. Set MOST bits to zero.
 			 */
-			u16 pcixcmd = 0;
-			pci_read_config_word(pdev, 0x6a, &pcixcmd);
-			pcixcmd &= 0xFF9F;
-			pcixcmd |= 0x0010;
-			pci_write_config_word(pdev, 0x6a, pcixcmd);
+			u8 pcixcmd;
+			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0x8F;
+			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
@@ -1449,14 +1449,14 @@
 			u8 revision;
 
 			/* 1030 Chip Fix. Disable Split transactions
-			 * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8)
+			 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
 			 */
 			pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 			if (revision < 0x08) {
-				u16 pcixcmd = 0;
-				pci_read_config_word(pdev, 0x6a, &pcixcmd);
-				pcixcmd &= 0xFF8F;
-				pci_write_config_word(pdev, 0x6a, pcixcmd);
+				u8 pcixcmd;
+				pci_read_config_byte(pdev, 0x6a, &pcixcmd);
+				pcixcmd &= 0x8F;
+				pci_write_config_byte(pdev, 0x6a, pcixcmd);
 			}
 		}
 	}
@@ -1764,6 +1764,8 @@
 			/* Check, and possibly reset, the coalescing value
 			 */
 			mpt_read_ioc_pg_1(ioc);
+
+			mpt_read_ioc_pg_4(ioc);
 		}
 
 		GetIoUnitPage2(ioc);
@@ -1950,6 +1952,15 @@
 			kfree(this->spi_data.pIocPg3);
 			this->spi_data.pIocPg3 = NULL;
 		}
+
+		if (freeup && this->spi_data.pIocPg4 != NULL) {
+			sz = this->spi_data.IocPg4Sz;
+			pci_free_consistent(this->pcidev, sz, 
+				this->spi_data.pIocPg4,
+				this->spi_data.IocPg4_dma);
+			this->spi_data.pIocPg4 = NULL;
+			this->alloc_total -= sz;
+		}
 	}
 }
 
@@ -2346,7 +2357,7 @@
 			 */
 			ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
 			ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
-			ioc->reply_sz = ioc->req_sz;
+			ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 			ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
 			dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
@@ -2609,8 +2620,8 @@
 void *
 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
 {
-	fw_image_t	**cached_fw = NULL;
-	u8		*mem = NULL;
+	fw_image_t	**cached_fw;
+	u8		*mem;
 	dma_addr_t	fw_dma;
 	int		alloc_total = 0;
 	int		bytes_left, bytes, num_frags;
@@ -2758,7 +2769,7 @@
 	u8			 reply[sizeof(FWUploadReply_t)];
 	FWUpload_t		*prequest;
 	FWUploadReply_t		*preply;
-	FWUploadTCSGE_t		*ptcsge = NULL;
+	FWUploadTCSGE_t		*ptcsge;
 	int			 sgeoffset;
 	int			 ii, sz, reply_sz;
 	int			 cmdStatus, freeMem = 0;
@@ -2890,16 +2901,16 @@
 static int
 mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 {
-	MpiFwHeader_t		*FwHdr = NULL;
+	MpiFwHeader_t		*FwHdr;
 	MpiExtImageHeader_t 	*ExtHdr;
-	fw_image_t		**pCached = NULL;
+	fw_image_t		**pCached;
 	int			 fw_sz;
 	u32			 diag0val;
 #ifdef MPT_DEBUG
 	u32			 diag1val = 0;
 #endif
 	int			 count = 0;
-	u32			*ptru32 = NULL;
+	u32			*ptru32;
 	u32			 diagRwData;
 	u32			 nextImage;
 	u32			 ext_offset;
@@ -4301,7 +4312,7 @@
 static int
 mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 {
-	u8			*pbuf = NULL;
+	u8			*pbuf;
 	dma_addr_t		 buf_dma;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4387,7 +4398,6 @@
 			}
 			if (pbuf) {
 				pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-				pbuf = NULL;
 			}
 		}
 	}
@@ -4424,6 +4434,8 @@
 				/* Save the Port Page 2 data
 				 * (reformat into a 32bit quantity)
 				 */
+				data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
+				ioc->spi_data.PortFlags = data;
 				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
 					pdevice = &pPP2->DeviceSettings[ii];
 					data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
@@ -4433,7 +4445,6 @@
 			}
 
 			pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-			pbuf = NULL;
 		}
 	}
 
@@ -4509,8 +4520,8 @@
 static int
 mpt_findImVolumes(MPT_ADAPTER *ioc)
 {
-	IOCPage2_t		*pIoc2 = NULL;
-	ConfigPageIoc2RaidVol_t	*pIocRv = NULL;
+	IOCPage2_t		*pIoc2;
+	ConfigPageIoc2RaidVol_t	*pIocRv;
 	dma_addr_t		 ioc2_dma;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4587,10 +4598,7 @@
 	}
 
 done_and_free:
-	if (pIoc2) {
-		pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
-		pIoc2 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
 
 	return rc;
 }
@@ -4598,7 +4606,7 @@
 int
 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 {
-	IOCPage3_t		*pIoc3 = NULL;
+	IOCPage3_t		*pIoc3;
 	u8			*mem;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
@@ -4651,18 +4659,66 @@
 		}
 	}
 
-	if (pIoc3) {
-		pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
-		pIoc3 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
 
 	return 0;
 }
 
 static void
+mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
+{
+	IOCPage4_t		*pIoc4;
+	CONFIGPARMS		 cfg;
+	ConfigPageHeader_t	 header;
+	dma_addr_t		 ioc4_dma;
+	int			 iocpage4sz;
+
+	/* Read and save IOC Page 4
+	 */
+	header.PageVersion = 0;
+	header.PageLength = 0;
+	header.PageNumber = 4;
+	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+	cfg.hdr = &header;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	if (mpt_config(ioc, &cfg) != 0)
+		return;
+
+	if (header.PageLength == 0)
+		return;
+
+	if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
+		iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
+		pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
+		if (!pIoc4)
+			return;
+	} else {
+		ioc4_dma = ioc->spi_data.IocPg4_dma;
+		iocpage4sz = ioc->spi_data.IocPg4Sz;
+	}
+
+	/* Read the Page into dma memory.
+	 */
+	cfg.physAddr = ioc4_dma;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	if (mpt_config(ioc, &cfg) == 0) {
+		ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
+		ioc->spi_data.IocPg4_dma = ioc4_dma;
+		ioc->spi_data.IocPg4Sz = iocpage4sz;
+	} else {
+		pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
+		ioc->spi_data.pIocPg4 = NULL;
+	}
+}
+
+static void
 mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
 {
-	IOCPage1_t		*pIoc1 = NULL;
+	IOCPage1_t		*pIoc1;
 	CONFIGPARMS		 cfg;
 	ConfigPageHeader_t	 header;
 	dma_addr_t		 ioc1_dma;
@@ -4738,10 +4794,7 @@
 		}
 	}
 
-	if (pIoc1) {
-		pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
-		pIoc1 = NULL;
-	}
+	pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
 
 	return;
 }
@@ -5428,7 +5481,7 @@
 	int		 rc;
 	unsigned long	 flags;
 
-	dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
 	printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
 	printk("MF count 0x%x !\n", ioc->mfcnt);
@@ -5460,11 +5513,11 @@
 
 		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 			if (MptResetHandlers[ii]) {
-				dprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+				dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
 						ioc->name, ii));
 				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
 				if (ioc->alt_ioc) {
-					dprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+					dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
 							ioc->name, ioc->alt_ioc->name, ii));
 					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
 				}
@@ -5486,7 +5539,7 @@
 		ioc->alt_ioc->diagPending = 0;
 	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-	dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
 
 	return rc;
 }
@@ -5495,7 +5548,7 @@
 static char *
 EventDescriptionStr(u8 event, u32 evData0)
 {
-	char *ds = NULL;
+	char *ds;
 
 	switch(event) {
 	case MPI_EVENT_NONE:
@@ -6001,7 +6054,7 @@
 fusion_exit(void)
 {
 	MPT_ADAPTER *this;
-	struct pci_dev *pdev = NULL;
+	struct pci_dev *pdev;
 
 	dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
 
@@ -6021,7 +6074,7 @@
 		this->active = 0;
 
 		pdev = (struct pci_dev *)this->pcidev;
-		mptscsih_sync_irq(pdev->irq);
+		mpt_sync_irq(pdev->irq);
 
 		/* Clear any lingering interrupt */
 		CHIPREG_WRITE32(&this->chip->IntStatus, 0);
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptbase.h linux-2.4.25-pre8/drivers/message/fusion/mptbase.h
--- linux-2.4.25-pre7/drivers/message/fusion/mptbase.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptbase.h	2004-01-29 10:58:21.000000000 -0800
@@ -11,7 +11,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptbase.h,v 1.149 2003/05/07 14:08:31 pdelaney Exp $
  */
@@ -77,11 +77,11 @@
 #endif
 
 #ifndef COPYRIGHT
-#define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
+#define COPYRIGHT	"Copyright (c) 1999-2003 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.05.05+"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.05.05+"
+#define MPT_LINUX_VERSION_COMMON	"2.05.11.01"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.05.11.01"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -96,7 +96,7 @@
 #define MPT_MAX_BUS			1	/* Do not change */
 #define MPT_MAX_FC_DEVICES		255
 #define MPT_MAX_SCSI_DEVICES		16
-#define MPT_LAST_LUN			31
+#define MPT_LAST_LUN			255
 #define MPT_SENSE_BUFFER_ALLOC		64
 	/* allow for 256 max sense alloc, but only 255 max request */
 #if MPT_SENSE_BUFFER_ALLOC >= 256
@@ -127,6 +127,8 @@
 #define  MPT_MAX_FRAME_SIZE		128
 #define  MPT_DEFAULT_FRAME_SIZE		128
 
+#define  MPT_REPLY_FRAME_SIZE		0x40  /* Must be a multiple of 8 */
+
 #define  MPT_SG_REQ_128_SCALE		1
 #define  MPT_SG_REQ_96_SCALE		2
 #define  MPT_SG_REQ_64_SCALE		4
@@ -245,6 +247,7 @@
 		MPIHeader_t		hdr;
 		SCSIIORequest_t		scsireq;
 		SCSIIOReply_t		sreply;
+		ConfigReply_t		configreply;
 		MPIDefaultReply_t	reply;
 		MPT_FRAME_TRACKER	frame;
 	} u;
@@ -398,12 +401,9 @@
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
 	u32			 num_luns;
-//--- LUN split here?
-	u32			 luns;		/* Max LUNs is 32 */
-	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
-	u8			 pad0[4];
-	u8			 inq00_data[20];
-	u8			 pad1[4];
+	u32			 luns[8];		/* Max LUNs is 256 */
+	u8			 pad[4];
+	u8			 inq_data[8];
 		/* IEEE Registered Extended Identifier
 		   obtained via INQUIRY VPD page 0x83 */
 		/* NOTE: Do not separate uniq_prepad and uniq_data
@@ -411,11 +411,6 @@
 	u8			 uniq_prepad[8];
 	u8			 uniq_data[20];
 	u8			 pad2[4];
-	u8			 inqC3_data[12];
-	u8			 pad3[4];
-	u8			 inqC9_data[12];
-	u8			 pad4[4];
-	u8			 dev_vol_name[64];
 } VirtDevice;
 
 /*
@@ -430,6 +425,7 @@
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
 #define MPT_TARGET_FLAGS_Q_YES		0x08
 #define MPT_TARGET_FLAGS_VALID_56	0x10
+#define MPT_TARGET_FLAGS_SAF_TE_ISSUED	0x20
 #endif
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
@@ -529,8 +525,12 @@
 /* #define MPT_SCSICFG_BLK_NEGO		0x10	   WriteSDP1 with WDTR and SDTR disabled */
 
 typedef	struct _ScsiCfgData {
+	u32		 PortFlags;
 	int		*nvram;			/* table of device NVRAM values */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
+	IOCPage4_t	*pIocPg4;		/* SEP devices addressing */
+	dma_addr_t	 IocPg4_dma;		/* Phys Addr of IOCPage4 data */
+	int		 IocPg4Sz;		/* IOCPage4 size */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
@@ -544,7 +544,8 @@
 	u8		 dvScheduled;		/* 1 if scheduled */
 	u8		 forceDv;		/* 1 to force DV scheduling */
 	u8		 noQas;			/* Disable QAS for this adapter */
-	u8		 rsvd[2];
+	u8		 Saf_Te;		/* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */
+	u8		 rsvd[1];
 } ScsiCfgData;
 
 typedef struct _fw_image {
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptctl.c linux-2.4.25-pre8/drivers/message/fusion/mptctl.c
--- linux-2.4.25-pre7/drivers/message/fusion/mptctl.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptctl.c	2004-01-29 10:58:21.000000000 -0800
@@ -32,7 +32,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston, Noah Romer
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptctl.c,v 1.66 2003/05/07 14:08:32 pdelaney Exp $
  */
@@ -208,14 +208,6 @@
 		return -EBUSY;
 	}
 
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
-	if (!nonblock) {
-		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
-			rc = -ERESTARTSYS;
-	} else {
-		rc = -EPERM;
-	}
-#else
 	if (nonblock) {
 		if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
 			rc = -EAGAIN;
@@ -223,7 +215,6 @@
 		if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
 			rc = -ERESTARTSYS;
 	}
-#endif
 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
 	return rc;
 }
@@ -1275,10 +1266,10 @@
 	/* Fill in the data and return the structure to the calling
 	 * program
 	 */
-	if (ioc->chip_type == C1030)
-		karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
-	else
+	if ((int)ioc->chip_type <= (int) FC929)
 		karg.adapterType = MPT_IOCTL_INTERFACE_FC;
+	else
+		karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
 
 	port = karg.hdr.port;
 
@@ -1329,6 +1320,7 @@
 	/* Set the Version Strings.
 	 */
 	strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
+	karg.driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0';
 
 	karg.busChangeEvent = 0;
 	karg.hostId = ioc->pfacts[port].PortSCSIID;
@@ -1369,7 +1361,8 @@
 	int			iocnum;
 	int			numDevices = 0;
 	unsigned int		max_id;
-	int			ii, jj, lun;
+	int			ii, jj, indexed_lun, lun_index;
+	u32			lun;
 	int			maxWordsLeft;
 	int			numBytes;
 	u8			port;
@@ -1443,8 +1436,10 @@
 			while (ii <= max_id) {
 				if (hd->Targets[ii]) {
 					for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
-						lun = (1 << jj);
-						if (hd->Targets[ii]->luns & lun) {
+						lun_index = (jj >> 5);
+						indexed_lun = (jj % 32);
+						lun = (1 << indexed_lun);
+						if (hd->Targets[ii]->luns[lun_index] & lun) {
 							numDevices++;
 							*pdata = (jj << 16) | ii;
 							--maxWordsLeft;
@@ -1529,7 +1524,9 @@
 	karg.chip_type = ioc->chip_type;
 #endif
 	strncpy (karg.name, ioc->name, MPT_MAX_NAME);
+	karg.name[MPT_MAX_NAME-1]='\0';
 	strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
+	karg.product[MPT_PRODUCT_LENGTH-1]='\0';
 
 	/* Copy the data from kernel memory to user memory
 	 */
@@ -1950,6 +1947,8 @@
 			 */
 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+			else
+				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
 
 			pScsiReq->SenseBufferLowAddr =
 				cpu_to_le32(ioc->sense_buf_low_dma
@@ -2011,6 +2010,8 @@
 			 */
 			if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
 				pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+			else
+				pScsiReq->SenseBufferLength = karg.maxSenseBytes;
 
 			pScsiReq->SenseBufferLowAddr =
 				cpu_to_le32(ioc->sense_buf_low_dma
@@ -2471,8 +2472,10 @@
 				cfg.physAddr = buf_dma;
 				if (mpt_config(ioc, &cfg) == 0) {
 					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
-					if (strlen(pdata->BoardTracerNumber) > 1)
+					if (strlen(pdata->BoardTracerNumber) > 1) {
 						strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
+						karg.serial_number[24-1]='\0';
+					}
 				}
 				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
 				pbuf = NULL;
@@ -2705,10 +2708,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
-
-/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
+#ifdef MPT_CONFIG_COMPAT
 extern int register_ioctl32_conversion(unsigned int cmd,
 				       int (*handler)(unsigned int,
 						      unsigned int,
@@ -2718,14 +2718,14 @@
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* sparc32_XXX functions are used to provide a conversion between
+/* compat_XXX functions are used to provide a conversion between
  * pointers and u32's. If the arg does not contain any pointers, then
- * a specialized function (sparc32_XXX) is not needed. If the arg
+ * a specialized function (compat_XXX) is not needed. If the arg
  * does contain pointer(s), then the specialized function is used
  * to ensure the structure contents is properly processed by mptctl.
  */
 static int
-sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
 			unsigned long arg, struct file *filp)
 {
 	struct mpt_fw_xfer32 kfw32;
@@ -2735,7 +2735,7 @@
 	int nonblock = (filp->f_flags & O_NONBLOCK);
 	int ret;
 
-	dctlprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+	dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n"));
 
 	if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
 		return -EFAULT;
@@ -2744,7 +2744,7 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dctlprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -2764,7 +2764,7 @@
 }
 
 static int
-sparc32_mpt_command(unsigned int fd, unsigned int cmd,
+compat_mpt_command(unsigned int fd, unsigned int cmd,
 			unsigned long arg, struct file *filp)
 {
 	struct mpt_ioctl_command32 karg32;
@@ -2775,7 +2775,7 @@
 	int nonblock = (filp->f_flags & O_NONBLOCK);
 	int ret;
 
-	dctlprintk((KERN_INFO MYNAM "::sparc32_mpt_command() called\n"));
+	dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n"));
 
 	if (copy_from_user(&karg32, (char *)arg, sizeof(karg32)))
 		return -EFAULT;
@@ -2784,7 +2784,7 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -2817,8 +2817,7 @@
 	return ret;
 }
 
-#endif		/*} linux >= 2.3.x */
-#endif		/*} sparc */
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int __init mptctl_init(void)
@@ -2864,35 +2863,33 @@
 		}
 	}
 
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
-	err = register_ioctl32_conversion(MPTIOCINFO, NULL);
+#ifdef MPT_CONFIG_COMPAT
+	err = register_ioctl32_conversion(MPTIOCINFO, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTIOCINFO1, NULL);
+	err = register_ioctl32_conversion(MPTIOCINFO1, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTARGETINFO, NULL);
+	err = register_ioctl32_conversion(MPTTARGETINFO, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTTEST, NULL);
+	err = register_ioctl32_conversion(MPTTEST, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTQUERY, NULL);
+	err = register_ioctl32_conversion(MPTEVENTQUERY, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTENABLE, NULL);
+	err = register_ioctl32_conversion(MPTEVENTENABLE, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTEVENTREPORT, NULL);
+	err = register_ioctl32_conversion(MPTEVENTREPORT, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTHARDRESET, NULL);
+	err = register_ioctl32_conversion(MPTHARDRESET, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(MPTCOMMAND32, sparc32_mpt_command);
+	err = register_ioctl32_conversion(MPTCOMMAND32, compat_mpt_command);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
-					  sparc32_mptfwxfer_ioctl);
+					  compat_mptfwxfer_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL);
+	err = register_ioctl32_conversion(HP_GETHOSTINFO, sys_ioctl);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL);
+	err = register_ioctl32_conversion(HP_GETTARGETINFO, sys_ioctl);
 	if (++where && err) goto out_fail;
-#endif		/*} linux >= 2.3.x */
-#endif		/*} sparc */
+#endif
 
 	/* Register this device */
 	err = misc_register(&mptctl_miscdev);
@@ -2925,8 +2922,7 @@
 
 out_fail:
 
-#if defined(__sparc__) && defined(__sparc_v9__)		/*{*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
+#ifdef MPT_CONFIG_COMPAT
 	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
 			" (%d:err=%d)\n", where, err);
 	unregister_ioctl32_conversion(MPTIOCINFO);
@@ -2941,8 +2937,7 @@
 	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
 	unregister_ioctl32_conversion(HP_GETHOSTINFO);
 	unregister_ioctl32_conversion(HP_GETTARGETINFO);
-#endif		/*} linux >= 2.3.x */
-#endif		/*} sparc */
+#endif
 
 	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
 		ioc = NULL;
@@ -2979,6 +2974,21 @@
 	mpt_deregister(mptctl_id);
 	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
 
+#ifdef MPT_CONFIG_COMPAT
+	unregister_ioctl32_conversion(MPTIOCINFO);
+	unregister_ioctl32_conversion(MPTIOCINFO1);
+	unregister_ioctl32_conversion(MPTTARGETINFO);
+	unregister_ioctl32_conversion(MPTTEST);
+	unregister_ioctl32_conversion(MPTEVENTQUERY);
+	unregister_ioctl32_conversion(MPTEVENTENABLE);
+	unregister_ioctl32_conversion(MPTEVENTREPORT);
+	unregister_ioctl32_conversion(MPTHARDRESET);
+	unregister_ioctl32_conversion(MPTCOMMAND32);
+	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+	unregister_ioctl32_conversion(HP_GETHOSTINFO);
+	unregister_ioctl32_conversion(HP_GETTARGETINFO);
+#endif
+
 	/* Free allocated memory */
 	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
 		ioc = NULL;
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptctl.h linux-2.4.25-pre8/drivers/message/fusion/mptctl.h
--- linux-2.4.25-pre7/drivers/message/fusion/mptctl.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptctl.h	2004-01-29 10:58:21.000000000 -0800
@@ -18,7 +18,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptctl.h,v 1.14 2003/03/18 22:49:51 pdelaney Exp $
  */
@@ -84,10 +84,10 @@
 #define MPTFWDOWNLOAD		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
 #define MPTCOMMAND		_IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command)
 
-#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#if defined(__KERNEL__) && defined(MPT_CONFIG_COMPAT)
 #define MPTFWDOWNLOAD32		_IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
 #define MPTCOMMAND32		_IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command32)
-#endif	/*}*/
+#endif
 
 #define MPTIOCINFO		_IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo)
 #define MPTIOCINFO1		_IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo_rev0)
@@ -117,13 +117,13 @@
 	void		*bufp;		/* Pointer to firmware buffer */
 };
 
-#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#if defined(__KERNEL__) && defined(MPT_CONFIG_COMPAT)
 struct mpt_fw_xfer32 {
 	unsigned int iocnum;
 	unsigned int fwlen;
 	u32 bufp;
 };
-#endif	/*}*/
+#endif
 
 /*
  *  IOCTL header structure.
@@ -316,7 +316,7 @@
 /*
  * SPARC PLATFORM: See earlier remark.
  */
-#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)		/*{*/
+#if defined(__KERNEL__) && defined(MPT_CONFIG_COMPAT)
 struct mpt_ioctl_command32 {
 	mpt_ioctl_header hdr;
 	int	timeout;
@@ -331,7 +331,7 @@
 	int	dataSgeOffset;
 	char	MF[1];
 };
-#endif	/*}*/
+#endif
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptscsih.c linux-2.4.25-pre8/drivers/message/fusion/mptscsih.c
--- linux-2.4.25-pre7/drivers/message/fusion/mptscsih.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptscsih.c	2004-01-29 10:58:21.000000000 -0800
@@ -24,7 +24,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Original author: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptscsih.c,v 1.1.2.4 2003/05/07 14:08:34 pdelaney Exp $
  */
@@ -180,12 +180,13 @@
 static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
-static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
+static void	mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
 static int	mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
+static int	mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
 static int	mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void	mptscsih_timer_expired(unsigned long data);
 static void	mptscsih_taskmgmt_timeout(unsigned long data);
@@ -438,10 +439,10 @@
 static inline int
 mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
 {
-	MPT_FRAME_HDR *chainBuf = NULL;
+	MPT_FRAME_HDR *chainBuf;
 	unsigned long flags;
-	int rc = FAILED;
-	int chain_idx = MPT_HOST_NO_CHAIN;
+	int rc;
+	int chain_idx;
 
 	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
 	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
@@ -454,6 +455,10 @@
 		chain_idx = offset / hd->ioc->req_sz;
 		rc = SUCCESS;
 	}
+	else {
+		rc = FAILED;
+		chain_idx = MPT_HOST_NO_CHAIN;
+	}
 	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
 
@@ -506,12 +511,13 @@
 	/* Map the data portion, if any.
 	 * sges_left  = 0 if no data transfer.
 	 */
-	sges_left = SCpnt->use_sg;
-	if (SCpnt->use_sg) {
-		sges_left = pci_map_sg(hd->ioc->pcidev,
+	if ( (sges_left = SCpnt->use_sg) ) {
+		if ( (sges_left = pci_map_sg(hd->ioc->pcidev,
 			       (struct scatterlist *) SCpnt->request_buffer,
 			       SCpnt->use_sg,
-			       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+			       scsi_to_pci_dma_dir(SCpnt->sc_data_direction)))
+			== 0 )
+				return FAILED;
 	} else if (SCpnt->request_bufflen) {
 		dma_addr_t	 buf_dma_addr;
 		scPrivate	*my_priv;
@@ -730,13 +736,6 @@
 
 	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
-	if ((mf == NULL) ||
-	    (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-		printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
-				ioc->name, mf?"BAD":"NULL", (void *) mf);
-		return 0;
-	}
-
 	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 	sc = hd->ScsiLookup[req_idx];
 	if (sc == NULL) {
@@ -878,7 +877,6 @@
 				mptscsih_no_negotiate(hd, sc->target);
 			break;
 
-		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
 		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */
 			/*
 			 *  YIKES!  I just discovered that SCSI IO which
@@ -916,6 +914,9 @@
 			sc->resid = sc->request_bufflen - xfer_cnt;
 			dprintk((KERN_NOTICE "  SET sc->resid=%02xh\n", sc->resid));
 #endif
+			if (sc->underflow > xfer_cnt) {
+				sc->result = DID_SOFT_ERROR;
+			}
 
 			/* Report Queue Full
 			 */
@@ -1036,6 +1037,7 @@
 		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */
 		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */
 		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */
+		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */
 		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */
 		default:
 			/*
@@ -1156,8 +1158,8 @@
 static void
 clean_taskQ(MPT_SCSI_HOST *hd)
 {
-	MPT_FRAME_HDR *mf = NULL;
-	MPT_FRAME_HDR *nextmf = NULL;
+	MPT_FRAME_HDR *mf;
+	MPT_FRAME_HDR *nextmf;
 	MPT_ADAPTER *ioc = hd->ioc;
 	unsigned long flags;
 
@@ -1196,7 +1198,7 @@
 static void
 search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd)
 {
-	MPT_FRAME_HDR *mf = NULL;
+	MPT_FRAME_HDR *mf;
 	unsigned long flags;
 	int count = 0;
 
@@ -1320,7 +1322,7 @@
 static void
 mptscsih_reset_timeouts (MPT_SCSI_HOST *hd)
 {
-	Scsi_Cmnd	*SCpnt = NULL;
+	Scsi_Cmnd	*SCpnt;
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
 
@@ -1346,9 +1348,9 @@
 static void
 mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
-	Scsi_Cmnd	*SCpnt = NULL;
-	MPT_FRAME_HDR	*mf = NULL;
-	MPT_DONE_Q	*buffer = NULL;
+	Scsi_Cmnd	*SCpnt;
+	MPT_FRAME_HDR	*mf;
+	MPT_DONE_Q	*buffer;
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
 
@@ -1457,18 +1459,16 @@
 	/* ReqToChain size must equal the req_depth
 	 * index = req_idx
 	 */
-	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
+		sz = hd->ioc->req_depth * sizeof(int);
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -1;
 
 		hd->ReqToChain = (int *) mem;
-	} else {
-		mem = (u8 *) hd->ReqToChain;
 	}
-	memset(mem, 0xFF, sz);
-
+	for (ii = 0; ii < hd->ioc->req_depth; ii++)
+		hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
 
 	/* ChainToChain size must equal the total number
 	 * of chain buffers to be allocated.
@@ -1606,9 +1606,9 @@
 int
 mptscsih_detect(Scsi_Host_Template *tpnt)
 {
-	struct Scsi_Host	*sh = NULL;
-	MPT_SCSI_HOST		*hd = NULL;
-	MPT_ADAPTER		*this;
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
+	MPT_ADAPTER		*ioc;
 	MPT_DONE_Q		*freedoneQ;
 	unsigned long		 flags;
 	int			 sz, ii;
@@ -1651,20 +1651,19 @@
 	atomic_set(&mpt_taskQdepth, 0);
 #endif
 
-	this = mpt_adapter_find_first();
-	while (this != NULL) {
+	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
 		/* 20010202 -sralston
 		 *  Added sanity check on readiness of the MPT adapter.
 		 */
-		if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+		if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
 			printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
-					this->name);
+					ioc->name);
 			continue;
 		}
 
-		if (!this->active) {
+		if (!ioc->active) {
 			printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
-					this->name);
+					ioc->name);
 			continue;
 		}
 
@@ -1672,14 +1671,14 @@
 		/*  Sanity check - ensure at least 1 port is INITIATOR capable
 		 */
 		ioc_cap = 0;
-		for (ii=0; ii < this->facts.NumberOfPorts; ii++) {
-			if (this->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)
+		for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+			if (ioc->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)
 				ioc_cap ++;
 		}
 
 		if (!ioc_cap) {
-			printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
-					this->name);
+			printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
+					ioc->name, ioc);
 			continue;
 		}
 
@@ -1690,7 +1689,7 @@
 		tpnt->proc_info = mptscsih_proc_info;
 		sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
 		if (sh != NULL) {
-			spin_lock_irqsave(&this->FreeQlock, flags);
+			spin_lock_irqsave(&ioc->FreeQlock, flags);
 			sh->io_port = 0;
 			sh->n_io_port = 0;
 			sh->irq = 0;
@@ -1705,7 +1704,7 @@
 			 * max_lun = 1 + actual last lun,
 			 *	see hosts.h :o(
 			 */
-			if ((int)this->chip_type > (int)FC929)
+			if ((int)ioc->chip_type > (int)FC929)
 				sh->max_id = MPT_MAX_SCSI_DEVICES;
 			else {
 				/* For FC, increase the queue depth
@@ -1732,7 +1731,7 @@
 			 * and all access to VirtDev
 			 */
 			sh->max_channel = 0;
-			sh->this_id = this->pfacts[0].PortSCSIID;
+			sh->this_id = ioc->pfacts[0].PortSCSIID;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
 			/* OS entry to allow host drivers to force
@@ -1742,7 +1741,7 @@
 #endif
 			/* Required entry.
 			 */
-			sh->unique_id = this->id;
+			sh->unique_id = ioc->id;
 
 			/* Verify that we won't exceed the maximum
 			 * number of chain buffers
@@ -1753,38 +1752,38 @@
 			 * A slightly different algorithm is required for
 			 * 64bit SGEs.
 			 */
-			scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+			scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
 			if (sizeof(dma_addr_t) == sizeof(u64)) {
-				numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-					(this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+				numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
+					(ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
 			} else {
-				numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-					(this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+				numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
+					(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
 			}
 
 			if (numSGE < sh->sg_tablesize) {
 				/* Reset this value */
 				dprintk((MYIOC_s_INFO_FMT
 					 "Resetting sg_tablesize to %d from %d\n",
-					 this->name, numSGE, sh->sg_tablesize));
+					 ioc->name, numSGE, sh->sg_tablesize));
 				sh->sg_tablesize = numSGE;
 			}
 
 			/* Set the pci device pointer in Scsi_Host structure.
 			 */
-			scsi_set_pci_device(sh, this->pcidev);
+			scsi_set_pci_device(sh, ioc->pcidev);
 
-			spin_unlock_irqrestore(&this->FreeQlock, flags);
+			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
 			hd = (MPT_SCSI_HOST *) sh->hostdata;
-			hd->ioc = this;
+			hd->ioc = ioc;
 			hd->max_sge = sh->sg_tablesize;
 
-			if ((int)this->chip_type > (int)FC929)
+			if ((int)ioc->chip_type > (int)FC929)
 				hd->is_spi = 1;
 
 			if (DmpService &&
-			    (this->chip_type == FC919 || this->chip_type == FC929))
+			    (ioc->chip_type == FC919 || ioc->chip_type == FC929))
 				hd->is_multipath = 1;
 
 			/* SCSI needs Scsi_Cmnd lookup table!
@@ -1799,7 +1798,7 @@
 			hd->ScsiLookup = (struct scsi_cmnd **) mem;
 
 			dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-				 this->name, hd->ScsiLookup, sz));
+				 ioc->name, hd->ScsiLookup, sz));
 
 			if (mptscsih_initChainBuffers(hd, 1) < 0)
 				goto done;
@@ -1870,7 +1869,7 @@
 
 			/* Attach the SCSI Host to the IOC structure
 			 */
-			this->sh = sh;
+			ioc->sh = sh;
 
 			/* Initialize this SCSI Hosts' timers
 			 * To use, set the timer expires field
@@ -1886,7 +1885,7 @@
 			hd->qtag_tick = jiffies;
 
 			/* Moved Earlier Pam D */
-			/* this->sh = sh;	*/
+			/* ioc->sh = sh;	*/
 
 #ifdef MPTSCSIH_DBG_TIMEOUT
 			hd->ioc->timeout_hard = 0;
@@ -1909,6 +1908,8 @@
 				if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
 					hd->ioc->spi_data.maxSyncOffset = 0;
 
+				hd->ioc->spi_data.Saf_Te = driver_setup.saf_te;
+
 				hd->negoNvram = 0;
 #ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
 				hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
@@ -1926,16 +1927,15 @@
 				}
 
 				ddvprintk((MYIOC_s_INFO_FMT
-					"dv %x width %x factor %x \n",
+					"dv %x width %x factor %x saf_te %x\n",
 					hd->ioc->name, driver_setup.dv,
 					driver_setup.max_width,
-					driver_setup.min_sync_fac));
+					driver_setup.min_sync_fac,
+					driver_setup.saf_te));
 			}
 
 			mpt_scsi_hosts++;
 		}
-
-		this = mpt_adapter_find_next(this);
 	}
 
 done:
@@ -2146,8 +2146,8 @@
 static int
 mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
 {
-	MPT_ADAPTER *ioc = NULL;
-	MPT_SCSI_HOST *hd = NULL;
+	MPT_ADAPTER *ioc;
+	MPT_SCSI_HOST *hd;
 
 	/* Ignore all messages other than reboot message
 	 */
@@ -2182,7 +2182,7 @@
 const char *
 mptscsih_info(struct Scsi_Host *SChost)
 {
-	MPT_SCSI_HOST *h = NULL;
+	MPT_SCSI_HOST *h;
 	int size = 0;
 
 	if (info_kbuf == NULL)
@@ -2398,7 +2398,7 @@
 int mptscsih_proc_info(char *buffer, char **start, off_t offset,
 			int length, int hostno, int func)
 {
-	MPT_ADAPTER	*ioc = NULL;
+	MPT_ADAPTER	*ioc;
 	MPT_SCSI_HOST	*hd = NULL;
 	int size = 0;
 
@@ -2489,7 +2489,7 @@
 	MPT_FRAME_HDR		*mf;
 	SCSIIORequest_t		*pScsiReq;
 	VirtDevice		*pTarget;
-	MPT_DONE_Q		*buffer = NULL;
+	MPT_DONE_Q		*buffer;
 	unsigned long		 flags;
 	int	 target;
 	int	 lun;
@@ -2774,7 +2774,7 @@
 static void
 mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
 {
-	MPT_FRAME_HDR *chain = NULL;
+	MPT_FRAME_HDR *chain;
 	unsigned long flags;
 	int chain_idx;
 	int next;
@@ -2839,7 +2839,7 @@
 static int
 mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
-	MPT_ADAPTER	*ioc = NULL;
+	MPT_ADAPTER	*ioc;
 	int		 rc = -1;
 	int		 doTask = 1;
 	u32		 ioc_raw_state;
@@ -3088,7 +3088,6 @@
 		search_doneQ_for_cmd(hd, SCpnt);
 
 		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
 		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
 			   "Command not in the active list! (sc=%p)\n",
 			   hd->ioc->name, SCpnt));
@@ -3345,7 +3344,6 @@
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
 		printk(KERN_WARNING "  WARNING - OldAbort, NULL hostdata ptr!!\n");
 		SCpnt->result = DID_ERROR << 16;
-		SCpnt->scsi_done(SCpnt);
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
@@ -3359,18 +3357,19 @@
 		 */
 		search_doneQ_for_cmd(hd, SCpnt);
 
-		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
+		SCpnt->result = DID_ABORT << 16;
 		return SCSI_ABORT_SUCCESS;
 	} else {
 		/* If this command is pended, then timeout/hang occurred
 		 * during DV. Force bus reset by posting command to F/W
 		 * and then following up with the reset request.
 		 */
+#ifndef MPTSCSIH_DBG_TIMEOUT
 		if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
 			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
 			post_pendingQ_commands(hd);
 		}
+#endif
 	}
 
 	/*
@@ -3476,8 +3475,7 @@
 	printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
 
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
+		SCpnt->result = DID_ERROR << 16;
 		return SCSI_RESET_SUCCESS;
 	}
 
@@ -3492,17 +3490,18 @@
 		search_doneQ_for_cmd(hd, SCpnt);
 
 		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
 		return SCSI_RESET_SUCCESS;
 	} else {
 		/* If this command is pended, then timeout/hang occurred
 		 * during DV. Force bus reset by posting command to F/W
 		 * and then following up with the reset request.
 		 */
+#ifndef MPTSCSIH_DBG_TIMEOUT
 		if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
 			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
 			post_pendingQ_commands(hd);
 		}
+#endif
 	}
 
 	/*
@@ -3628,8 +3627,8 @@
 
 #ifdef MPTSCSIH_DBG_TIMEOUT
 				if (ioc->timeout_hard == 1) {
-					mptscsih_TMHandler(hd, 
-						MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 
+					mptscsih_TMHandler(hd,
+						MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
 						0, 0, 0, 0, CAN_SLEEP);
 
 				}
@@ -3727,6 +3726,9 @@
 				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 				mf = NULL;
 
+#ifndef MPTSCSIH_DBG_TIMEOUT
+				post_pendingQ_commands(hd);
+#endif
 				if (mptscsih_TMHandler(hd, task_type, SCpnt->channel,
 						      SCpnt->target, SCpnt->lun,
 						       ctx2abort, CAN_SLEEP) < 0) {
@@ -3784,7 +3786,7 @@
 {
 	SCSITaskMgmtReply_t	*pScsiTmReply;
 	SCSITaskMgmt_t		*pScsiTmReq;
-	MPT_SCSI_HOST		*hd = NULL;
+	MPT_SCSI_HOST		*hd;
 	unsigned long		 flags;
 	u8			 tmType = 0;
 
@@ -3962,10 +3964,10 @@
 			}
 
 			if (pTarget != NULL) {
-				printk(MYIOC_s_INFO_FMT
+				dprintk((MYIOC_s_INFO_FMT
 					 "scsi%d: Id=%d Lun=%d: Queue depth=%d\n",
-					 hd->ioc->name, sh->host_no,
-					 device->id, device->lun, device->queue_depth);
+					 hd->ioc->name, 
+					 device->id, device->lun, device->queue_depth));
 
 				dprintk((MYIOC_s_INFO_FMT
 					 "Id = %d, sync factor = %x\n",
@@ -4041,11 +4043,10 @@
 		thisIo.SCSIStatus = pScsiReply->SCSIStatus;
 		thisIo.DoDisplay = 1;
 		if (hd->is_multipath)
-			sprintf(devFoo, "%d:%d:%d \"%s\"",
+			sprintf(devFoo, "%d:%d:%d",
 					hd->ioc->id,
 					pReq->TargetID,
-					pReq->LUN[1],
-					target->dev_vol_name);
+					pReq->LUN[1]);
 		else
 			sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->target, sc->lun);
 		thisIo.DevIDStr = devFoo;
@@ -4102,7 +4103,7 @@
 	unsigned long	 flags;
 	MPT_DONE_Q	*buffer;
 	MPT_FRAME_HDR	*mf = NULL;
-	MPT_FRAME_HDR	*cmdMfPtr = NULL;
+	MPT_FRAME_HDR	*cmdMfPtr;
 
 	ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
 	cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
@@ -4190,7 +4191,7 @@
 static int
 mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-	MPT_SCSI_HOST	*hd = NULL;
+	MPT_SCSI_HOST	*hd;
 	unsigned long	 flags;
 
 	dtmprintk((KERN_WARNING MYNAM
@@ -4263,7 +4264,7 @@
 
 		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
 	} else {
-		ScsiCfgData	*pSpi = NULL;
+		ScsiCfgData	*pSpi;
 
 		dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
 
@@ -4971,13 +4972,12 @@
  *	Allocate and initialize memory for this target.
  *	Save inquiry data.
  *
- *	Returns pointer to VirtDevice structure.
  */
-static VirtDevice *
+static void 
 mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
 {
+	int		indexed_lun, lun_index;
 	VirtDevice	*vdev;
-	int		 sz;
 
 	dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n",
 			hd->ioc->name, bus_id, target_id, lun, hd));
@@ -4986,6 +4986,7 @@
 		if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
 			printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n",
 					hd->ioc->name, (int)sizeof(VirtDevice));
+			return;
 		} else {
 			memset(vdev, 0, sizeof(VirtDevice));
 			rwlock_init(&vdev->VdevLock);
@@ -5004,24 +5005,44 @@
 	}
 
 	vdev->raidVolume = 0;
-	if (vdev && hd->is_spi) {
+	if (hd->is_spi) {
 		if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
 			vdev->raidVolume = 1;
 			ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
 		}
 	}
 
-	if (vdev && data) {
-		if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) ||
-		((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
-
-			/* Copy the inquiry data  - if we haven't yet.
-			*/
-			sz = MIN(dlen, SCSI_STD_INQUIRY_BYTES);
+	if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+		/* Copy the inquiry data  - if we haven't yet.
+		*/
+
+		memcpy (vdev->inq_data, data, 8);
 
-			memcpy (vdev->inq_data, data, sz);
+		if ( (data[0] == SCSI_TYPE_PROC) && 
+			!(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
+			if ( dlen > 49 ) {
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+				if ( data[44] == 'S' && 
+				     data[45] == 'A' && 
+				     data[46] == 'F' && 
+				     data[47] == '-' && 
+				     data[48] == 'T' && 
+				     data[49] == 'E' ) {
+					vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+					mptscsih_writeIOCPage4(hd, target_id, bus_id);
+				}
+			} else {
+				/* Treat all Processors as SAF-TE if 
+				 * command line option is set */
+				if ( hd->ioc->spi_data.Saf_Te ) {
+					vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+					mptscsih_writeIOCPage4(hd, target_id, bus_id);
+				}
+			}
+		} else 
 			vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
 
+		if ((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
 			/* Update the target capabilities
 			 */
 			if (dlen > 56) {
@@ -5038,17 +5059,19 @@
 					pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
 			}
 		}
-
-		/* Is LUN supported? If so, upper 3 bits will be 0
-		 * in first byte of inquiry data.
-		 */
-		if ((*data & 0xe0) == 0)
-			vdev->luns |= (1 << lun);
 	}
 
+	/* Is LUN supported? If so, upper 3 bits will be 0
+	 * in first byte of inquiry data.
+	 */
+	if ((*data & 0xe0) == 0) {
+		lun_index = (lun >> 5);  /* 32 luns per lun_index */
+		indexed_lun = (lun % 32);
+		vdev->luns[lun_index] |= (1 << indexed_lun);
+	}
 
 	dprintk((KERN_INFO "  target = %p\n", vdev));
-	return vdev;
+	return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5063,13 +5086,13 @@
 	int  id = (int) target->target_id;
 	int  nvram;
 	char canQ = 0;
+	VirtDevice	*vdev;
+	int ii;
 	u8 width = MPT_NARROW;
 	u8 factor = MPT_ASYNC;
 	u8 offset = 0;
 	u8 version, nfactor;
-	u8 noQas = 0;
-
-	ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
+	u8 noQas = 1;
 
 	if (!hd->is_spi) {
 		if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
@@ -5079,19 +5102,16 @@
 		return;
 	}
 
+	target->negoFlags = pspi_data->noQas;
+
 	/* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
 	 * support. If available, default QAS to off and allow enabling.
 	 * If not available, default QAS to on, turn off for non-disks.
 	 */
-	if (target->tflags & MPT_TARGET_FLAGS_VALID_56)
-		noQas = 1;
 
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
-		if ((target->inq_data[0] & 0x1F) != 0x00)
-			noQas = 1;
-
 		version = target->inq_data[2] & 0x07;
 		if (version < 2) {
 			width = 0;
@@ -5111,6 +5131,7 @@
 					factor = MPT_ULTRA160;
 				else
 					factor = MPT_ULTRA320;
+				offset = pspi_data->maxSyncOffset;
 
 				/* If RAID, never disable QAS
 				 * else if non RAID, do not disable
@@ -5120,8 +5141,6 @@
 				 */
 				if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
 					noQas = 0;
-
-				offset = pspi_data->maxSyncOffset;
 			} else {
 				factor = MPT_ASYNC;
 				offset = 0;
@@ -5180,35 +5199,31 @@
 
 		/* Disable unused features.
 		 */
-		target->negoFlags = pspi_data->noQas;
 		if (!width)
 			target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
 
 		if (!offset)
 			target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
 
-		if (noQas)
-			target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
-
 		/* GEM, processor WORKAROUND
 		 */
-		if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)){
+		if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)) {
 			target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
 			pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
-		}
-
-		/* Disable QAS if mixed configuration case
-		 */
-		if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) != 0x03)){
-			VirtDevice	*vdev;
-			int ii;
-
-			ddvtprintk((KERN_INFO "Disabling QAS!\n"));
-			pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
-			for (ii = 0; ii < id; ii++) {
-				vdev = hd->Targets[id];
-				if (vdev != NULL)
-					vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+		} else {
+			if (noQas && (pspi_data->noQas == 0)) {
+				pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
+				target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+				/* Disable QAS in a mixed configuration case
+		 		*/
+
+//				ddvtprintk((KERN_INFO "Disabling QAS!\n"));
+				for (ii = 0; ii < id; ii++) {
+					if ( (vdev = hd->Targets[ii]) ) {
+						vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+					}	
+				}
 			}
 		}
 	}
@@ -5334,9 +5349,9 @@
 mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
-	Config_t		*pReq = NULL;
-	SCSIDevicePage1_t	*pData = NULL;
-	VirtDevice		*pTarget = NULL;
+	Config_t		*pReq;
+	SCSIDevicePage1_t	*pData;
+	VirtDevice		*pTarget;
 	MPT_FRAME_HDR		*mf;
 	dma_addr_t		 dataDma;
 	u16			 req_idx;
@@ -5432,7 +5447,6 @@
 			factor = pTarget->minSyncFactor;
 			offset = pTarget->maxOffset;
 			negoFlags = pTarget->negoFlags;
-			pTarget = NULL;
 		}
 
 		if (flags & MPT_SCSICFG_BLK_NEGO)
@@ -5515,6 +5529,86 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*	mptscsih_writeIOCPage4  - write IOC Page 4
+ *	@hd: Pointer to a SCSI Host Structure
+ *	@target_id: write IOC Page4 for this ID & Bus
+ *
+ *	Return: -EAGAIN if unable to obtain a Message Frame
+ *		or 0 if success.
+ *
+ *	Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
+{
+	MPT_ADAPTER		*ioc = hd->ioc;
+	Config_t		*pReq;
+	IOCPage4_t		*IOCPage4Ptr;
+	MPT_FRAME_HDR		*mf;
+	dma_addr_t		 dataDma;
+	u16			 req_idx;
+	u32			 frameOffset;
+	u32			 flagsLength;
+	int			 ii;
+
+	/* Get a MF for this command.
+	 */
+	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
+		dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
+					ioc->name));
+		return -EAGAIN;
+	}
+
+	ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n",
+		ioc->name, mf, target_id));
+
+	/* Set the request and the data pointers.
+	 * Place data at end of MF.
+	 */
+	pReq = (Config_t *)mf;
+
+	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
+
+	/* Complete the request frame (same for all requests).
+	 */
+	pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+	pReq->Reserved = 0;
+	pReq->ChainOffset = 0;
+	pReq->Function = MPI_FUNCTION_CONFIG;
+	pReq->Reserved1[0] = 0;
+	pReq->Reserved1[1] = 0;
+	pReq->Reserved1[2] = 0;
+	pReq->MsgFlags = 0;
+	for (ii=0; ii < 8; ii++) {
+		pReq->Reserved2[ii] = 0;
+	}
+
+       	IOCPage4Ptr = ioc->spi_data.pIocPg4;
+       	dataDma = ioc->spi_data.IocPg4_dma;
+       	ii = IOCPage4Ptr->ActiveSEP++;
+       	IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
+       	IOCPage4Ptr->SEP[ii].SEPBus = bus;
+       	pReq->Header = IOCPage4Ptr->Header;
+	pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
+
+	/* Add a SGE to the config request.
+	 */
+	flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | 
+		(IOCPage4Ptr->Header.PageLength + ii) * 4;
+
+	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+	dsprintk((MYIOC_s_INFO_FMT
+		"writeIOCPage4: pgaddr 0x%x\n",
+			ioc->name, (target_id | (bus<<8))));
+
+	mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
+
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*	mptscsih_taskmgmt_timeout - Call back for timeout on a
  *	task management request.
  *	@data: Pointer to MPT_SCSI_HOST recast as an unsigned long
@@ -6138,7 +6232,7 @@
 mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
 {
 	MPT_ADAPTER		*ioc= hd->ioc;
-	VirtDevice		*pTarget = NULL;
+	VirtDevice		*pTarget;
 	SCSIDevicePage1_t	*pcfg1Data = NULL;
 	INTERNAL_CMD		 iocmd;
 	CONFIGPARMS		 cfg;
@@ -6146,7 +6240,8 @@
 	ConfigPageHeader_t	 header1;
 	int			 bus = 0;
 	int			 id = 0;
-	int			 lun = 0;
+	int			 lun;
+	int			 indexed_lun, lun_index;
 	int			 hostId = ioc->pfacts[portnum].PortSCSIID;
 	int			 max_id;
 	int			 requested, configuration, data;
@@ -6237,12 +6332,13 @@
 
 		/* If target Ptr NULL or if this target is NOT a disk, skip.
 		 */
-	//	if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
 		if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
 			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
 				/* If LUN present, issue the command
 				 */
-				if (pTarget->luns & (1<<lun)) {
+				lun_index = (lun >> 5);  /* 32 luns per lun_index */
+				indexed_lun = (lun % 32);
+				if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
 					iocmd.lun = lun;
 					(void) mptscsih_do_cmd(hd, &iocmd);
 				}
@@ -6283,8 +6379,8 @@
 static void
 mptscsih_domainValidation(void *arg)
 {
-	MPT_SCSI_HOST		*hd = NULL;
-	MPT_ADAPTER		*ioc = NULL;
+	MPT_SCSI_HOST		*hd;
+	MPT_ADAPTER		*ioc;
 	unsigned long		 flags;
 	int 			 id, maxid, dvStatus, did;
 	int			 ii, isPhysDisk;
@@ -6441,7 +6537,7 @@
  */
 static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
 {
-	VirtDevice *pTarget = NULL;
+	VirtDevice *pTarget;
 	int ii;
 
 	if (hd->Targets == NULL)
@@ -6495,12 +6591,12 @@
 mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
-	VirtDevice		*pTarget = NULL;
-	SCSIDevicePage1_t	*pcfg1Data = NULL;
-	SCSIDevicePage0_t	*pcfg0Data = NULL;
-	u8			*pbuf1 = NULL;
-	u8			*pbuf2 = NULL;
-	u8			*pDvBuf = NULL;
+	VirtDevice		*pTarget;
+	SCSIDevicePage1_t	*pcfg1Data;
+	SCSIDevicePage0_t	*pcfg0Data;
+	u8			*pbuf1;
+	u8			*pbuf2;
+	u8			*pDvBuf;
 	dma_addr_t		 dvbuf_dma = -1;
 	dma_addr_t		 buf1_dma = -1;
 	dma_addr_t		 buf2_dma = -1;
@@ -6653,7 +6749,8 @@
 			if (nfactor < pspi_data->minSyncFactor )
 				nfactor = pspi_data->minSyncFactor;
 	
-			if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE)) {
+			if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
+				(pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
 	
 				ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
 					ioc->name, bus, id, lun));
@@ -6921,6 +7018,9 @@
 	if (inq0 != 0)
 		goto target_done;
 
+	if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
+		goto target_done;
+
 	/* Start the Enhanced Test.
 	 * 0) issue TUR to clear out check conditions
 	 * 1) read capacity of echo (regular) buffer
@@ -7377,9 +7477,9 @@
 static void
 mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
 {
-	VirtDevice		*pTarget = NULL;
-	SCSIDevicePage0_t	*pPage0 = NULL;
-	SCSIDevicePage1_t	*pPage1 = NULL;
+	VirtDevice		*pTarget;
+	SCSIDevicePage0_t	*pPage0;
+	SCSIDevicePage1_t	*pPage1;
 	int			val = 0, data, configuration;
 	u8			width = 0;
 	u8			offset = 0;
@@ -7762,9 +7862,9 @@
 /* Commandline Parsing routines and defines.
  *
  * insmod format:
- *	insmod mptscsih mptscsih="width:1 dv:n factor:0x09"
+ *	insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1"
  *  boot format:
- *	mptscsih=width:1,dv:n,factor:0x8
+ *	mptscsih=width:1,dv:n,factor:0x8,saf-te:1
  *
  */
 #ifdef MODULE
@@ -7777,11 +7877,13 @@
 	"dv:"
 	"width:"
 	"factor:"
-       ;	/* DONNOT REMOVE THIS ';' */
+	"saf-te:"
+       ;	/* DO NOT REMOVE THIS ';' */
 
 #define OPT_DV			1
 #define OPT_MAX_WIDTH		2
 #define OPT_MIN_SYNC_FACTOR	3
+#define OPT_SAF_TE		4
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
@@ -7838,6 +7940,10 @@
 			driver_setup.min_sync_fac = val;
 			break;
 
+		case OPT_SAF_TE:
+			driver_setup.saf_te = val;
+			break;
+
 		default:
 			printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 			break;
diff -urN linux-2.4.25-pre7/drivers/message/fusion/mptscsih.h linux-2.4.25-pre8/drivers/message/fusion/mptscsih.h
--- linux-2.4.25-pre7/drivers/message/fusion/mptscsih.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/mptscsih.h	2004-01-29 10:58:21.000000000 -0800
@@ -18,7 +18,7 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: mptscsih.h,v 1.1.2.2 2003/05/07 14:08:35 pdelaney Exp $
  */
@@ -116,12 +116,14 @@
 #define MPTSCSIH_DOMAIN_VALIDATION      1
 #define MPTSCSIH_MAX_WIDTH              1
 #define MPTSCSIH_MIN_SYNC               0x08
+#define MPTSCSIH_SAF_TE                 0
 
 struct mptscsih_driver_setup
 {
         u8      dv;
         u8      max_width;
         u8      min_sync_fac;
+        u8      saf_te;
 };
 
 
@@ -130,6 +132,7 @@
         MPTSCSIH_DOMAIN_VALIDATION,             \
         MPTSCSIH_MAX_WIDTH,                     \
         MPTSCSIH_MIN_SYNC,                      \
+        MPTSCSIH_SAF_TE,                        \
 }
 
 
diff -urN linux-2.4.25-pre7/drivers/message/fusion/scsi3.h linux-2.4.25-pre8/drivers/message/fusion/scsi3.h
--- linux-2.4.25-pre7/drivers/message/fusion/scsi3.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/message/fusion/scsi3.h	2004-01-29 10:58:21.000000000 -0800
@@ -7,7 +7,7 @@
  *  Copyright (c) 1996-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston (19960517)
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephens@lsil.com)
+ *  (mailto:mpt_linux_developer@lsil.com)
  *
  *  $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $
  */
diff -urN linux-2.4.25-pre7/drivers/net/8139cp.c linux-2.4.25-pre8/drivers/net/8139cp.c
--- linux-2.4.25-pre7/drivers/net/8139cp.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/net/8139cp.c	2004-01-29 10:58:21.000000000 -0800
@@ -615,8 +615,10 @@
 		if (cpr16(IntrStatus) & cp_rx_intr_mask)
 			goto rx_status_loop;
 
-		netif_rx_complete(dev);
+		local_irq_disable();
 		cpw16_f(IntrMask, cp_intr_mask);
+		__netif_rx_complete(dev);
+		local_irq_enable();
 
 		return 0;	/* done */
 	}
@@ -643,6 +645,12 @@
 
 	spin_lock(&cp->lock);
 
+	/* close possible race's with dev_close */
+	if (unlikely(!netif_running(dev))) {
+		cpw16(IntrMask, 0);
+		goto out;
+	}
+
 	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
 		if (netif_rx_schedule_prep(dev)) {
 			cpw16_f(IntrMask, cp_norx_intr_mask);
@@ -664,7 +672,7 @@
 
 		/* TODO: reset hardware */
 	}
-
+out:
 	spin_unlock(&cp->lock);
 	return IRQ_HANDLED;
 }
diff -urN linux-2.4.25-pre7/drivers/net/irda/via-ircc.c linux-2.4.25-pre8/drivers/net/irda/via-ircc.c
--- linux-2.4.25-pre7/drivers/net/irda/via-ircc.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/net/irda/via-ircc.c	2004-01-29 10:58:21.000000000 -0800
@@ -79,7 +79,7 @@
 
 /* Some prototypes */
 static int via_ircc_open(int i, chipio_t * info, unsigned int id);
-static int __exit via_ircc_close(struct via_ircc_cb *self);
+static int via_ircc_close(struct via_ircc_cb *self);
 static int via_ircc_setup(chipio_t * info, unsigned int id);
 static int via_ircc_dma_receive(struct via_ircc_cb *self);
 static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
@@ -107,8 +107,8 @@
 void hwreset(struct via_ircc_cb *self);
 static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase);
 static int upload_rxdata(struct via_ircc_cb *self, int iobase);
-static int __init via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id);
-static void __exit via_remove_one (struct pci_dev *pdev);
+static int via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id);
+static void via_remove_one (struct pci_dev *pdev);
 
 /* Should use udelay() instead, even if we are x86 only - Jean II */
 void iodelay(int udelay)
@@ -137,7 +137,7 @@
 	.name		= VIA_MODULE_NAME,
 	.id_table	= via_pci_tbl,
 	.probe		= via_init_one,
-	.remove		= via_remove_one,
+	.remove		= __devexit_p(via_remove_one),
 };
 
 
@@ -146,7 +146,7 @@
  *
  *    Initialize chip. Just find out chip type and resource.
  */
-int __init via_ircc_init(void)
+int __devinit via_ircc_init(void)
 {
 	int rc;
 
@@ -168,7 +168,7 @@
 
 }
 
-static int __init via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id)
+static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id)
 {
 	int rc;
         u8 temp,oldPCI_40,oldPCI_44,bTmp,bTmp1;
@@ -288,7 +288,7 @@
  *    Close all configured chips
  *
  */
-static void __exit via_ircc_clean(void)
+static void __devexit via_ircc_clean(void)
 {
 	int i;
 
@@ -301,7 +301,7 @@
 	}
 }
 
-static void __exit via_remove_one (struct pci_dev *pdev)
+static void __devexit via_remove_one (struct pci_dev *pdev)
 {
 #ifdef	HEADMSG
         DBG(printk(KERN_INFO "via_remove_one :  ......\n"));
@@ -310,7 +310,7 @@
 
 }
 
-static void __exit via_ircc_cleanup(void)
+static void __devexit via_ircc_cleanup(void)
 {
 
 #ifdef	HEADMSG
@@ -326,7 +326,7 @@
  *    Open driver instance
  *
  */
-static __init int via_ircc_open(int i, chipio_t * info, unsigned int id)
+static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
 {
 	struct net_device *dev;
 	struct via_ircc_cb *self;
@@ -460,7 +460,7 @@
  *    Close driver instance
  *
  */
-static int __exit via_ircc_close(struct via_ircc_cb *self)
+static int __devexit via_ircc_close(struct via_ircc_cb *self)
 {
 	int iobase;
 
diff -urN linux-2.4.25-pre7/drivers/net/ns83820.c linux-2.4.25-pre8/drivers/net/ns83820.c
--- linux-2.4.25-pre7/drivers/net/ns83820.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/net/ns83820.c	2004-01-29 10:58:21.000000000 -0800
@@ -1790,7 +1790,7 @@
 	dev->net_dev.owner = THIS_MODULE;
 	dev->net_dev.priv = dev;
 
-	PREPARE_TQUEUE(&dev->tq_refill, queue_refill, dev);
+	INIT_TQUEUE(&dev->tq_refill, queue_refill, dev);
 	tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev);
 
 	err = pci_enable_device(pci_dev);
diff -urN linux-2.4.25-pre7/drivers/net/pcmcia/xircom_cb.c linux-2.4.25-pre8/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.25-pre7/drivers/net/pcmcia/xircom_cb.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/net/pcmcia/xircom_cb.c	2004-01-29 10:58:21.000000000 -0800
@@ -341,6 +341,11 @@
 	printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]);
 	printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);
 #endif	
+	/* Handle shared irq and hotplug */
+	if (status == 0 || status == 0xffffffff) {
+		spin_unlock(&card->lock);
+		return;
+	}
 
 	if (link_status_changed(card)) {
 		int newlink;
diff -urN linux-2.4.25-pre7/drivers/net/tokenring/olympic.c linux-2.4.25-pre8/drivers/net/tokenring/olympic.c
--- linux-2.4.25-pre7/drivers/net/tokenring/olympic.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.25-pre8/drivers/net/tokenring/olympic.c	2004-01-29 10:58:21.000000000 -0800
@@ -457,14 +457,7 @@
 	printk("Before the open command \n");
 #endif	
 	do {
-		int i;
-
-		for(i=0;i<SRB_COMMAND_SIZE;i+=4)
-			writel(0,init_srb+i);
-		if(SRB_COMMAND_SIZE & 2)
-			writew(0,init_srb+(SRB_COMMAND_SIZE & ~3));
-		if(SRB_COMMAND_SIZE & 1)
-			writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1));
+		memset_io(init_srb,0,SRB_COMMAND_SIZE);
 
 		writeb(SRB_OPEN_ADAPTER,init_srb) ; 	/* open */
 		writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2);
diff -urN linux-2.4.25-pre7/drivers/net/wan/pc300_drv.c linux-2.4.25-pre8/drivers/net/wan/pc300_drv.c
--- linux-2.4.25-pre7/drivers/net/wan/pc300_drv.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/net/wan/pc300_drv.c	2004-01-29 10:58:21.000000000 -0800
@@ -2427,7 +2427,8 @@
 					       sizeof(struct net_device_stats));
 					if (card->hw.type == PC300_TE)
 						memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
-				    copy_to_user(arg, &pc300stats, sizeof(pc300stats_t));
+					if (copy_to_user(arg, &pc300stats, sizeof(pc300stats_t)))
+						return -EFAULT;
 				}
 				return 0;
 			}
@@ -3459,12 +3460,10 @@
 }
 
 static struct pci_driver cpc_driver = {
-	name:"pc300",
-	id_table:cpc_pci_dev_id,
-	probe:cpc_init_one,
-	remove:cpc_remove_one,
-	suspend:NULL,
-	resume:NULL,
+	.name		= "pc300",
+	.id_table	= cpc_pci_dev_id,
+	.probe		= cpc_init_one,
+	.remove		= __devexit_p(cpc_remove_one),
 };
 
 static int __init cpc_init(void)
diff -urN linux-2.4.25-pre7/drivers/pci/pci.ids linux-2.4.25-pre8/drivers/pci/pci.ids
--- linux-2.4.25-pre7/drivers/pci/pci.ids	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/pci/pci.ids	2004-01-29 10:58:21.000000000 -0800
@@ -4511,6 +4511,7 @@
 	9132  Ethernet 100/10 MBit
 1283  Integrated Technology Express, Inc.
 	673a  IT8330G
+	8181  IT8181E/F LCD/VGA Controller
 	8330  IT8330G
 	8888  IT8888F PCI to ISA Bridge with SMB
 	8889  IT8889F PCI to ISA Bridge
diff -urN linux-2.4.25-pre7/drivers/sbus/char/flash.c linux-2.4.25-pre8/drivers/sbus/char/flash.c
--- linux-2.4.25-pre7/drivers/sbus/char/flash.c	2001-10-10 23:42:47.000000000 -0700
+++ linux-2.4.25-pre8/drivers/sbus/char/flash.c	2004-01-29 10:58:21.000000000 -0800
@@ -161,10 +161,13 @@
 {
 	struct sbus_bus *sbus;
 	struct sbus_dev *sdev = 0;
+#ifdef CONFIG_PCI
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev = 0;
 	struct linux_prom_registers regs[2];
-	int len, err, nregs;
+	int len, nregs;
+#endif
+	int err;
 
 	for_all_sbusdev(sdev, sbus) {
 		if (!strcmp(sdev->prom_name, "flashprom")) {
diff -urN linux-2.4.25-pre7/drivers/scsi/aha152x.c linux-2.4.25-pre8/drivers/scsi/aha152x.c
--- linux-2.4.25-pre7/drivers/scsi/aha152x.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/scsi/aha152x.c	2004-01-29 10:58:21.000000000 -0800
@@ -222,10 +222,6 @@
 
 #include <linux/module.h>
 
-#if defined(PCMCIA)
-#undef MODULE
-#endif
-
 #include <linux/sched.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -254,6 +250,10 @@
 
 #include <scsi/scsicam.h>
 
+#if defined(PCMCIA)
+#undef MODULE
+#endif
+
 /* DEFINES */
 
 /* For PCMCIA cards, always use AUTOCONF */
@@ -3951,7 +3951,9 @@
 	return thislength < length ? thislength : length;
 }
 
+#ifndef PCMCIA
 /* Eventually this will go into an include file, but this will be later */
 static Scsi_Host_Template driver_template = AHA152X;
 
 #include "scsi_module.c"
+#endif
diff -urN linux-2.4.25-pre7/drivers/scsi/fdomain.c linux-2.4.25-pre8/drivers/scsi/fdomain.c
--- linux-2.4.25-pre7/drivers/scsi/fdomain.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.25-pre8/drivers/scsi/fdomain.c	2004-01-29 10:58:21.000000000 -0800
@@ -2046,7 +2046,9 @@
 
 MODULE_LICENSE("GPL");
 
+#ifndef PCMCIA
 /* Eventually this will go into an include file, but this will be later */
 static Scsi_Host_Template driver_template = FDOMAIN_16X0;
 
 #include "scsi_module.c"
+#endif
diff -urN linux-2.4.25-pre7/drivers/scsi/qlogicfas.c linux-2.4.25-pre8/drivers/scsi/qlogicfas.c
--- linux-2.4.25-pre7/drivers/scsi/qlogicfas.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.25-pre8/drivers/scsi/qlogicfas.c	2004-01-29 10:58:21.000000000 -0800
@@ -111,10 +111,6 @@
 
 #include <linux/module.h>
 
-#ifdef PCMCIA
-#undef MODULE
-#endif 
-
 #include <linux/blk.h>	/* to get disk capacity */
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -131,6 +127,10 @@
 #include "qlogicfas.h"
 #include <linux/stat.h>
 
+#ifdef PCMCIA
+#undef MODULE
+#endif 
+
 /*----------------------------------------------------------------*/
 /* driver state info, local to driver */
 static int	    qbase;	/* Port */
@@ -647,7 +647,7 @@
 	if(request_irq(qlirq, do_ql_ihandl, SA_SHIRQ, "qlogicfas", hreg) < 0)
 #endif	
 	{
-		scsi_unregister(host);
+		scsi_unregister(hreg);
 		goto err_release_mem;
 	}
 #endif
@@ -717,7 +717,9 @@
 }
 MODULE_LICENSE("GPL");
 
+#ifndef PCMCIA
 /* Eventually this will go into an include file, but this will be later */
 static Scsi_Host_Template driver_template = QLOGICFAS;
 #include "scsi_module.c"
+#endif
 
diff -urN linux-2.4.25-pre7/drivers/usb/Config.in linux-2.4.25-pre8/drivers/usb/Config.in
--- linux-2.4.25-pre7/drivers/usb/Config.in	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/Config.in	2004-01-29 10:58:21.000000000 -0800
@@ -92,7 +92,6 @@
       dep_tristate '  USB Realtek RTL8150 based ethernet device support (EXPERIMENTAL)' CONFIG_USB_RTL8150 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-      dep_tristate '  USB ASIX AX88172 based ethernet device support (EXPERIMENTAL)' CONFIG_USB_AX8817X $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    fi
diff -urN linux-2.4.25-pre7/drivers/usb/Makefile linux-2.4.25-pre8/drivers/usb/Makefile
--- linux-2.4.25-pre7/drivers/usb/Makefile	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/Makefile	2004-01-29 10:58:21.000000000 -0800
@@ -110,7 +110,6 @@
 obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o
 obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_KAWETH)        += kaweth.o
-obj-$(CONFIG_USB_AX8817X)	+= ax8817x.o
 obj-$(CONFIG_USB_CDCETHER)	+= CDCEther.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
 obj-$(CONFIG_USB_TIGL)          += tiglusb.o
diff -urN linux-2.4.25-pre7/drivers/usb/auermain.c linux-2.4.25-pre8/drivers/usb/auermain.c
--- linux-2.4.25-pre7/drivers/usb/auermain.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/auermain.c	2004-01-29 10:58:21.000000000 -0800
@@ -2,7 +2,7 @@
 /*
  *      auermain.c  --  Auerswald PBX/System Telephone usb driver.
  *
- *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
+ *      Copyright (C) 2002-2004  Wolfgang Mües (wolfgang@iksw-muees.de)
  *
  *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
  *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
@@ -55,7 +55,7 @@
 
 /*-------------------------------------------------------------------*/
 /* Version Information */
-#define DRIVER_VERSION "1.2.3"
+#define DRIVER_VERSION "1.2.6"
 #define DRIVER_AUTHOR  "Wolfgang Mües <wolfgang@iksw-muees.de>"
 #define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
 
@@ -828,9 +828,10 @@
 static struct usb_device_id auerswald_ids[] = {
 	{USB_DEVICE(ID_AUERSWALD, 0x00C0)},	/* COMpact 2104 USB/DSL */
 	{USB_DEVICE(ID_AUERSWALD, 0x00DB)},	/* COMpact 4410/2206 USB */
-	{USB_DEVICE(ID_AUERSWALD, 0x00DC)},	/* comming soon... */
-	{USB_DEVICE(ID_AUERSWALD, 0x00F1)},	/* Comfort 2000 System Telephone */
-	{USB_DEVICE(ID_AUERSWALD, 0x00F2)},	/* Comfort 1200 System Telephone */
+	{USB_DEVICE(ID_AUERSWALD, 0x00DC)},	/* COMpact 4406 DSL */
+	{USB_DEVICE(ID_AUERSWALD, 0x00DD)},	/* COMpact 2204 USB */
+	{USB_DEVICE(ID_AUERSWALD, 0x00F1)},	/* COMfort 2000 System Telephone */
+	{USB_DEVICE(ID_AUERSWALD, 0x00F2)},	/* COMfort 1200 System Telephone */
 	{}					/* Terminating entry */
 };
 
diff -urN linux-2.4.25-pre7/drivers/usb/ax8817x.c linux-2.4.25-pre8/drivers/usb/ax8817x.c
--- linux-2.4.25-pre7/drivers/usb/ax8817x.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/ax8817x.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1291 +0,0 @@
-/*
- * ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver
- *
- * $Id: ax8817x.c,v 1.15 2003/06/15 18:45:21 dhollis Exp $
- *
- * Copyright (c) 2002-2003 TiVo Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * History 
- *
- *	2003-06-28 - Dave Hollis <dhollis@davehollis.com>  1.0.2
- *		* Added support for Intellinet
- *	2003-06-12 - Dave Hollis <dhollis@davehollis.com>  1.0.1
- *		* use usb_make_path for ethtool info
- *		* Use crc32.h for crc functions
- *		* Additional callback cases for other host ctrlrs
- *		* Force minimum default rcv buffers
- *
- *	2003-06-12 - Dave Hollis <dhollis@davehollis.com>  1.0.0
- *		* Backport removal of multiple tx_urb / lengthy 
- *		  start_xmit routines, etc.
- *		* ethtool driver name returns driver name, not
- *		  long description
- *
- *	2003-06-05 - Dave Hollis <dhollis@davehollis.com>  0.9.9
- *		* Cleanup unnecessary #if 0
- *		* Fix coding style to match kernel style
- *
- *	2003-05-31 - Dave Hollis <dhollis@davehollis.com>  0.9.8
- *		* Don't stop/start the queue in start_xmit
- *		* Swallow URB status upon hard removal
- *		* Cleanup remaining comments (kill // style)
- *
- *	2003-05-29 - Dave Hollis <dhollis@davehollis.com>  0.9.7
- *		* Set module owner
- *		* Follow-up on suggestions from David Brownell &
- *		  Oliver Neukum which should help with robustness
- *		* Use ether_crc from stock kernel if available
- *
- *	2003-05-28 - Dave Hollis <dhollis@davehollis.com>  0.9.6
- *		* Added basic ethtool & mii support
- *
- *	2003-05-28 - Dave Hollis <dhollis@davehollis.com>  0.9.5
- *		* Workout devrequest change to usb_ctrlrequest structure
- *		* Replace FILL_BULK_URB macros to non-deprecated 
- *		  usb_fill_bulk_urb macros
- *		* Replace printks with equivalent macros
- *		* Use defines for module description, version, author to
- *		  simplify future changes
- *
- * Known Issues
- *	usb-uhci.c: process_transfer: fixed toggle message to console
- *		Possible bug in usb-uhci or bug in this driver that
- *		makes it spit that out.  Doesn't seem to have harmful
- *		effects.
- *
- * Todo
- *	Fix mii/ethtool output
-*/
-
-#include <linux/slab.h>
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <linux/mii.h>
-#include <asm/uaccess.h>
-#include <linux/crc32.h>
-
-/* Version Information */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "TiVo, Inc."
-#define DRIVER_DESC "ASIX AX8817x USB Ethernet driver"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
-
-
-#define AX_REQ_READ         ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE )
-#define AX_REQ_WRITE        ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE )
-
-#define AX_CMD_SET_SW_MII           0x06
-#define AX_CMD_READ_MII_REG         0x07
-#define AX_CMD_WRITE_MII_REG        0x08
-#define AX_CMD_SET_HW_MII           0x0a
-#define AX_CMD_WRITE_RX_CTL         0x10
-#define AX_CMD_WRITE_MULTI_FILTER   0x16
-#define AX_CMD_READ_NODE_ID         0x17
-#define AX_CMD_READ_PHY_ID          0x19
-#define AX_CMD_WRITE_MEDIUM_MODE    0x1b
-#define AX_CMD_WRITE_GPIOS          0x1f
-
-#define AX_RX_MAX                   ETH_FRAME_LEN
-#define AX_TIMEOUT_CMD              ( HZ / 10 )
-#define AX_TIMEOUT_TX               ( HZ * 2 )
-#define AX_MAX_MCAST                64
-
-#define AX_DRV_STATE_INITIALIZING   0x00
-#define AX_DRV_STATE_RUNNING        0x01
-#define AX_DRV_STATE_EXITING        0x02
-
-#define AX_PHY_STATE_INITIALIZING   0x00
-#define AX_PHY_STATE_NO_LINK        0x01
-#define AX_PHY_STATE_POLLING_1      0x02
-#define AX_PHY_STATE_POLLING_2      0x03
-#define AX_PHY_STATE_POLLING_3      0x04
-#define AX_PHY_STATE_POLLING_4      0x05
-#define AX_PHY_STATE_SETTING_MAC    0x06
-#define AX_PHY_STATE_LINK           0x07
-#define AX_PHY_STATE_ABORT_POLL     0x08
-#define AX_PHY_STATE_ABORTING       0x09
-
-#define AX_MAX_PHY_RETRY            50
-
-#define AX_RX_URBS_DEFAULT	    2
-
-static const char driver_name[] = "ax8817x";
-static int n_rx_urbs = AX_RX_URBS_DEFAULT;
-
-MODULE_PARM(n_rx_urbs, "i");
-MODULE_PARM_DESC(n_rx_urbs,
-		 "Number of rx buffers to queue at once (def 2)");
-
-struct ax8817x_info;
-struct ax_cmd_req;
-typedef int (*ax_cmd_callback_t) (struct ax8817x_info *,
-				  struct ax_cmd_req *);
-
-struct ax_cmd_req {
-	struct list_head list;
-	ax_cmd_callback_t cmd_callback;
-	void *priv;
-	int status;
-	void *data;
-	int data_size;
-	int timeout;
-	struct usb_ctrlrequest devreq;
-};
-
-struct ax8817x_info {
-	struct usb_device *usb;
-	struct net_device *net;
-	struct urb **rx_urbs;
-	struct urb *tx_urb;
-	struct urb *int_urb;
-	u8 *int_buf;
-	struct urb *ctl_urb;
-	struct list_head ctl_queue;
-	spinlock_t ctl_lock;
-	atomic_t rx_refill_cnt;
-	int tx_head;
-	int tx_tail;
-	spinlock_t tx_lock;
-	struct net_device_stats stats;
-	struct ax_cmd_req phy_req;
-	u8 phy_id;
-	u8 phy_state;
-	u8 drv_state;
-};
-
-
-const struct usb_device_id ax8817x_id_table[] __devinitdata = {
-	/* Linksys USB200M */
-      {USB_DEVICE(0x077b, 0x2226), driver_info:0x00130103},
-	/* Hawking UF200, TRENDnet TU2-ET100 */
-      {USB_DEVICE(0x07b8, 0x420a), driver_info:0x001f1d1f},
-	/* NETGEAR FA120 */
-      {USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103},
-	/* D-Link DUB-E100 */
-      {USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f},
-	/* Intellinet USB Ethernet*/
-      {USB_DEVICE(0x0b95, 0x1720), driver_info:0x00130103},
-
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, ax8817x_id_table);
-
-static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *,
-			     int);
-static void ax_rx_callback(struct urb *urb);
-
-static void ax_ctl_callback(struct urb *urb)
-{
-	struct ax8817x_info *ax_info =
-	    (struct ax8817x_info *) urb->context;
-
-	ax_run_ctl_queue(ax_info, NULL,
-			 urb->status ? urb->status : urb->actual_length);
-}
-
-/* 
- * Queue a new ctl request, or dequeue the first in the list
-*/
-static void ax_run_ctl_queue(struct ax8817x_info *ax_info,
-			     struct ax_cmd_req *req, int status)
-{
-	struct ax_cmd_req *next_req = NULL;
-	struct ax_cmd_req *last_req = NULL;
-	unsigned long flags;
-
-	/* Need to lock around queue list manipulation */
-	spin_lock_irqsave(&ax_info->ctl_lock, flags);
-
-	if (req == NULL) {
-		last_req =
-		    list_entry(ax_info->ctl_queue.next, struct ax_cmd_req,
-			       list);
-	} else {
-		if (list_empty(&ax_info->ctl_queue)) {
-			next_req = req;
-		}
-
-		req->status = -EINPROGRESS;
-		list_add_tail(&req->list, &ax_info->ctl_queue);
-	}
-
-	while (1) {
-		if (last_req != NULL) {
-			/* dequeue completed entry */
-			list_del(&last_req->list);
-
-			last_req->status = status;
-			if (last_req->cmd_callback(ax_info, last_req)) {
-				/* requeue if told to do so */
-				last_req->status = -EINPROGRESS;
-				list_add_tail(&last_req->list,
-					      &ax_info->ctl_queue);
-			}
-
-			if (list_empty(&ax_info->ctl_queue)) {
-				next_req = NULL;
-			} else {
-				next_req =
-				    list_entry(ax_info->ctl_queue.next,
-					       struct ax_cmd_req, list);
-			}
-		}
-
-		spin_unlock_irqrestore(&ax_info->ctl_lock, flags);
-
-		if (next_req == NULL) {
-			break;
-		}
-
-		/* XXX: do something with timeout */
-		usb_fill_control_urb(ax_info->ctl_urb, ax_info->usb,
-				     next_req->devreq.
-				     bRequestType & USB_DIR_IN ?
-				     usb_rcvctrlpipe(ax_info->usb,
-						     0) :
-				     usb_sndctrlpipe(ax_info->usb, 0),
-				     (void *) &next_req->devreq,
-				     next_req->data, next_req->data_size,
-				     ax_ctl_callback, ax_info);
-
-		status = usb_submit_urb(ax_info->ctl_urb);
-		if (status >= 0) {
-			break;
-		}
-
-		last_req = next_req;
-
-		spin_lock_irqsave(&ax_info->ctl_lock, flags);
-	}
-}
-
-static int ax_sync_cmd_callback(struct ax8817x_info *unused,
-				struct ax_cmd_req *req)
-{
-	wait_queue_head_t *wq = (wait_queue_head_t *) req->priv;
-
-	wake_up(wq);
-
-	return 0;
-}
-
-static int ax_async_cmd_callback(struct ax8817x_info *unused,
-				 struct ax_cmd_req *req)
-{
-	if (req->status < 0) {
-		err("%s: Async command %d failed: %d\n", __FUNCTION__,
-		    req->devreq.bRequest, req->status);
-	}
-
-	/* Nothing else to do here, just need to free the request (and its
-	   allocated data) */
-	if (req->data != NULL) {
-		kfree(req->data);
-	}
-	kfree(req);
-
-	return 0;
-}
-
-/*
- * This is mostly the same as usb_control_msg(), except that it is able
- * to queue control messages
-*/
-static int ax_control_msg(struct ax8817x_info *ax_info, u8 requesttype,
-			  u8 request, u16 value, u16 index, void *data,
-			  u16 size, int timeout)
-{
-	struct ax_cmd_req *req;
-	DECLARE_WAIT_QUEUE_HEAD(wq);
-	DECLARE_WAITQUEUE(wait, current);
-	int ret;
-
-	req = kmalloc(sizeof(struct ax_cmd_req), GFP_KERNEL);
-	if (req == NULL) {
-		return -ENOMEM;
-	}
-
-	req->devreq.bRequestType = requesttype;
-	req->devreq.bRequest = request;
-	req->devreq.wValue = cpu_to_le16(value);
-	req->devreq.wIndex = cpu_to_le16(index);
-	req->devreq.wLength = cpu_to_le16(size);
-	req->data = data;
-	req->data_size = size;
-	req->timeout = timeout;
-
-	req->priv = &wq;
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&wq, &wait);
-
-	req->cmd_callback = ax_sync_cmd_callback;
-
-	ax_run_ctl_queue(ax_info, req, 0);
-	schedule();
-
-	ret = req->status;
-
-	kfree(req);
-
-	return ret;
-}
-
-/*
- * Same, but can be used asynchronously, may fail, and returns no exit
- * status
-*/
-static void ax_control_msg_async(struct ax8817x_info *ax_info,
-				 u8 requesttype, u8 request, u16 value,
-				 u16 index, void *data, u16 size,
-				 int timeout)
-{
-	struct ax_cmd_req *req;
-
-	req = kmalloc(sizeof(struct ax_cmd_req), GFP_ATOMIC);
-	if (req == NULL) {
-		/* There's not much else we can do here... */
-		err("%s: Failed alloc\n", __FUNCTION__);
-		return;
-	}
-
-	req->devreq.bRequestType = requesttype;
-	req->devreq.bRequest = request;
-	req->devreq.wValue = cpu_to_le16(value);
-	req->devreq.wIndex = cpu_to_le16(index);
-	req->devreq.wLength = cpu_to_le16(size);
-	req->data = data;
-	req->data_size = size;
-	req->timeout = timeout;
-
-	req->cmd_callback = ax_async_cmd_callback;
-
-	ax_run_ctl_queue(ax_info, req, 0);
-}
-
-static inline int ax_read_cmd(struct ax8817x_info *ax_info, u8 cmd,
-			      u16 value, u16 index, u16 size, void *data)
-{
-	return ax_control_msg(ax_info, AX_REQ_READ, cmd, value, index,
-			      data, size, AX_TIMEOUT_CMD);
-}
-
-static inline int ax_write_cmd(struct ax8817x_info *ax_info, u8 cmd,
-			       u16 value, u16 index, u16 size, void *data)
-{
-	return ax_control_msg(ax_info, AX_REQ_WRITE, cmd, value, index,
-			      data, size, AX_TIMEOUT_CMD);
-}
-
-static inline void ax_write_cmd_async(struct ax8817x_info *ax_info, u8 cmd,
-				      u16 value, u16 index, u16 size,
-				      void *data)
-{
-	ax_control_msg_async(ax_info, AX_REQ_WRITE, cmd, value, index,
-			     data, size, AX_TIMEOUT_CMD);
-}
-
-static int ax_refill_rx_urb(struct ax8817x_info *ax_info, struct urb *urb)
-{
-	struct sk_buff *skb;
-	int ret;
-
-	skb = dev_alloc_skb(AX_RX_MAX + 2);
-	if (skb != NULL) {
-		skb_reserve(skb, 2);	/* for IP header alignment */
-		skb->dev = ax_info->net;
-
-		usb_fill_bulk_urb(urb, ax_info->usb,
-				  usb_rcvbulkpipe(ax_info->usb, 3),
-				  skb->data, AX_RX_MAX, ax_rx_callback,
-				  skb);
-
-		ret = usb_submit_urb(urb);
-		if (ret < 0) {
-			err("Failed submit rx URB (%d)\n", ret);
-			dev_kfree_skb_irq(skb);
-			urb->context = NULL;
-		} else {
-			ret = 0;
-		}
-	} else {
-		/* this just means we're low on memory at the moment. Try to
-		   handle it gracefully. */
-		urb->context = NULL;
-		ret = 1;
-	}
-
-	return ret;
-}
-
-static int ax_phy_cmd_callback(struct ax8817x_info *ax_info,
-			       struct ax_cmd_req *req)
-{
-	int full_duplex;
-	int flow_control;
-	u16 mii_data_le;
-
-	if (req->status < 0) {
-		err("%s: Failed at state %d: %d\n", __FUNCTION__,
-		    ax_info->phy_state, req->status);
-		/* Not sure what else we can do, so just bail */
-		ax_info->phy_state = AX_PHY_STATE_ABORTING;
-	}
-
-	switch (ax_info->phy_state) {
-		/* Now that we're in software MII mode, read the BMSR */
-	case AX_PHY_STATE_POLLING_1:
-		ax_info->phy_state = AX_PHY_STATE_POLLING_2;
-		req->devreq.bRequestType = AX_REQ_READ;
-		req->devreq.bRequest = AX_CMD_READ_MII_REG;
-		req->devreq.wValue = cpu_to_le16(ax_info->phy_id);
-		req->devreq.wIndex = cpu_to_le16(MII_BMSR);
-		req->devreq.wLength = cpu_to_le16(2);
-		req->data_size = 2;
-		(long) req->priv = 0;	/* This is the retry count */
-		return 1;
-
-		/* Done reading BMSR */
-	case AX_PHY_STATE_POLLING_2:
-		mii_data_le = *(u16 *) req->data;
-		if ((mii_data_le &
-		     cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE))
-		    == cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) {
-			if (mii_data_le & cpu_to_le16(BMSR_ANEGCOMPLETE)) {
-				/* Autonegotiation done, go on to read LPA */
-				ax_info->phy_state =
-				    AX_PHY_STATE_POLLING_3;
-				req->devreq.wIndex = cpu_to_le16(MII_LPA);
-				return 1;
-			} else if ((long) req->priv++ < AX_MAX_PHY_RETRY) {
-				/* Reread BMSR if it's still autonegotiating. This is
-				   probably unnecessary logic, I've never seen it take
-				   more than 1 try... */
-				return 1;
-			}
-			/* else fall through to abort */
-		}
-		/* XXX: should probably handle auto-neg failure better,
-		   by reverting to manual setting of something safe. (?) */
-
-		ax_info->phy_state = AX_PHY_STATE_ABORT_POLL;
-		/* and then fall through to set hw MII */
-
-		/* Got what we needed from PHY, set back to hardware MII mode
-		   (Do same for abort in mid-poll) */
-	case AX_PHY_STATE_POLLING_3:
-	case AX_PHY_STATE_ABORT_POLL:
-		ax_info->phy_state += 1;
-		req->devreq.bRequestType = AX_REQ_WRITE;
-		req->devreq.bRequest = AX_CMD_SET_HW_MII;
-		req->devreq.wValue = cpu_to_le16(0);
-		req->devreq.wIndex = cpu_to_le16(0);
-		req->devreq.wLength = cpu_to_le16(0);
-		req->data_size = 0;
-		return 1;
-
-		/* The end result, set the right duplex and flow control mode in the
-		   MAC (based on the PHY's LPA reg, which should still be in the data
-		   buffer) */
-	case AX_PHY_STATE_POLLING_4:
-		mii_data_le = *(u16 *) req->data;
-		ax_info->phy_state = AX_PHY_STATE_SETTING_MAC;
-		req->devreq.bRequest = AX_CMD_WRITE_MEDIUM_MODE;
-		full_duplex = mii_data_le & cpu_to_le16(LPA_DUPLEX);
-		flow_control = full_duplex &&
-		    (mii_data_le & cpu_to_le16(0x0400));
-		req->devreq.wValue = cpu_to_le16(0x04) |
-		    (full_duplex ? cpu_to_le16(0x02) : 0) |
-		    (flow_control ? cpu_to_le16(0x10) : 0);
-		info("%s: Link established, %s duplex, flow control %sabled\n", ax_info->net->name, full_duplex ? "full" : "half", flow_control ? "en" : "dis");
-		return 1;
-
-		/* All done */
-	case AX_PHY_STATE_SETTING_MAC:
-		ax_info->phy_state = AX_PHY_STATE_LINK;
-		netif_carrier_on(ax_info->net);
-		return 0;
-
-	default:
-		err("%s: Unknown state %d\n", __FUNCTION__,
-		    ax_info->phy_state);
-		/* fall through */
-	case AX_PHY_STATE_ABORTING:
-		ax_info->phy_state = AX_PHY_STATE_NO_LINK;
-		return 0;
-	}
-}
-
-static void ax_int_callback(struct urb *urb)
-{
-	struct ax8817x_info *ax_info =
-	    (struct ax8817x_info *) urb->context;
-	u8 phy_link;
-
-	if (ax_info->drv_state == AX_DRV_STATE_EXITING ||
-	    urb->actual_length < 3) {
-		return;
-	}
-
-	/* Ignore the first PHY link report, it will sometimes be reported as
-	   link active, even though we just told the PHY to reset. If it
-	   really has link, we'll pick it up next int callback.
-	 */
-	if (ax_info->phy_state == AX_PHY_STATE_INITIALIZING) {
-		netif_carrier_off(ax_info->net);
-		ax_info->phy_state = AX_PHY_STATE_NO_LINK;
-		return;
-	}
-
-	/* Assume we're only interested in the primary PHY for now. */
-	phy_link = ax_info->int_buf[2] & 1;
-
-	if (phy_link ==
-	    (ax_info->phy_state == AX_PHY_STATE_NO_LINK) ? 0 : 1) {
-		/* Common case, no change */
-		return;
-	}
-
-	if (phy_link == 0) {
-		netif_carrier_off(ax_info->net);
-		/* Abort an in-progress poll of the PHY if necessary */
-		switch (ax_info->phy_state) {
-		case AX_PHY_STATE_POLLING_1:
-		case AX_PHY_STATE_POLLING_2:
-		case AX_PHY_STATE_POLLING_3:
-			ax_info->phy_state = AX_PHY_STATE_ABORT_POLL;
-			break;
-
-		case AX_PHY_STATE_POLLING_4:
-		case AX_PHY_STATE_SETTING_MAC:
-			ax_info->phy_state = AX_PHY_STATE_ABORTING;
-			break;
-
-		case AX_PHY_STATE_LINK:
-			ax_info->phy_state = AX_PHY_STATE_NO_LINK;
-			break;
-
-		default:
-			/* If we're already aborting, continue aborting */
-			break;
-		}
-	} else {
-		/* Note that we only fall into this case if previous phy_state was
-		   AX_PHY_STATE_NO_LINK. When the link is reported active while
-		   we're still polling, or when we're aborting, the logic above
-		   will just return, and we'll check again next int callback. */
-
-		ax_info->phy_state = AX_PHY_STATE_POLLING_1;
-		ax_info->phy_req.devreq.bRequestType = AX_REQ_WRITE;
-		ax_info->phy_req.devreq.bRequest = AX_CMD_SET_SW_MII;
-		ax_info->phy_req.devreq.wValue = cpu_to_le16(0);
-		ax_info->phy_req.devreq.wIndex = cpu_to_le16(0);
-		ax_info->phy_req.devreq.wLength = cpu_to_le16(0);
-		ax_info->phy_req.data_size = 0;
-		ax_info->phy_req.timeout = AX_TIMEOUT_CMD;
-		ax_info->phy_req.cmd_callback = ax_phy_cmd_callback;
-
-		ax_run_ctl_queue(ax_info, &ax_info->phy_req, 0);
-	}
-}
-
-static void ax_rx_callback(struct urb *urb)
-{
-	struct sk_buff *skb = (struct sk_buff *) urb->context;
-	struct net_device *net = skb->dev;
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-	int ret, len, refill;
-
-	switch (urb->status) {
-	case 0:
-		break;
-
-	default:
-		err("%s: URB status %d\n", __FUNCTION__, urb->status);
-		/* It's not clear that we can do much in this case, the rx pipe
-		   doesn't ever seem to stall, so if we got -ETIMEDOUT, that
-		   usually means the device was unplugged, and we just haven't
-		   noticed yet.
-		   Just fall through and free skb without resubmitting urb. */
-	case -ENOENT:		/* */
-	case -ECONNRESET:	/* Async unlink */
-	case -ESHUTDOWN:	/* Hardware gone */
-	case -EILSEQ:		/* Get this when you yank it out on UHCI */
-	case -ETIMEDOUT:	/* OHCI */
-	case -EPROTO:		/* EHCI */
-	case -EPIPE:		
-		dev_kfree_skb_any(skb);
-		urb->context = NULL;
-		return;
-	}
-
-	if (ax_info->drv_state == AX_DRV_STATE_INITIALIZING) {
-		/* Not really expecting this to ever happen, since we haven't yet
-		   enabled receive in the rx_ctl register, but ya never know... */
-		goto refill_same;
-	} else if (ax_info->drv_state == AX_DRV_STATE_EXITING) {
-		dev_kfree_skb_any(skb);
-		urb->context = NULL;
-		return;
-	}
-
-	len = urb->actual_length;
-	if (len == 0) {
-		/* this shouldn't happen... */
-		goto refill_same;
-	}
-
-	refill = ax_refill_rx_urb(ax_info, urb);
-
-	if (refill == 0
-	    || atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) {
-		/* Send the receive buffer up the network stack */
-		skb_put(skb, len);
-		skb->protocol = eth_type_trans(skb, net);
-		net->last_rx = jiffies;
-		ax_info->stats.rx_packets++;
-		ax_info->stats.rx_bytes += len;
-
-		netif_rx(skb);
-
-		if (refill == 0) {
-			int i;
-
-			/* This is the common case. This URB got refilled OK, and
-			   no other URBs need to be refilled. */
-			if (atomic_read(&ax_info->rx_refill_cnt) == 0) {
-				return;
-			}
-
-			for (i = 0; i < n_rx_urbs; i++) {
-				struct urb *urb = ax_info->rx_urbs[i];
-
-				if (urb->context == NULL) {
-					if (ax_refill_rx_urb(ax_info, urb)
-					    == 0) {
-						atomic_dec(&ax_info->
-							   rx_refill_cnt);
-					} else {
-						break;
-					}
-				}
-			}
-		} else {
-			/* remember to refill this one later */
-			atomic_inc(&ax_info->rx_refill_cnt);
-		}
-
-		return;
-	} else {
-		ax_info->stats.rx_dropped++;
-		if (refill < 0) {
-			/* the error code was already printk'ed in ax_refill_rx_urb()
-			   so just note the consequences here: */
-			warn("Halting rx due to error\n");
-			return;
-		}
-
-		/* fall through to resubmit this URB with the existing skb
-		   will try to reallocate skb's on next rx callback */
-	}
-
-      refill_same:
-	usb_fill_bulk_urb(urb, ax_info->usb,
-			  usb_rcvbulkpipe(ax_info->usb, 3), skb->data,
-			  AX_RX_MAX, ax_rx_callback, skb);
-
-	ret = usb_submit_urb(urb);
-	if (ret < 0) {
-		err("Failed submit rx URB (%d)\n", ret);
-	}
-}
-
-static int ax8817x_open(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-	u8 buf[4];
-	int i, ret;
-
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf);
-	if (ret < 0) {
-		return ret;
-	}
-
-	ret = 0;
-
-	ax_info->tx_urb = usb_alloc_urb(0);
-	if (ax_info->tx_urb == NULL)
-		ret = -ENOMEM;
-
-	atomic_set(&ax_info->rx_refill_cnt, 0);
-
-	for (i = 0; i < n_rx_urbs && ret == 0; i++) {
-		struct urb *urb = ax_info->rx_urbs[i];
-
-		if (urb == NULL) {
-			urb = ax_info->rx_urbs[i] = usb_alloc_urb(0);
-			if (urb == NULL) {
-				ret = -ENOMEM;
-				break;
-			}
-			if (n_rx_urbs > 1) {
-				urb->transfer_flags |= USB_QUEUE_BULK;
-			}
-		}
-		ret = ax_refill_rx_urb(ax_info, urb);
-		if (ret == 1) {
-			atomic_inc(&ax_info->rx_refill_cnt);
-			ret = 0;
-		}
-	}
-
-	/* XXX: should handle the case where we couldn't allocate any skb's
-	   better. They get allocated with GFP_ATOMIC, so they may all fail... */
-	if (ret == 0 && atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) {
-		netif_start_queue(net);
-	} else {
-		/* Error: clean up anything we allocated and bail. */
-		usb_free_urb(ax_info->tx_urb);
-
-		for (i = 0; i < n_rx_urbs; i++) {
-			struct urb *urb = ax_info->rx_urbs[i];
-
-			if (urb != NULL) {
-				/* skb gets freed in the URB callback */
-				usb_unlink_urb(urb);
-				usb_free_urb(urb);
-			}
-		}
-
-		err("%s: Failed start rx queue (%d)\n", __FUNCTION__, ret);
-	}
-	return ret;
-}
-
-static int ax8817x_stop(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-	u8 buf[4];
-	int i, ret;
-
-	netif_stop_queue(net);
-
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf);
-	if (ret < 0 && ax_info->drv_state != AX_DRV_STATE_EXITING) {
-		err("%s: Failed cmd (%d)\n", __FUNCTION__, ret);
-	}
-
-	if (ax_info->tx_urb != NULL) {
-		usb_unlink_urb(ax_info->tx_urb);
-		usb_free_urb(ax_info->tx_urb);
-		ax_info->tx_urb = NULL;
-	}
-
-	for (i = 0; i < n_rx_urbs; i++) {
-		struct urb *urb = ax_info->rx_urbs[i];
-		if (urb != NULL) {
-			/* skb gets freed in the URB callback */
-			usb_unlink_urb(urb);
-			usb_free_urb(urb);
-			ax_info->rx_urbs[i] = NULL;
-		}
-	}
-
-	return 0;
-}
-
-static void write_bulk_callback(struct urb *urb)
-{
-	struct ax8817x_info *ax_info = urb->context;
-
-	if (!ax_info || (ax_info->drv_state == AX_DRV_STATE_EXITING))
-		return;
-
-	if (!netif_device_present(ax_info->net))
-		return;
-
-	if (urb->status)
-		info("%s: TX status %d", ax_info->net->name, urb->status);
-
-	ax_info->net->trans_start = jiffies;
-	netif_wake_queue(ax_info->net);
-}
-
-static int ax8817x_start_xmit(struct sk_buff *skb, struct net_device *net)
-{
-	struct ax8817x_info *ax_info = net->priv;
-	int res;
-
-	netif_stop_queue(net);
-
-	ax_info->tx_urb->transfer_flags |= USB_ZERO_PACKET;
-	usb_fill_bulk_urb(ax_info->tx_urb, ax_info->usb,
-			  usb_sndbulkpipe(ax_info->usb, 2),
-			  skb->data, skb->len, write_bulk_callback,
-			  ax_info);
-	if ((res = usb_submit_urb(ax_info->tx_urb))) {
-		warn("Failed tx_urb %d", res);
-		ax_info->stats.tx_errors++;
-		netif_start_queue(net);
-	} else {
-		ax_info->stats.tx_packets++;
-		ax_info->stats.tx_bytes += skb->len;
-		net->trans_start = jiffies;
-	}
-	dev_kfree_skb(skb);
-
-	return 0;
-}
-
-static void ax8817x_tx_timeout(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = net->priv;
-
-	if (!ax_info)
-		return;
-
-	warn("%s: Tx timed out.", net->name);
-	ax_info->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb(ax_info->tx_urb);
-	ax_info->stats.tx_errors++;
-}
-
-static struct net_device_stats *ax8817x_stats(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-
-	return &ax_info->stats;
-}
-
-static void ax8817x_set_multicast(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-	u8 rx_ctl = 0x8c;
-
-	if (net->flags & IFF_PROMISC) {
-		rx_ctl |= 0x01;
-	} else if (net->flags & IFF_ALLMULTI
-		   || net->mc_count > AX_MAX_MCAST) {
-		rx_ctl |= 0x02;
-	} else if (net->mc_count == 0) {
-		/* just broadcast and directed */
-	} else {
-		struct dev_mc_list *mc_list = net->mc_list;
-		u8 *multi_filter;
-		u32 crc_bits;
-		int i;
-
-		multi_filter = kmalloc(8, GFP_ATOMIC);
-		if (multi_filter == NULL) {
-			/* Oops, couldn't allocate a DMA buffer for setting the multicast
-			   filter. Try all multi mode, although the ax_write_cmd_async
-			   will almost certainly fail, too... (but it will printk). */
-			rx_ctl |= 0x02;
-		} else {
-			memset(multi_filter, 0, 8);
-
-			/* Build the multicast hash filter. */
-			for (i = 0; i < net->mc_count; i++) {
-				crc_bits =
-				    ether_crc(ETH_ALEN,
-					      mc_list->dmi_addr) >> 26;
-				multi_filter[crc_bits >> 3] |=
-				    1 << (crc_bits & 7);
-				mc_list = mc_list->next;
-			}
-
-			ax_write_cmd_async(ax_info,
-					   AX_CMD_WRITE_MULTI_FILTER, 0, 0,
-					   8, multi_filter);
-
-			rx_ctl |= 0x10;
-		}
-	}
-
-	ax_write_cmd_async(ax_info, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0,
-			   NULL);
-}
-
-static int ax8817x_ethtool_ioctl(struct net_device *net, void *uaddr)
-{
-	struct ax8817x_info *ax_info;
-	int cmd;
-
-	ax_info = net->priv;
-	if (get_user(cmd, (int *) uaddr))
-		return -EFAULT;
-
-	switch (cmd) {
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-
-			strncpy(info.driver, driver_name,
-				ETHTOOL_BUSINFO_LEN);
-			strncpy(info.version, DRIVER_VERSION,
-				ETHTOOL_BUSINFO_LEN);
-			usb_make_path(ax_info->usb, info.bus_info,
-				      sizeof info.bus_info);
-			if (copy_to_user(uaddr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GSET:{
-			struct ethtool_cmd ecmd;
-
-			if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-				return -EFAULT;
-			ecmd.supported = (SUPPORTED_10baseT_Half |
-					  SUPPORTED_10baseT_Full |
-					  SUPPORTED_100baseT_Half |
-					  SUPPORTED_100baseT_Full |
-					  SUPPORTED_Autoneg |
-					  SUPPORTED_TP | SUPPORTED_MII);
-			ecmd.port = PORT_TP;
-			ecmd.transceiver = XCVR_INTERNAL;
-			ecmd.phy_address = 0;	/* FIXME */
-
-			if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SSET:
-		return -ENOTSUPP;
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-
-			edata.data = netif_carrier_ok(net);
-			if (copy_to_user(uaddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static int ax8817x_mii_ioctl(struct net_device *net, struct ifreq *ifr,
-			     int cmd)
-{
-	struct ax8817x_info *ax_info;
-	struct mii_ioctl_data *data_ptr =
-	    (struct mii_ioctl_data *) &(ifr->ifr_data);
-
-	ax_info = net->priv;
-
-	switch (cmd) {
-	case SIOCGMIIPHY:
-		data_ptr->phy_id = ax_info->phy_id;
-		break;
-	case SIOCGMIIREG:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-
-		ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, 0,
-			    data_ptr->reg_num & 0x1f, 2,
-			    &(data_ptr->val_out));
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
-}
-
-static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr,
-			 int cmd)
-{
-	struct ax8817x_info *ax_info;
-	int res;
-
-	ax_info = net->priv;
-	res = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		res = ax8817x_ethtool_ioctl(net, ifr->ifr_data);
-		break;
-	case SIOCGMIIPHY:	/* Get address of PHY in use */
-	case SIOCGMIIREG:	/* Read from MII PHY register */
-	case SIOCSMIIREG:	/* Write to MII PHY register */
-		return ax8817x_mii_ioctl(net, ifr, cmd);
-	default:
-		res = -EOPNOTSUPP;
-	}
-
-	return res;
-}
-
-static int ax8817x_net_init(struct net_device *net)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv;
-	u8 buf[6];
-	u16 *buf16 = (u16 *) buf;
-	int ret;
-
-	spin_lock_init(&ax_info->tx_lock);
-
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf);
-	if (ret < 0) {
-		return ret;
-	}
-
-	memset(buf, 0, 6);
-
-	/* Get the MAC address */
-	ret = ax_read_cmd(ax_info, AX_CMD_READ_NODE_ID, 0, 0, 6, buf);
-	if (ret < 0) {
-		return ret;
-	}
-
-	memcpy(net->dev_addr, buf, 6);
-
-	/* Get the PHY id */
-	ret = ax_read_cmd(ax_info, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
-	if (ret < 0) {
-		return ret;
-	} else if (ret < 2) {
-		/* this should always return 2 bytes */
-		return -EIO;
-	}
-
-	/* Reset the PHY, and drop it into auto-negotiation mode */
-	ax_info->phy_id = buf[1];
-	ax_info->phy_state = AX_PHY_STATE_INITIALIZING;
-
-	ret = ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
-	if (ret < 0) {
-		return ret;
-	}
-
-	*buf16 = cpu_to_le16(BMCR_RESET);
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG,
-			   ax_info->phy_id, MII_BMCR, 2, buf16);
-	if (ret < 0) {
-		return ret;
-	}
-
-	/* Advertise that we can do full-duplex pause */
-	*buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400);
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG,
-			   ax_info->phy_id, MII_ADVERTISE, 2, buf16);
-	if (ret < 0) {
-		return ret;
-	}
-
-	*buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART);
-	ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG,
-			   ax_info->phy_id, MII_BMCR, 2, buf16);
-	if (ret < 0) {
-		return ret;
-	}
-
-	ret = ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
-	if (ret < 0) {
-		return ret;
-	}
-
-	net->open = ax8817x_open;
-	net->stop = ax8817x_stop;
-	net->hard_start_xmit = ax8817x_start_xmit;
-	net->tx_timeout = ax8817x_tx_timeout;
-	net->watchdog_timeo = AX_TIMEOUT_TX;
-	net->get_stats = ax8817x_stats;
-	net->do_ioctl = ax8817x_ioctl;
-	net->set_multicast_list = ax8817x_set_multicast;
-
-	return 0;
-}
-
-static void *ax8817x_bind(struct usb_device *usb, unsigned intf,
-			  const struct usb_device_id *id)
-{
-	struct ax8817x_info *ax_info;
-	struct net_device *net;
-	int i, ret;
-	unsigned long gpio_bits = id->driver_info;
-	u8 buf[2];
-
-	/* Allocate the URB lists along with the device info struct */
-	ax_info = kmalloc(sizeof(struct ax8817x_info) +
-			  n_rx_urbs * sizeof(struct urb *), GFP_KERNEL);
-	if (ax_info == NULL) {
-		err("%s: Failed ax alloc\n", __FUNCTION__);
-		goto exit_err;
-	}
-
-	memset(ax_info, 0, sizeof(struct ax8817x_info) +
-	       n_rx_urbs * sizeof(struct urb *));
-
-	ax_info->drv_state = AX_DRV_STATE_INITIALIZING;
-	ax_info->rx_urbs = (struct urb **) (ax_info + 1);
-	ax_info->usb = usb;
-
-	/* Set up the control URB queue */
-
-	INIT_LIST_HEAD(&ax_info->ctl_queue);
-	spin_lock_init(&ax_info->ctl_lock);
-	ax_info->ctl_urb = usb_alloc_urb(0);
-	if (ax_info->ctl_urb == NULL) {
-		goto exit_err_free_ax;
-	}
-
-	/* Toggle the GPIOs in a manufacturer/model specific way */
-
-	for (i = 2; i >= 0; i--) {
-		ret = ax_write_cmd(ax_info, AX_CMD_WRITE_GPIOS,
-				   (gpio_bits >> (i * 8)) & 0xff, 0, 0,
-				   buf);
-		if (ret < 0) {
-			goto exit_err_free_ax;
-		}
-		wait_ms(5);
-	}
-
-	/* Set up the net device */
-
-	net = alloc_etherdev(0);
-	if (net == NULL) {
-		err("%s: Failed net alloc\n", __FUNCTION__);
-		goto exit_err_free_ax;
-	}
-
-	ax_info->net = net;
-
-	SET_MODULE_OWNER(net);
-	net->init = ax8817x_net_init;
-	net->priv = ax_info;
-
-	ret = register_netdev(net);
-	if (ret < 0) {
-		err("%s: Failed net init (%d)\n", __FUNCTION__, ret);
-		goto exit_err_free_net;
-	}
-
-	/* Set up the interrupt URB, and start PHY state monitoring */
-
-	ax_info->int_urb = usb_alloc_urb(0);
-	if (ax_info->int_urb == NULL) {
-		goto exit_err_unregister_net;
-	}
-	ax_info->int_buf = kmalloc(8, GFP_KERNEL);
-	if (ax_info->int_buf == NULL) {
-		goto exit_err_free_int_urb;
-	}
-	ax_info->phy_req.data = kmalloc(2, GFP_KERNEL);
-	if (ax_info->phy_req.data == NULL) {
-		goto exit_err_free_int_buf;
-	}
-
-	usb_fill_int_urb(ax_info->int_urb, usb, usb_rcvintpipe(usb, 1),
-			 ax_info->int_buf, 8, ax_int_callback, ax_info,
-			 100);
-
-	ret = usb_submit_urb(ax_info->int_urb);
-	if (ret < 0) {
-		err("%s: Failed int URB submit (%d)\n", __FUNCTION__, ret);
-		goto exit_err_free_phy_buf;
-	}
-
-	ax_info->drv_state = AX_DRV_STATE_RUNNING;
-	return ax_info;
-
-      exit_err_free_phy_buf:
-	kfree(ax_info->phy_req.data);
-
-      exit_err_free_int_buf:
-	kfree(ax_info->int_buf);
-
-      exit_err_free_int_urb:
-	usb_free_urb(ax_info->int_urb);
-
-      exit_err_unregister_net:
-	ax_info->drv_state = AX_DRV_STATE_EXITING;
-	unregister_netdev(net);
-
-      exit_err_free_net:
-	kfree(net);
-
-      exit_err_free_ax:
-	if (ax_info->ctl_urb != NULL) {
-		/* no need to unlink, since there should not be any ctl URBs
-		   pending at this point */
-		usb_free_urb(ax_info->ctl_urb);
-	}
-
-	kfree(ax_info);
-
-      exit_err:
-	err("%s: Failed to initialize\n", __FUNCTION__);
-	return NULL;
-}
-
-static void ax8817x_disconnect(struct usb_device *usb, void *p)
-{
-	struct ax8817x_info *ax_info = (struct ax8817x_info *) p;
-
-	ax_info->drv_state = AX_DRV_STATE_EXITING;
-
-	if (ax_info->int_urb != NULL) {
-		usb_unlink_urb(ax_info->int_urb);
-		usb_free_urb(ax_info->int_urb);
-		kfree(ax_info->int_buf);
-	}
-
-	unregister_netdev(ax_info->net);
-
-	/* XXX: hmmm... need to go through and clear out the ctl queue, too... */
-	if (ax_info->ctl_urb != NULL) {
-		usb_unlink_urb(ax_info->ctl_urb);
-		usb_free_urb(ax_info->ctl_urb);
-	}
-
-	kfree(ax_info);
-}
-
-
-static struct usb_driver ax8817x_driver = {
-	.owner = THIS_MODULE,
-	.name = driver_name,
-	.probe = ax8817x_bind,
-	.disconnect = ax8817x_disconnect,
-	.id_table = ax8817x_id_table,
-};
-
-static int __init ax8817x_init(void)
-{
-	int ret;
-
-	if (n_rx_urbs < 1) 
-		n_rx_urbs = AX_RX_URBS_DEFAULT;
-
-	ret = usb_register(&ax8817x_driver);
-	if (ret < 0) {
-		err("%s: Failed to register\n", __FUNCTION__);
-	} else {
-		info(DRIVER_DESC " " DRIVER_VERSION);
-	}
-
-	return ret;
-}
-
-static void __exit ax8817x_exit(void)
-{
-	usb_deregister(&ax8817x_driver);
-}
-
-module_init(ax8817x_init);
-module_exit(ax8817x_exit);
-
-EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/Config.in linux-2.4.25-pre8/drivers/usb/gadget/Config.in
--- linux-2.4.25-pre7/drivers/usb/gadget/Config.in	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/Config.in	2004-01-29 10:58:21.000000000 -0800
@@ -5,28 +5,31 @@
 # Long term, this likely doesn't all belong in one directory
 # Plan to split it up eventually.
 #
-# CAREFUL!  Some versions of "xconfig" don't execute this correctly.
-#
 mainmenu_option next_comment
 comment 'Support for USB gadgets'
 
-bool 'Support for USB Gadgets' CONFIG_USB_GADGET
-if [ "$CONFIG_USB_GADGET" = "y" ]; then
+tristate 'Support for USB Gadgets' CONFIG_USB_GADGET
+if [ "$CONFIG_USB_GADGET" = "y" -o "$CONFIG_USB_GADGET" = "m" ]; then
   
   #
   # really want _exactly one_ device controller driver at a time,
   # since they control compile options for gadget drivers.
   #
-  comment 'USB Peripheral Controller Drivers'
-  
-  # assume all the dependencies may be undefined ("== true", yeech)
+  choice 'USB Peripheral Controller Driver' "\
+	NetChip-2280			CONFIG_USB_GADGET_NET2280 \
+	Toshiba-TC86C001(Goku-S)	CONFIG_USB_GADGET_GOKU \
+	" NetChip-2280
+
   define_tristate CONFIG_USB_GADGET_CONTROLLER n
-  if [ "$CONFIG_PCI" = "y" ] ; then
-    tristate '  NetChip 2280 support' CONFIG_USB_NET2280
+
+  if [ "$CONFIG_PCI" = "y" -a "$CONFIG_USB_GADGET_NET2280" = "y" ] ; then
+    define_tristate CONFIG_USB_NET2280 $CONFIG_USB_GADGET
     define_tristate CONFIG_USB_GADGET_CONTROLLER $CONFIG_USB_NET2280
   fi
-
-  # pxa2xx_udc, goku_udc, and others also work on 2.4 ...
+  if [ "$CONFIG_PCI" = "y" -a "$CONFIG_USB_GADGET_GOKU" = "y" ] ; then
+    define_tristate CONFIG_USB_GOKU $CONFIG_USB_GADGET
+    define_tristate CONFIG_USB_GADGET_CONTROLLER $CONFIG_USB_GOKU
+  fi
 
   if [ "$CONFIG_USB_GADGET_CONTROLLER" = "y" -o "$CONFIG_USB_GADGET_CONTROLLER" = "m" ] ; then
 
@@ -46,32 +49,30 @@
   comment 'USB Gadget Drivers'
 
   dep_tristate '  Gadget Zero (DEVELOPMENT)' CONFIG_USB_ZERO $CONFIG_USB_GADGET_CONTROLLER
-  if [ "$CONFIG_USB_ZERO" = "y" -o "$CONFIG_USB_ZERO" = "m" ]; then
-      if [ "$CONFIG_USB_NET2280" = "y" -o "$CONFIG_USB_NET2280" = "m" ]; then
-  	define_bool CONFIG_USB_ZERO_NET2280 y
-      else if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
-  	define_bool CONFIG_USB_ZERO_PXA2XX y
-      else if [ "$CONFIG_USB_GOKU" = "y" -o "$CONFIG_USB_GOKU" = "m" ]; then
-  	define_bool CONFIG_USB_ZERO_GOKU y
-      fi fi fi
-      # ...
-  fi
-  
   dep_tristate '  Ethernet Gadget (EXPERIMENTAL)' CONFIG_USB_ETH $CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
-  if [ "$CONFIG_USB_ETH" = "y" -o "$CONFIG_USB_ETH" = "m" ]; then
-      if [ "$CONFIG_USB_NET2280" = "y" -o "$CONFIG_USB_NET2280" = "m" ]; then
-  	define_bool CONFIG_USB_ETH_NET2280 y
-      else if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
-  	define_bool CONFIG_USB_ETH_PXA2XX y
-      else if [ "$CONFIG_USB_GOKU" = "y" -o "$CONFIG_USB_GOKU" = "m" ]; then
-  	define_bool CONFIG_USB_ETH_GOKU y
-      fi fi fi
-      # ...
-  fi
+  dep_tristate '  File-backed Storage Gadget (DEVELOPMENT)' CONFIG_USB_FILE_STORAGE $CONFIG_USB_GADGET_CONTROLLER
+  dep_mbool '    File-backed Storage Gadget test mode' CONFIG_USB_FILE_STORAGE_TEST $CONFIG_USB_FILE_STORAGE
   
-  
-  # ... or other gadget drivers:  printer class, hid, etc ...
 
+    # enforce the "only one statically linked gadget driver" rule
+
+    if [ "$CONFIG_USB_ZERO" = "y" ]; then
+      # zero = y
+      define_tristate CONFIG_USB_ETH n
+      define_tristate CONFIG_USB_FILE_STORAGE n
+    fi
+
+    if [ "$CONFIG_USB_ETH" = "y" ]; then
+      define_tristate CONFIG_USB_ZERO n
+      # eth = y
+      define_tristate CONFIG_USB_FILE_STORAGE n
+    fi
+
+    if [ "$CONFIG_USB_FILE_STORAGE" = "y" ]; then
+      define_tristate CONFIG_USB_ZERO n
+      define_tristate CONFIG_USB_ETH n
+      # file_storage = y
+    fi
   fi
 fi
 endmenu
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/Makefile linux-2.4.25-pre8/drivers/usb/gadget/Makefile
--- linux-2.4.25-pre7/drivers/usb/gadget/Makefile	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/Makefile	2004-01-29 10:58:21.000000000 -0800
@@ -6,12 +6,14 @@
 # for static linking
 O_TARGET	:= built-in.o
 
-list-multi			:= g_zero.o g_ether.o
+list-multi			:= g_zero.o g_ether.o g_file_storage.o
 
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
+obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 
 # only one of these may be statically linked ...
 controller-$(CONFIG_USB_NET2280)	+= net2280.o
+controller-$(CONFIG_USB_GOKU)		+= goku_udc.o
 
 # ... and only one of these, too; kbuild/kconfig don't help though.
 g_zero-objs			:= zero.o usbstring.o
@@ -20,6 +22,8 @@
 g_ether-objs			:= ether.o usbstring.o
 obj-$(CONFIG_USB_ETH)		+= g_ether.o
 
+g_file_storage-objs		:= file_storage.o usbstring.o
+obj-$(CONFIG_USB_FILE_STORAGE)	+= g_file_storage.o
 
 export-objs :=			$(controller-y) $(controller-m)
 
@@ -29,3 +33,5 @@
 	$(LD) -r -o $@ $(g_zero-objs)
 g_ether.o: $(g_ether-objs)
 	$(LD) -r -o $@ $(g_ether-objs)
+g_file_storage.o: $(g_file_storage-objs)
+	$(LD) -r -o $@ $(g_file_storage-objs)
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/ether.c linux-2.4.25-pre8/drivers/usb/gadget/ether.c
--- linux-2.4.25-pre7/drivers/usb/gadget/ether.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/ether.c	2004-01-29 10:58:21.000000000 -0800
@@ -134,12 +134,9 @@
  *
  * CHIP ... hardware identifier
  * DRIVER_VERSION_NUM ... alerts the host side driver to differences
- * EP0_MAXPACKET ... controls packetization of control requests
  * EP_*_NAME ... which endpoints do we use for which purpose?
  * EP_*_NUM ... numbers for them (often limited by hardware)
  * HIGHSPEED ... define if ep0 and descriptors need high speed support
- * MAX_USB_POWER ... define if we use other than 100 mA bus current
- * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
  * WAKEUP ... if hardware supports remote wakeup AND we will issue the
  * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
  *
@@ -155,6 +152,9 @@
 /* #undef on hardware that can't implement CDC */
 #define	DEV_CONFIG_CDC
 
+/* undef on bus-powered hardware, and #define MAX_USB_POWER */
+#define SELFPOWER
+
 /*
  * NetChip 2280, PCI based.
  *
@@ -164,11 +164,10 @@
  * performance note:  only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f)
  * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help.
  */
-#ifdef	CONFIG_USB_ETH_NET2280
+#ifdef	CONFIG_USB_GADGET_NET2280
 #define CHIP			"net2280"
 #define DEFAULT_QLEN		4		/* has dma chaining */
 #define DRIVER_VERSION_NUM	0x0111
-#define EP0_MAXPACKET		64
 static const char EP_OUT_NAME [] = "ep-a";
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep-b";
@@ -176,8 +175,6 @@
 static const char EP_STATUS_NAME [] = "ep-f";
 #define EP_STATUS_NUM	3
 #define HIGHSPEED
-/* specific hardware configs could be bus-powered */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* supports remote wakeup, but this driver doesn't */
 
 extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
@@ -193,22 +190,19 @@
 
 /*
  * PXA-2xx UDC:  widely used in second gen Linux-capable ARM PDAs
- * and other products.
+ * and other products.  The IXP-42x UDC is register-compatible.
  *
  * multiple interfaces (or altsettings) aren't usable.  so this hardware
  * can't implement CDC, which needs both capabilities.
  */
-#ifdef	CONFIG_USB_ETH_PXA2XX
+#ifdef	CONFIG_USB_GADGET_PXA2XX
 #undef	DEV_CONFIG_CDC
 #define CHIP			"pxa2xx"
 #define DRIVER_VERSION_NUM	0x0113
-#define EP0_MAXPACKET		16
 static const char EP_OUT_NAME [] = "ep2out-bulk";
 #define EP_OUT_NUM	2
 static const char EP_IN_NAME [] = "ep1in-bulk";
 #define EP_IN_NUM	1
-/* doesn't support bus-powered operation */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* supports remote wakeup, but this driver doesn't */
 
 /* no hw optimizations to apply */
@@ -221,17 +215,14 @@
  * can't have a notification endpoint, since there are only the two
  * bulk-capable ones.  the CDC spec allows that.
  */
-#ifdef	CONFIG_USB_ETH_SA1100
+#ifdef	CONFIG_USB_GADGET_SA1100
 #define CHIP			"sa1100"
 #define DRIVER_VERSION_NUM	0x0115
-#define EP0_MAXPACKET		8
 static const char EP_OUT_NAME [] = "ep1out-bulk";
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2in-bulk";
 #define EP_IN_NUM	2
 // EP_STATUS_NUM is undefined
-/* doesn't support bus-powered operation */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* doesn't support remote wakeup? */
 
 /* no hw optimizations to apply */
@@ -243,25 +234,43 @@
  *
  * This has three semi-configurable full speed bulk/interrupt endpoints.
  */
-#ifdef	CONFIG_USB_ETH_GOKU
+#ifdef	CONFIG_USB_GADGET_GOKU
 #define CHIP			"goku"
 #define DRIVER_VERSION_NUM	0x0116
-#define EP0_MAXPACKET		8
 static const char EP_OUT_NAME [] = "ep1-bulk";
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2-bulk";
 #define EP_IN_NUM	2
 static const char EP_STATUS_NAME [] = "ep3-bulk";
 #define EP_STATUS_NUM	3
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* doesn't support remote wakeup */
 
 #define hw_optimize(g) do {} while (0)
 #endif
 
+/*
+ * SuperH UDC:  UDC built-in to some Renesas SH processors.
+ *
+ * This has three semi-configurable full speed bulk/interrupt endpoints.
+ *
+ * Only one configuration and interface is supported.  So this hardware
+ * can't implement CDC.
+ */
+#ifdef	CONFIG_USB_GADGET_SUPERH
+#undef	DEV_CONFIG_CDC
+#define CHIP			"superh"
+#define DRIVER_VERSION_NUM	0x0117
+static const char EP_OUT_NAME[] = "ep1out-bulk";
+#define EP_OUT_NUM		1
+static const char EP_IN_NAME[] = "ep2in-bulk";
+#define EP_IN_NUM		2
+
+#define hw_optimize(g) do {} while (0)
+#endif
+
 /*-------------------------------------------------------------------------*/
 
-#ifndef EP0_MAXPACKET
+#ifndef CHIP
 #	error Configure some USB peripheral controller driver!
 #endif
 
@@ -292,19 +301,15 @@
  * hardware that supports remote wakeup defaults to disabling it.
  */
 
-#ifndef	SELFPOWER
-/* default: say we rely on bus power */
-#define SELFPOWER	0
-/* else:
- * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
- * - MAX_USB_POWER may be nonzero.
- */
-#endif
-
 #ifndef	MAX_USB_POWER
-/* any hub supports this steady state bus power consumption */
-#define MAX_USB_POWER	100	/* mA */
+#ifdef	SELFPOWER
+/* some hosts are confused by 0mA  */
+#define MAX_USB_POWER	2	/* mA */
+#else
+/* bus powered */
+#error	Define your bus power consumption!
 #endif
+#endif	/* MAX_USB_POWER */
 
 #ifndef	WAKEUP
 /* default: this driver won't do remote wakeup */
@@ -388,7 +393,7 @@
 /*
  * This device advertises one configuration.
  */
-static const struct usb_device_descriptor
+static struct usb_device_descriptor
 device_desc = {
 	.bLength =		sizeof device_desc,
 	.bDescriptorType =	USB_DT_DEVICE,
@@ -398,7 +403,6 @@
 	.bDeviceClass =		DEV_CONFIG_CLASS,
 	.bDeviceSubClass =	0,
 	.bDeviceProtocol =	0,
-	.bMaxPacketSize0 =	EP0_MAXPACKET,
 
 	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
 	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
@@ -408,7 +412,7 @@
 	.bNumConfigurations =	1,
 };
 
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
 eth_config = {
 	.bLength =		sizeof eth_config,
 	.bDescriptorType =	USB_DT_CONFIG,
@@ -421,7 +425,7 @@
 #endif
 	.bConfigurationValue =	DEV_CONFIG_VALUE,
 	.iConfiguration =	STRING_PRODUCT,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | WAKEUP,
 	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
 };
 
@@ -657,7 +661,7 @@
 	.bInterval =		1,
 };
 
-static const struct usb_qualifier_descriptor
+static struct usb_qualifier_descriptor
 dev_qualifier = {
 	.bLength =		sizeof dev_qualifier,
 	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
@@ -665,12 +669,10 @@
 	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
 	.bDeviceClass =		DEV_CONFIG_CLASS,
 
-	/* assumes ep0 uses the same value for both speeds ... */
-	.bMaxPacketSize0 =	EP0_MAXPACKET,
-
 	.bNumConfigurations =	1,
 };
 
+
 /* maxpacket and other transfer characteristics vary by speed. */
 #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
 
@@ -971,7 +973,7 @@
 	if (number == dev->config)
 		return 0;
 
-#ifdef CONFIG_USB_ETH_SA1100
+#ifdef CONFIG_USB_GADGET_SA1100
 	if (dev->config && atomic_read (&dev->tx_qlen) != 0) {
 		/* tx fifo is full, but we can't clear it...*/
 		INFO (dev, "can't change configurations\n");
@@ -1018,6 +1020,7 @@
 
 /* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */
 #define CDC_NOTIFY_NETWORK_CONNECTION	0x00	/* required; 6.3.1 */
+#define CDC_NOTIFY_RESPONSE_AVAILABLE	0x01	/* optional; 6.3.2 */
 #define CDC_NOTIFY_SPEED_CHANGE		0x2a	/* required; 6.3.8 */
 
 struct cdc_notification {
@@ -1135,6 +1138,8 @@
 /* see section 3.8.2 table 10 of the CDC spec for more ethernet
  * requests, mostly for filters (multicast, pm) and statistics
  */
+#define CDC_SEND_ENCAPSULATED_REQUEST	0x00	/* optional */
+#define CDC_GET_ENCAPSULATED_RESPONSE	0x01	/* optional */
 #define CDC_SET_ETHERNET_PACKET_FILTER	0x43	/* required */
 
 /*
@@ -1200,7 +1205,7 @@
 		value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
 		break;
-#ifdef	CONFIG_USB_ETH_PXA2XX
+#ifdef	CONFIG_USB_GADGET_PXA2XX
 	/* PXA UDC prevents us from using SET_INTERFACE in normal ways.
 	 * And it hides GET_CONFIGURATION and GET_INTERFACE too.
 	 */
@@ -1650,7 +1655,7 @@
 	req->context = skb;
 	req->complete = tx_complete;
 
-#ifdef	CONFIG_USB_ETH_SA1100
+#ifdef	CONFIG_USB_GADGET_SA1100
 	/* don't demand zlp (req->zero) support from all hardware */
 	if ((length % dev->in_ep->maxpacket) == 0)
 		length++;
@@ -1782,6 +1787,17 @@
 		return -ENODEV;
 #endif
 
+	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+#ifdef	HIGHSPEED
+	/* assumes ep0 uses the same value for both speeds ... */
+	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+#endif
+
+#ifdef	SELFPOWERED
+	eth_config.bmAttributes |= USB_CONFIG_ATT_SELFPOWERED;
+	usb_gadget_set_selfpowered (gadget);
+#endif
+
  	net = alloc_etherdev (sizeof *dev);
  	if (!net)
 		return status;
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/file_storage.c linux-2.4.25-pre8/drivers/usb/gadget/file_storage.c
--- linux-2.4.25-pre7/drivers/usb/gadget/file_storage.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/file_storage.c	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,4047 @@
+/*
+ * file_storage.c -- File-backed USB Storage Gadget, for USB development
+ *
+ * Copyright (C) 2003 Alan Stern
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * The File-backed Storage Gadget acts as a USB Mass Storage device,
+ * appearing to the host as a disk drive.  In addition to providing an
+ * example of a genuinely useful gadget driver for a USB device, it also
+ * illustrates a technique of double-buffering for increased throughput.
+ * Last but not least, it gives an easy way to probe the behavior of the
+ * Mass Storage drivers in a USB host.
+ *
+ * Backing storage is provided by a regular file or a block device, specified
+ * by the "file" module parameter.  Access can be limited to read-only by
+ * setting the optional "ro" module parameter.
+ *
+ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
+ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
+ * by the optional "transport" module parameter.  It also supports the
+ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
+ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
+ * the optional "protocol" module parameter.  For testing purposes the
+ * gadget will indicate that it has removable media if the optional
+ * "removable" module parameter is set.  In addition, the default Vendor ID,
+ * Product ID, and release number can be overridden.
+ *
+ * There is support for multiple logical units (LUNs), each of which has
+ * its own backing file.  The number of LUNs can be set using the optional
+ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
+ * files are specified using comma-separated lists for "file" and "ro".
+ * The default number of LUNs is taken from the number of "file" elements;
+ * it is 1 if "file" is not given.  If "removable" is not set then a backing
+ * file must be specified for each LUN.  If it is set, then an unspecified
+ * or empty backing filename means the LUN's medium is not loaded.
+ *
+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
+ * needed (an interrupt-out endpoint is also needed for CBI).  The memory
+ * requirement amounts to two 16K buffers, size configurable by a parameter.
+ * Support is included for both full-speed and high-speed operation.
+ *
+ * Module options:
+ *
+ *	file=filename[,filename...]
+ *				Required if "removable" is not set, names of
+ *					the files or block devices used for
+ *					backing storage
+ *	ro=b[,b...]		Default false, booleans for read-only access
+ *	luns=N			Default N = number of filenames, number of
+ *					LUNs to support
+ *	transport=XXX		Default BBB, transport name (CB, CBI, or BBB)
+ *	protocol=YYY		Default SCSI, protocol name (RBC, 8020 or
+ *					ATAPI, QIC, UFI, 8070, or SCSI;
+ *					also 1 - 6)
+ *	removable		Default false, boolean for removable media
+ *	vendor=0xVVVV		Default 0x0525 (NetChip), USB Vendor ID
+ *	product=0xPPPP		Default 0xa4a5 (FSG), USB Product ID
+ *	release=0xRRRR		Override the USB release number (bcdDevice)
+ *	buflen=N		Default N=16384, buffer size used (will be
+ *					rounded down to a multiple of
+ *					PAGE_CACHE_SIZE)
+ *	stall			Default determined according to the type of
+ *					USB device controller (usually true),
+ *					boolean to permit the driver to halt
+ *					bulk endpoints
+ *
+ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro"
+ * options are available; default values are used for everything else.
+ *
+ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
+ */
+
+
+/*
+ *				Driver Design
+ *
+ * The FSG driver is fairly straightforward.  There is a main kernel
+ * thread that handles most of the work.  Interrupt routines field
+ * callbacks from the controller driver: bulk- and interrupt-request
+ * completion notifications, endpoint-0 events, and disconnect events.
+ * Completion events are passed to the main thread by wakeup calls.  Many
+ * ep0 requests are handled at interrupt time, but SetInterface,
+ * SetConfiguration, and device reset requests are forwarded to the
+ * thread in the form of "exceptions" using SIGUSR1 signals (since they
+ * should interrupt any ongoing file I/O operations).
+ *
+ * The thread's main routine implements the standard command/data/status
+ * parts of a SCSI interaction.  It and its subroutines are full of tests
+ * for pending signals/exceptions -- all this polling is necessary since
+ * the kernel has no setjmp/longjmp equivalents.  (Maybe this is an
+ * indication that the driver really wants to be running in userspace.)
+ * An important point is that so long as the thread is alive it keeps an
+ * open reference to the backing file.  This will prevent unmounting
+ * the backing file's underlying filesystem and could cause problems
+ * during system shutdown, for example.  To prevent such problems, the
+ * thread catches INT, TERM, and KILL signals and converts them into
+ * an EXIT exception.
+ *
+ * In normal operation the main thread is started during the gadget's
+ * fsg_bind() callback and stopped during fsg_unbind().  But it can also
+ * exit when it receives a signal, and there's no point leaving the
+ * gadget running when the thread is dead.  So just before the thread
+ * exits, it deregisters the gadget driver.  This makes things a little
+ * tricky: The driver is deregistered at two places, and the exiting
+ * thread can indirectly call fsg_unbind() which in turn can tell the
+ * thread to exit.  The first problem is resolved through the use of the
+ * REGISTERED atomic bitflag; the driver will only be deregistered once.
+ * The second problem is resolved by having fsg_unbind() check
+ * fsg->state; it won't try to stop the thread if the state is already
+ * FSG_STATE_TERMINATED.
+ *
+ * To provide maximum throughput, the driver uses a circular pipeline of
+ * buffer heads (struct fsg_buffhd).  In principle the pipeline can be
+ * arbitrarily long; in practice the benefits don't justify having more
+ * than 2 stages (i.e., double buffering).  But it helps to think of the
+ * pipeline as being a long one.  Each buffer head contains a bulk-in and
+ * a bulk-out request pointer (since the buffer can be used for both
+ * output and input -- directions always are given from the host's
+ * point of view) as well as a pointer to the buffer and various state
+ * variables.
+ *
+ * Use of the pipeline follows a simple protocol.  There is a variable
+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
+ * At any time that buffer head may still be in use from an earlier
+ * request, so each buffer head has a state variable indicating whether
+ * it is EMPTY, FULL, or BUSY.  Typical use involves waiting for the
+ * buffer head to be EMPTY, filling the buffer either by file I/O or by
+ * USB I/O (during which the buffer head is BUSY), and marking the buffer
+ * head FULL when the I/O is complete.  Then the buffer will be emptied
+ * (again possibly by USB I/O, during which it is marked BUSY) and
+ * finally marked EMPTY again (possibly by a completion routine).
+ *
+ * A module parameter tells the driver to avoid stalling the bulk
+ * endpoints wherever the transport specification allows.  This is
+ * necessary for some UDCs like the SuperH, which cannot reliably clear a
+ * halt on a bulk endpoint.  However, under certain circumstances the
+ * Bulk-only specification requires a stall.  In such cases the driver
+ * will halt the endpoint and set a flag indicating that it should clear
+ * the halt in software during the next device reset.  Hopefully this
+ * will permit everything to work correctly.
+ *
+ * One subtle point concerns sending status-stage responses for ep0
+ * requests.  Some of these requests, such as device reset, can involve
+ * interrupting an ongoing file I/O operation, which might take an
+ * arbitrarily long time.  During that delay the host might give up on
+ * the original ep0 request and issue a new one.  When that happens the
+ * driver should not notify the host about completion of the original
+ * request, as the host will no longer be waiting for it.  So the driver
+ * assigns to each ep0 request a unique tag, and it keeps track of the
+ * tag value of the request associated with a long-running exception
+ * (device-reset, interface-change, or configuration-change).  When the
+ * exception handler is finished, the status-stage response is submitted
+ * only if the current ep0 request tag is equal to the exception request
+ * tag.  Thus only the most recently received ep0 request will get a
+ * status-stage response.
+ *
+ * Warning: This driver source file is too long.  It ought to be split up
+ * into a header file plus about 3 separate .c files, to handle the details
+ * of the Gadget, USB Mass Storage, and SCSI protocols.
+ */
+
+
+#undef DEBUG
+#undef VERBOSE
+#undef DUMP_MSGS
+
+#include <linux/config.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <linux/compiler.h>
+#include <linux/completion.h>
+#include <linux/dcache.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_DESC		"File-backed Storage Gadget"
+#define DRIVER_NAME		"g_file_storage"
+#define DRIVER_VERSION		"14 January 2004"
+
+static const char longname[] = DRIVER_DESC;
+static const char shortname[] = DRIVER_NAME;
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Alan Stern");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures. */
+#define DRIVER_VENDOR_ID	0x0525	// NetChip
+#define DRIVER_PRODUCT_ID	0xa4a5	// Linux-USB File-backed Storage Gadget
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Hardware-specific configuration, controlled by which device
+ * controller driver was configured.
+ *
+ * CHIP ... hardware identifier
+ * DRIVER_VERSION_NUM ... alerts the host side driver to differences
+ * EP_*_NAME ... which endpoints do we use for which purpose?
+ * EP_*_NUM ... numbers for them (often limited by hardware)
+ * FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep
+ * FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep
+ * HIGHSPEED ... define if ep0 and descriptors need high speed support
+ * MAX_USB_POWER ... define if we use other than 100 mA bus current
+ * SELFPOWER ... if we can run on bus power, zero
+ * NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them
+ */
+
+
+/*
+ * NetChip 2280, PCI based.
+ *
+ * This has half a dozen configurable endpoints, four with dedicated
+ * DMA channels to manage their FIFOs.  It supports high speed.
+ * Those endpoints can be arranged in any desired configuration.
+ */
+#ifdef	CONFIG_USB_GADGET_NET2280
+#define CHIP			"net2280"
+#define DRIVER_VERSION_NUM	0x0211
+static const char EP_BULK_IN_NAME[] = "ep-a";
+#define EP_BULK_IN_NUM		1
+#define FS_BULK_IN_MAXPACKET	64
+static const char EP_BULK_OUT_NAME[] = "ep-b";
+#define EP_BULK_OUT_NUM		2
+#define FS_BULK_OUT_MAXPACKET	64
+static const char EP_INTR_IN_NAME[] = "ep-e";
+#define EP_INTR_IN_NUM		5
+#define HIGHSPEED
+#endif
+
+
+/*
+ * Dummy_hcd, software-based loopback controller.
+ *
+ * This imitates the abilities of the NetChip 2280, so we will use
+ * the same configuration.
+ */
+#ifdef	CONFIG_USB_GADGET_DUMMY
+#define CHIP			"dummy"
+#define DRIVER_VERSION_NUM	0x0212
+static const char EP_BULK_IN_NAME[] = "ep-a";
+#define EP_BULK_IN_NUM		1
+#define FS_BULK_IN_MAXPACKET	64
+static const char EP_BULK_OUT_NAME[] = "ep-b";
+#define EP_BULK_OUT_NUM		2
+#define FS_BULK_OUT_MAXPACKET	64
+static const char EP_INTR_IN_NAME[] = "ep-e";
+#define EP_INTR_IN_NUM		5
+#define HIGHSPEED
+#endif
+
+
+/*
+ * PXA-2xx UDC:  widely used in second gen Linux-capable PDAs.
+ *
+ * This has fifteen fixed-function full speed endpoints, and it
+ * can support all USB transfer types.
+ *
+ * These supports three or four configurations, with fixed numbers.
+ * The hardware interprets SET_INTERFACE, net effect is that you
+ * can't use altsettings or reset the interfaces independently.
+ * So stick to a single interface.
+ */
+#ifdef	CONFIG_USB_GADGET_PXA2XX
+#define CHIP			"pxa2xx"
+#define DRIVER_VERSION_NUM	0x0213
+static const char EP_BULK_IN_NAME[] = "ep1in-bulk";
+#define EP_BULK_IN_NUM		1
+#define FS_BULK_IN_MAXPACKET	64
+static const char EP_BULK_OUT_NAME[] = "ep2out-bulk";
+#define EP_BULK_OUT_NUM		2
+#define FS_BULK_OUT_MAXPACKET	64
+static const char EP_INTR_IN_NAME[] = "ep6in-bulk";
+#define EP_INTR_IN_NUM		6
+#endif
+
+
+/*
+ * SuperH UDC:  UDC built-in to some Renesas SH processors.
+ *
+ * This has three fixed-function full speed bulk/interrupt endpoints.
+ *
+ * Only one configuration and interface is supported (SET_CONFIGURATION
+ * and SET_INTERFACE are handled completely by the hardware).
+ */
+#ifdef	CONFIG_USB_GADGET_SUPERH
+#define CHIP			"superh"
+#define DRIVER_VERSION_NUM	0x0215
+static const char EP_BULK_IN_NAME[] = "ep2in-bulk";
+#define EP_BULK_IN_NUM		2
+#define FS_BULK_IN_MAXPACKET	64
+static const char EP_BULK_OUT_NAME[] = "ep1out-bulk";
+#define EP_BULK_OUT_NUM		1
+#define FS_BULK_OUT_MAXPACKET	64
+static const char EP_INTR_IN_NAME[] = "ep3in-bulk";
+#define EP_INTR_IN_NUM		3
+#define NO_BULK_STALL
+#endif
+
+
+/*
+ * Toshiba TC86C001 ("Goku-S") UDC
+ *
+ * This has three semi-configurable full speed bulk/interrupt endpoints.
+ */
+#ifdef	CONFIG_USB_GADGET_GOKU
+#define CHIP			"goku"
+#define DRIVER_VERSION_NUM	0x0216
+static const char EP_BULK_OUT_NAME [] = "ep1-bulk";
+#define EP_BULK_OUT_NUM		1
+#define FS_BULK_IN_MAXPACKET	64
+static const char EP_BULK_IN_NAME [] = "ep2-bulk";
+#define EP_BULK_IN_NUM		2
+#define FS_BULK_OUT_MAXPACKET	64
+static const char EP_INTR_IN_NAME [] = "ep3-bulk";
+#define EP_INTR_IN_NUM		3
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef CHIP
+#	error Configure some USB peripheral controller driver!
+#endif
+
+/* Power usage is config specific.
+ * Hardware that supports remote wakeup defaults to disabling it.
+ */
+#ifndef	SELFPOWER
+/* default: say we're self-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* else:
+ * - SELFPOWER value must be zero
+ * - MAX_USB_POWER may be nonzero.
+ */
+#endif
+
+#ifndef	MAX_USB_POWER
+/* Any hub supports this steady state bus power consumption */
+#define MAX_USB_POWER	100	/* mA */
+#endif
+
+/* We don't support remote wake-up */
+
+#ifdef NO_BULK_STALL
+#define CAN_STALL	0
+#else
+#define CAN_STALL	1
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+#define fakedev_printk(level, dev, format, args...) \
+	printk(level "%s %s: " format, DRIVER_NAME, (dev)->name, ##args)
+
+#define xprintk(f,level,fmt,args...) \
+	fakedev_printk(level , (f)->gadget , fmt , ## args)
+#define yprintk(l,level,fmt,args...) \
+	fakedev_printk(level , &(l)->dev , fmt , ## args)
+
+#ifdef DEBUG
+#define DBG(fsg,fmt,args...) \
+	xprintk(fsg , KERN_DEBUG , fmt , ## args)
+#define LDBG(lun,fmt,args...) \
+	yprintk(lun , KERN_DEBUG , fmt , ## args)
+#define MDBG(fmt,args...) \
+	printk(KERN_DEBUG DRIVER_NAME ": " fmt, ## args)
+#else
+#define DBG(fsg,fmt,args...) \
+	do { } while (0)
+#define LDBG(lun,fmt,args...) \
+	do { } while (0)
+#define MDBG(fmt,args...) \
+	do { } while (0)
+#undef VERBOSE
+#undef DUMP_MSGS
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG	DBG
+#define VLDBG	LDBG
+#else
+#define VDBG(fsg,fmt,args...) \
+	do { } while (0)
+#define VLDBG(lun,fmt,args...) \
+	do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(fsg,fmt,args...) \
+	xprintk(fsg , KERN_ERR , fmt , ## args)
+#define LERROR(lun,fmt,args...) \
+	yprintk(lun , KERN_ERR , fmt , ## args)
+
+#define WARN(fsg,fmt,args...) \
+	xprintk(fsg , KERN_WARNING , fmt , ## args)
+#define LWARN(lun,fmt,args...) \
+	yprintk(lun , KERN_WARNING , fmt , ## args)
+
+#define INFO(fsg,fmt,args...) \
+	xprintk(fsg , KERN_INFO , fmt , ## args)
+#define LINFO(lun,fmt,args...) \
+	yprintk(lun , KERN_INFO , fmt , ## args)
+
+#define MINFO(fmt,args...) \
+	printk(KERN_INFO DRIVER_NAME ": " fmt, ## args)
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Encapsulate the module parameter settings */
+
+#define MAX_LUNS	8
+
+static char		*file[MAX_LUNS] = {NULL, };
+static int		ro[MAX_LUNS] = {0, };
+static unsigned int	luns = 0;
+static char 		*transport = "BBB";
+static char 		*protocol = "SCSI";
+static int 		removable = 0;
+static unsigned short	vendor = DRIVER_VENDOR_ID;
+static unsigned short	product = DRIVER_PRODUCT_ID;
+static unsigned short	release = DRIVER_VERSION_NUM;
+static unsigned int	buflen = 16384;
+static int		stall = CAN_STALL;
+
+static struct {
+	unsigned int	nluns;
+
+	char		*transport_parm;
+	char		*protocol_parm;
+	int		removable;
+	unsigned short	vendor;
+	unsigned short	product;
+	unsigned short	release;
+	unsigned int	buflen;
+	int		can_stall;
+
+	int		transport_type;
+	char		*transport_name;
+	int		protocol_type;
+	char		*protocol_name;
+
+} mod_data;
+
+
+MODULE_PARM(file, "1-8s");
+MODULE_PARM_DESC(file, "names of backing files or devices");
+
+MODULE_PARM(ro, "1-8b");
+MODULE_PARM_DESC(ro, "true to force read-only");
+
+
+/* In the non-TEST version, only the file and ro module parameters
+ * are available. */
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+
+MODULE_PARM(luns, "i");
+MODULE_PARM_DESC(luns, "number of LUNs");
+
+MODULE_PARM(transport, "s");
+MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
+
+MODULE_PARM(protocol, "s");
+MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
+		"8070, or SCSI)");
+
+MODULE_PARM(removable, "b");
+MODULE_PARM_DESC(removable, "true to simulate removable media");
+
+MODULE_PARM(vendor, "h");
+MODULE_PARM_DESC(vendor, "USB Vendor ID");
+
+MODULE_PARM(product, "h");
+MODULE_PARM_DESC(product, "USB Product ID");
+
+MODULE_PARM(release, "h");
+MODULE_PARM_DESC(release, "USB release number");
+
+MODULE_PARM(buflen, "i");
+MODULE_PARM_DESC(buflen, "I/O buffer size");
+
+MODULE_PARM(stall, "i");
+MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+
+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB protocol value = the transport method */
+#define USB_PR_CBI	0x00		// Control/Bulk/Interrupt
+#define USB_PR_CB	0x01		// Control/Bulk w/o interrupt
+#define USB_PR_BULK	0x50		// Bulk-only
+
+/* USB subclass value = the protocol encapsulation */
+#define USB_SC_RBC	0x01		// Reduced Block Commands (flash)
+#define USB_SC_8020	0x02		// SFF-8020i, MMC-2, ATAPI (CD-ROM)
+#define USB_SC_QIC	0x03		// QIC-157 (tape)
+#define USB_SC_UFI	0x04		// UFI (floppy)
+#define USB_SC_8070	0x05		// SFF-8070i (removable)
+#define USB_SC_SCSI	0x06		// Transparent SCSI
+
+/* Bulk-only data structures */
+
+/* Command Block Wrapper */
+struct bulk_cb_wrap {
+	u32	Signature;		// Contains 'USBC'
+	u32	Tag;			// Unique per command id
+	u32	DataTransferLength;	// Size of the data
+	u8	Flags;			// Direction in bit 7
+	u8	Lun;			// LUN (normally 0)
+	u8	Length;			// Of the CDB, <= MAX_COMMAND_SIZE
+	u8	CDB[16];		// Command Data Block
+};
+
+#define USB_BULK_CB_WRAP_LEN	31
+#define USB_BULK_CB_SIG		0x43425355	// Spells out USBC
+#define USB_BULK_IN_FLAG	0x80
+
+/* Command Status Wrapper */
+struct bulk_cs_wrap {
+	u32	Signature;		// Should = 'USBS'
+	u32	Tag;			// Same as original command
+	u32	Residue;		// Amount not transferred
+	u8	Status;			// See below
+};
+
+#define USB_BULK_CS_WRAP_LEN	13
+#define USB_BULK_CS_SIG		0x53425355	// Spells out 'USBS'
+#define USB_STATUS_PASS		0
+#define USB_STATUS_FAIL		1
+#define USB_STATUS_PHASE_ERROR	2
+
+/* Bulk-only class specific requests */
+#define USB_BULK_RESET_REQUEST		0xff
+#define USB_BULK_GET_MAX_LUN_REQUEST	0xfe
+
+
+/* CBI Interrupt data structure */
+struct interrupt_data {
+	u8	bType;
+	u8	bValue;
+};
+
+#define CBI_INTERRUPT_DATA_LEN		2
+
+/* CBI Accept Device-Specific Command request */
+#define USB_CBI_ADSC_REQUEST		0x00
+
+
+#define MAX_COMMAND_SIZE	16	// Length of a SCSI Command Data Block
+
+/* SCSI commands that we recognize */
+#define SC_FORMAT_UNIT			0x04
+#define SC_INQUIRY			0x12
+#define SC_MODE_SELECT_6		0x15
+#define SC_MODE_SELECT_10		0x55
+#define SC_MODE_SENSE_6			0x1a
+#define SC_MODE_SENSE_10		0x5a
+#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL	0x1e
+#define SC_READ_6			0x08
+#define SC_READ_10			0x28
+#define SC_READ_12			0xa8
+#define SC_READ_CAPACITY		0x25
+#define SC_READ_FORMAT_CAPACITIES	0x23
+#define SC_RELEASE			0x17
+#define SC_REQUEST_SENSE		0x03
+#define SC_RESERVE			0x16
+#define SC_SEND_DIAGNOSTIC		0x1d
+#define SC_START_STOP_UNIT		0x1b
+#define SC_SYNCHRONIZE_CACHE		0x35
+#define SC_TEST_UNIT_READY		0x00
+#define SC_VERIFY			0x2f
+#define SC_WRITE_6			0x0a
+#define SC_WRITE_10			0x2a
+#define SC_WRITE_12			0xaa
+
+/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
+#define SS_NO_SENSE				0
+#define SS_COMMUNICATION_FAILURE		0x040800
+#define SS_INVALID_COMMAND			0x052000
+#define SS_INVALID_FIELD_IN_CDB			0x052400
+#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100
+#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500
+#define SS_MEDIUM_NOT_PRESENT			0x023a00
+#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302
+#define SS_NOT_READY_TO_READY_TRANSITION	0x062800
+#define SS_RESET_OCCURRED			0x062900
+#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900
+#define SS_UNRECOVERED_READ_ERROR		0x031100
+#define SS_WRITE_ERROR				0x030c02
+#define SS_WRITE_PROTECTED			0x072700
+
+#define SK(x)		((u8) ((x) >> 16))	// Sense Key byte, etc.
+#define ASC(x)		((u8) ((x) >> 8))
+#define ASCQ(x)		((u8) (x))
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * These definitions will permit the compiler to avoid generating code for
+ * parts of the driver that aren't used in the non-TEST version.  Even gcc
+ * can recognize when a test of a constant expression yields a dead code
+ * path.
+ *
+ * Also, in the non-TEST version, open_backing_file() is only used during
+ * initialization and the sysfs attribute store_xxx routines aren't used
+ * at all.  We will define NORMALLY_INIT to mark them as __init so they
+ * don't occupy kernel code space unnecessarily.
+ */
+
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+
+#define transport_is_bbb()	(mod_data.transport_type == USB_PR_BULK)
+#define transport_is_cbi()	(mod_data.transport_type == USB_PR_CBI)
+#define protocol_is_scsi()	(mod_data.protocol_type == USB_SC_SCSI)
+#define backing_file_is_open(curlun)	((curlun)->filp != NULL)
+#define NORMALLY_INIT
+
+#else
+
+#define transport_is_bbb()	1
+#define transport_is_cbi()	0
+#define protocol_is_scsi()	1
+#define backing_file_is_open(curlun)	1
+#define NORMALLY_INIT		__init
+
+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
+
+
+struct lun {
+	struct file	*filp;
+	loff_t		file_length;
+	loff_t		num_sectors;
+
+	unsigned int	ro : 1;
+	unsigned int	prevent_medium_removal : 1;
+	unsigned int	registered : 1;
+
+	u32		sense_data;
+	u32		sense_data_info;
+	u32		unit_attention_data;
+
+#define BUS_ID_SIZE	20
+	struct __lun_device {
+		char	name[BUS_ID_SIZE];
+		void	*driver_data;
+	} dev;
+};
+
+
+/* Big enough to hold our biggest descriptor */
+#define EP0_BUFSIZE	256
+#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	// An impossibly large value
+
+/* Number of buffers we will use.  2 is enough for double-buffering */
+#define NUM_BUFFERS	2
+
+enum fsg_buffer_state {
+	BUF_STATE_EMPTY = 0,
+	BUF_STATE_FULL,
+	BUF_STATE_BUSY
+};
+
+struct fsg_buffhd {
+	void				*buf;
+	dma_addr_t			dma;
+	volatile enum fsg_buffer_state	state;
+	struct fsg_buffhd		*next;
+
+	/* The NetChip 2280 is faster, and handles some protocol faults
+	 * better, if we don't submit any short bulk-out read requests.
+	 * So we will record the intended request length here. */
+	unsigned int			bulk_out_intended_length;
+
+	struct usb_request		*inreq;
+	volatile int			inreq_busy;
+	struct usb_request		*outreq;
+	volatile int			outreq_busy;
+};
+
+enum fsg_state {
+	FSG_STATE_COMMAND_PHASE = -10,		// This one isn't used anywhere
+	FSG_STATE_DATA_PHASE,
+	FSG_STATE_STATUS_PHASE,
+
+	FSG_STATE_IDLE = 0,
+	FSG_STATE_ABORT_BULK_OUT,
+	FSG_STATE_RESET,
+	FSG_STATE_INTERFACE_CHANGE,
+	FSG_STATE_CONFIG_CHANGE,
+	FSG_STATE_DISCONNECT,
+	FSG_STATE_EXIT,
+	FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+	DATA_DIR_UNKNOWN = 0,
+	DATA_DIR_FROM_HOST,
+	DATA_DIR_TO_HOST,
+	DATA_DIR_NONE
+};
+
+struct fsg_dev {
+	/* lock protects: state, all the req_busy's, and cbbuf_cmnd */
+	spinlock_t		lock;
+	struct usb_gadget	*gadget;
+
+	/* filesem protects: backing files in use */
+	struct rw_semaphore	filesem;
+
+	struct usb_ep		*ep0;		// Handy copy of gadget->ep0
+	struct usb_request	*ep0req;	// For control responses
+	volatile unsigned int	ep0_req_tag;
+	const char		*ep0req_name;
+
+	struct usb_request	*intreq;	// For interrupt responses
+	volatile int		intreq_busy;
+	struct fsg_buffhd	*intr_buffhd;
+
+ 	unsigned int		bulk_out_maxpacket;
+	enum fsg_state		state;		// For exception handling
+	unsigned int		exception_req_tag;
+
+	u8			config, new_config;
+
+	unsigned int		running : 1;
+	unsigned int		bulk_in_enabled : 1;
+	unsigned int		bulk_out_enabled : 1;
+	unsigned int		intr_in_enabled : 1;
+	unsigned int		phase_error : 1;
+	unsigned int		short_packet_received : 1;
+	unsigned int		bad_lun_okay : 1;
+
+	unsigned long		atomic_bitflags;
+#define REGISTERED		0
+#define CLEAR_BULK_HALTS	1
+
+	struct usb_ep		*bulk_in;
+	struct usb_ep		*bulk_out;
+	struct usb_ep		*intr_in;
+
+	struct fsg_buffhd	*next_buffhd_to_fill;
+	struct fsg_buffhd	*next_buffhd_to_drain;
+	struct fsg_buffhd	buffhds[NUM_BUFFERS];
+
+	wait_queue_head_t	thread_wqh;
+	int			thread_wakeup_needed;
+	struct completion	thread_notifier;
+	int			thread_pid;
+	struct task_struct	*thread_task;
+	sigset_t		thread_signal_mask;
+
+	int			cmnd_size;
+	u8			cmnd[MAX_COMMAND_SIZE];
+	enum data_direction	data_dir;
+	u32			data_size;
+	u32			data_size_from_cmnd;
+	u32			tag;
+	unsigned int		lun;
+	u32			residue;
+	u32			usb_amount_left;
+
+	/* The CB protocol offers no way for a host to know when a command
+	 * has completed.  As a result the next command may arrive early,
+	 * and we will still have to handle it.  For that reason we need
+	 * a buffer to store new commands when using CB (or CBI, which
+	 * does not oblige a host to wait for command completion either). */
+	int			cbbuf_cmnd_size;
+	u8			cbbuf_cmnd[MAX_COMMAND_SIZE];
+
+	unsigned int		nluns;
+	struct lun		*luns;
+	struct lun		*curlun;
+};
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int inline exception_in_progress(struct fsg_dev *fsg)
+{
+	return (fsg->state > FSG_STATE_IDLE);
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+		struct fsg_buffhd *bh, unsigned int length)
+{
+	unsigned int	rem;
+
+	bh->bulk_out_intended_length = length;
+	rem = length % fsg->bulk_out_maxpacket;
+	if (rem > 0)
+		length += fsg->bulk_out_maxpacket - rem;
+	bh->outreq->length = length;
+}
+
+static struct fsg_dev			*the_fsg;
+static struct usb_gadget_driver		fsg_driver;
+
+static void	close_backing_file(struct lun *curlun);
+static void	close_all_backing_files(struct fsg_dev *fsg);
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DUMP_MSGS
+
+static void dump_msg(struct fsg_dev *fsg, const char *label,
+		const u8 *buf, unsigned int length)
+{
+	unsigned int	start, num, i;
+	char		line[52], *p;
+
+	if (length >= 512)
+		return;
+	DBG(fsg, "%s, length %u:\n", label, length);
+
+	start = 0;
+	while (length > 0) {
+		num = min(length, 16u);
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			sprintf(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		printk(KERN_DEBUG "%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+
+static void inline dump_cdb(struct fsg_dev *fsg)
+{}
+
+#else
+
+static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+		const u8 *buf, unsigned int length)
+{}
+
+static void inline dump_cdb(struct fsg_dev *fsg)
+{
+	int	i;
+	char	cmdbuf[3*MAX_COMMAND_SIZE + 1];
+
+	for (i = 0; i < fsg->cmnd_size; ++i)
+		sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
+	VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+}
+
+#endif /* DUMP_MSGS */
+
+
+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
+{
+	const char	*name;
+
+	if (ep == fsg->bulk_in)
+		name = "bulk-in";
+	else if (ep == fsg->bulk_out)
+		name = "bulk-out";
+	else
+		name = ep->name;
+	DBG(fsg, "%s set halt\n", name);
+	return usb_ep_set_halt(ep);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Routines for unaligned data access */
+
+static u16 inline get_be16(u8 *buf)
+{
+	return ((u16) buf[0] << 8) | ((u16) buf[1]);
+}
+
+static u32 inline get_be32(u8 *buf)
+{
+	return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
+			((u32) buf[2] << 8) | ((u32) buf[3]);
+}
+
+static void inline put_be16(u8 *buf, u16 val)
+{
+	buf[0] = val >> 8;
+	buf[1] = val;
+}
+
+static void inline put_be32(u8 *buf, u32 val)
+{
+	buf[0] = val >> 24;
+	buf[1] = val >> 16;
+	buf[2] = val >> 8;
+	buf[3] = val;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.  Also the (static) config and interface
+ * descriptors are adjusted during fsg_bind().
+ */
+#define STRING_MANUFACTURER	1
+#define STRING_PRODUCT		2
+#define STRING_SERIAL		3
+
+/* There is only one configuration. */
+#define	CONFIG_VALUE		1
+
+static struct usb_device_descriptor
+device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
+
+	/* The next three values can be overridden by module parameters */
+	.idVendor =		__constant_cpu_to_le16(DRIVER_VENDOR_ID),
+	.idProduct =		__constant_cpu_to_le16(DRIVER_PRODUCT_ID),
+	.bcdDevice =		__constant_cpu_to_le16(DRIVER_VERSION_NUM),
+
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.iSerialNumber =	STRING_SERIAL,
+	.bNumConfigurations =	1,
+};
+
+static struct usb_config_descriptor
+config_desc = {
+	.bLength =		sizeof config_desc,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* wTotalLength adjusted during bind() */
+	.bNumInterfaces =	1,
+	.bConfigurationValue =	CONFIG_VALUE,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER,
+	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+};
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor
+intf_desc = {
+	.bLength =		sizeof intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,		// Adjusted during bind()
+	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =	USB_SC_SCSI,	// Adjusted during bind()
+	.bInterfaceProtocol =	USB_PR_BULK,	// Adjusted during bind()
+};
+
+/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
+ * and interrupt-in. */
+
+static const struct usb_endpoint_descriptor
+fs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_BULK_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(FS_BULK_IN_MAXPACKET),
+};
+
+static const struct usb_endpoint_descriptor
+fs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_BULK_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(FS_BULK_OUT_MAXPACKET),
+};
+
+static const struct usb_endpoint_descriptor
+fs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_INTR_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(2),
+	.bInterval =		32,	// frames -> 32 ms
+};
+
+#ifdef	HIGHSPEED
+
+/*
+ * USB 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * That means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the config descriptor.
+ */
+static const struct usb_endpoint_descriptor
+hs_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_BULK_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static const struct usb_endpoint_descriptor
+hs_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_BULK_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+	.bInterval =		1,	// NAK every 1 uframe
+};
+
+static const struct usb_endpoint_descriptor
+hs_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_INTR_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16(2),
+	.bInterval =		9,	// 2**(9-1) = 256 uframes -> 32 ms
+};
+
+static struct usb_qualifier_descriptor
+dev_qualifier = {
+	.bLength =		sizeof dev_qualifier,
+	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
+
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
+
+	.bNumConfigurations =	1,
+};
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g,fs,hs)	(((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
+
+#else
+
+/* If there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,fs,hs)	fs
+
+#endif	/* !HIGHSPEED */
+
+
+/* The CBI specification limits the serial string to 12 uppercase hexadecimal
+ * characters. */
+static char				serial[13];
+
+/* Static strings, in ISO 8859/1 */
+static struct usb_string		strings[] = {
+	{ STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, },
+	{ STRING_PRODUCT, longname, },
+	{ STRING_SERIAL, serial, },
+	{ }			// end of list
+};
+
+static struct usb_gadget_strings	stringtab = {
+	.language	= 0x0409,		// en-us
+	.strings	= strings,
+};
+
+
+/*
+ * Config descriptors are handcrafted.  They must agree with the code
+ * that sets configurations and with code managing interfaces and their
+ * altsettings.  They must also handle different speeds and other-speed
+ * requests.
+ */
+static int populate_config_buf(enum usb_device_speed speed,
+		u8 *buf0, u8 type, unsigned index)
+{
+	u8	*buf = buf0;
+#ifdef HIGHSPEED
+	int	hs;
+#endif
+
+	if (index > 0)
+		return -EINVAL;
+	if (config_desc.wTotalLength  > EP0_BUFSIZE)
+		return -EDOM;
+
+	/* Config (or other speed config) */
+	memcpy(buf, &config_desc, USB_DT_CONFIG_SIZE);
+	buf[1] = type;
+	buf += USB_DT_CONFIG_SIZE;
+
+	/* Interface */
+	memcpy(buf, &intf_desc, USB_DT_INTERFACE_SIZE);
+	buf += USB_DT_INTERFACE_SIZE;
+
+	/* The endpoints in the interface (at that speed) */
+#ifdef HIGHSPEED
+	hs = (speed == USB_SPEED_HIGH);
+	if (type == USB_DT_OTHER_SPEED_CONFIG)
+		hs = !hs;
+	if (hs) {
+		memcpy(buf, &hs_bulk_in_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy(buf, &hs_bulk_out_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		if (transport_is_cbi()) {
+			memcpy(buf, &hs_intr_in_desc, USB_DT_ENDPOINT_SIZE);
+			buf += USB_DT_ENDPOINT_SIZE;
+		}
+	} else
+#endif
+	{
+		memcpy(buf, &fs_bulk_in_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy(buf, &fs_bulk_out_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		if (transport_is_cbi()) {
+			memcpy(buf, &fs_intr_in_desc, USB_DT_ENDPOINT_SIZE);
+			buf += USB_DT_ENDPOINT_SIZE;
+		}
+	}
+
+	return buf - buf0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+static void wakeup_thread(struct fsg_dev *fsg)
+{
+	/* Tell the main thread that something has happened */
+	fsg->thread_wakeup_needed = 1;
+	wake_up_all(&fsg->thread_wqh);
+}
+
+
+static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
+{
+	unsigned long		flags;
+	struct task_struct	*thread_task;
+
+	/* Do nothing if a higher-priority exception is already in progress.
+	 * If a lower-or-equal priority exception is in progress, preempt it
+	 * and notify the main thread by sending it a signal. */
+	spin_lock_irqsave(&fsg->lock, flags);
+	if (fsg->state <= new_state) {
+		fsg->exception_req_tag = fsg->ep0_req_tag;
+		fsg->state = new_state;
+		thread_task = fsg->thread_task;
+		if (thread_task)
+			send_sig_info(SIGUSR1, (void *) 1L, thread_task);
+	}
+	spin_unlock_irqrestore(&fsg->lock, flags);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* The disconnect callback and ep0 routines.  These always run in_irq,
+ * except that ep0_queue() is called in the main thread to acknowledge
+ * completion of various requests: set config, set interface, and
+ * Bulk-only device reset. */
+
+static void fsg_disconnect(struct usb_gadget *gadget)
+{
+	struct fsg_dev		*fsg = get_gadget_data(gadget);
+
+	DBG(fsg, "disconnect or port reset\n");
+	raise_exception(fsg, FSG_STATE_DISCONNECT);
+}
+
+
+static int ep0_queue(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
+	if (rc != 0 && rc != -ESHUTDOWN) {
+
+		/* We can't do much more than wait for a reset */
+		WARN(fsg, "error in submission: %s --> %d\n",
+				fsg->ep0->name, rc);
+	}
+	return rc;
+}
+
+static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+
+	if (req->actual > 0)
+		dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
+	if (req->status || req->actual != req->length)
+		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+				req->status, req->actual, req->length);
+	if (req->status == -ECONNRESET)		// Request was cancelled
+		usb_ep_fifo_flush(ep);
+
+	if (req->status == 0 && req->context)
+		((fsg_routine_t) (req->context))(fsg);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Bulk and interrupt endpoint completion handlers.
+ * These always run in_irq. */
+
+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+
+	if (req->status || req->actual != req->length)
+		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+				req->status, req->actual, req->length);
+	if (req->status == -ECONNRESET)		// Request was cancelled
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	spin_lock(&fsg->lock);
+	bh->inreq_busy = 0;
+	bh->state = BUF_STATE_EMPTY;
+	spin_unlock(&fsg->lock);
+	wakeup_thread(fsg);
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+
+	dump_msg(fsg, "bulk-out", req->buf, req->actual);
+	if (req->status || req->actual != bh->bulk_out_intended_length)
+		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+				req->status, req->actual,
+				bh->bulk_out_intended_length);
+	if (req->status == -ECONNRESET)		// Request was cancelled
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	spin_lock(&fsg->lock);
+	bh->outreq_busy = 0;
+	bh->state = BUF_STATE_FULL;
+	spin_unlock(&fsg->lock);
+	wakeup_thread(fsg);
+}
+
+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+
+	if (req->status || req->actual != req->length)
+		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+				req->status, req->actual, req->length);
+	if (req->status == -ECONNRESET)		// Request was cancelled
+		usb_ep_fifo_flush(ep);
+
+	/* Hold the lock while we update the request and buffer states */
+	spin_lock(&fsg->lock);
+	fsg->intreq_busy = 0;
+	bh->state = BUF_STATE_EMPTY;
+	spin_unlock(&fsg->lock);
+	wakeup_thread(fsg);
+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 class-specific handlers.  These always run in_irq. */
+
+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+	struct usb_request	*req = fsg->ep0req;
+	static u8		cbi_reset_cmnd[6] = {
+			SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
+
+	/* Error in command transfer? */
+	if (req->status || req->length != req->actual ||
+			req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
+
+		/* Not all controllers allow a protocol stall after
+		 * receiving control-out data, but we'll try anyway. */
+		fsg_set_halt(fsg, fsg->ep0);
+		return;			// Wait for reset
+	}
+
+	/* Is it the special reset command? */
+	if (req->actual >= sizeof cbi_reset_cmnd &&
+			memcmp(req->buf, cbi_reset_cmnd,
+				sizeof cbi_reset_cmnd) == 0) {
+
+		/* Raise an exception to stop the current operation
+		 * and reinitialize our state. */
+		DBG(fsg, "cbi reset request\n");
+		raise_exception(fsg, FSG_STATE_RESET);
+		return;
+	}
+
+	VDBG(fsg, "CB[I] accept device-specific command\n");
+	spin_lock(&fsg->lock);
+
+	/* Save the command for later */
+	if (fsg->cbbuf_cmnd_size)
+		WARN(fsg, "CB[I] overwriting previous command\n");
+	fsg->cbbuf_cmnd_size = req->actual;
+	memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
+
+	spin_unlock(&fsg->lock);
+	wakeup_thread(fsg);
+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
+}
+
+
+static int class_setup_req(struct fsg_dev *fsg,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_request	*req = fsg->ep0req;
+	int			value = -EOPNOTSUPP;
+
+	if (!fsg->config)
+		return value;
+
+	/* Handle Bulk-only class-specific requests */
+	if (transport_is_bbb()) {
+		switch (ctrl->bRequest) {
+
+		case USB_BULK_RESET_REQUEST:
+			if (ctrl->bRequestType != (USB_DIR_OUT |
+					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+				break;
+			if (ctrl->wIndex != 0) {
+				value = -EDOM;
+				break;
+			}
+
+			/* Raise an exception to stop the current operation
+			 * and reinitialize our state. */
+			DBG(fsg, "bulk reset request\n");
+			raise_exception(fsg, FSG_STATE_RESET);
+			value = DELAYED_STATUS;
+			break;
+
+		case USB_BULK_GET_MAX_LUN_REQUEST:
+			if (ctrl->bRequestType != (USB_DIR_IN |
+					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+				break;
+			if (ctrl->wIndex != 0) {
+				value = -EDOM;
+				break;
+			}
+			VDBG(fsg, "get max LUN\n");
+			*(u8 *) req->buf = fsg->nluns - 1;
+			value = min(ctrl->wLength, (u16) 1);
+			break;
+		}
+	}
+
+	/* Handle CBI class-specific requests */
+	else {
+		switch (ctrl->bRequest) {
+
+		case USB_CBI_ADSC_REQUEST:
+			if (ctrl->bRequestType != (USB_DIR_OUT |
+					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+				break;
+			if (ctrl->wIndex != 0) {
+				value = -EDOM;
+				break;
+			}
+			if (ctrl->wLength > MAX_COMMAND_SIZE) {
+				value = -EOVERFLOW;
+				break;
+			}
+			value = ctrl->wLength;
+			fsg->ep0req->context = received_cbi_adsc;
+			break;
+		}
+	}
+
+	if (value == -EOPNOTSUPP)
+		VDBG(fsg,
+			"unknown class-specific control req "
+			"%02x.%02x v%04x i%04x l%u\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+	return value;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 standard request handlers.  These always run in_irq. */
+
+static int standard_setup_req(struct fsg_dev *fsg,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_request	*req = fsg->ep0req;
+	int			value = -EOPNOTSUPP;
+
+	/* Usually this just stores reply data in the pre-allocated ep0 buffer,
+	 * but config change events will also reconfigure hardware. */
+	switch (ctrl->bRequest) {
+
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+				USB_RECIP_DEVICE))
+			break;
+		switch (ctrl->wValue >> 8) {
+
+		case USB_DT_DEVICE:
+			VDBG(fsg, "get device descriptor\n");
+			value = min(ctrl->wLength, (u16) sizeof device_desc);
+			memcpy(req->buf, &device_desc, value);
+			break;
+#ifdef HIGHSPEED
+		case USB_DT_DEVICE_QUALIFIER:
+			VDBG(fsg, "get device qualifier\n");
+			value = min(ctrl->wLength, (u16) sizeof dev_qualifier);
+			memcpy(req->buf, &dev_qualifier, value);
+			break;
+
+		case USB_DT_OTHER_SPEED_CONFIG:
+			VDBG(fsg, "get other-speed config descriptor\n");
+			goto get_config;
+#endif /* HIGHSPEED */
+		case USB_DT_CONFIG:
+			VDBG(fsg, "get configuration descriptor\n");
+#ifdef HIGHSPEED
+		get_config:
+#endif /* HIGHSPEED */
+			value = populate_config_buf(fsg->gadget->speed,
+					req->buf,
+					ctrl->wValue >> 8,
+					ctrl->wValue & 0xff);
+			if (value >= 0)
+				value = min(ctrl->wLength, (u16) value);
+			break;
+
+		case USB_DT_STRING:
+			VDBG(fsg, "get string descriptor\n");
+
+			/* wIndex == language code */
+			value = usb_gadget_get_string(&stringtab,
+					ctrl->wValue & 0xff, req->buf);
+			if (value >= 0)
+				value = min(ctrl->wLength, (u16) value);
+			break;
+		}
+		break;
+
+	/* One config, two speeds */
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+				USB_RECIP_DEVICE))
+			break;
+		VDBG(fsg, "set configuration\n");
+		if (ctrl->wValue == CONFIG_VALUE || ctrl->wValue == 0) {
+			fsg->new_config = ctrl->wValue;
+
+			/* Raise an exception to wipe out previous transaction
+			 * state (queued bufs, etc) and set the new config. */
+			raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
+			value = DELAYED_STATUS;
+		}
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+				USB_RECIP_DEVICE))
+			break;
+		VDBG(fsg, "get configuration\n");
+		*(u8 *) req->buf = fsg->config;
+		value = min(ctrl->wLength, (u16) 1);
+		break;
+
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
+				USB_RECIP_INTERFACE))
+			break;
+		if (fsg->config && ctrl->wIndex == 0) {
+
+			/* Raise an exception to wipe out previous transaction
+			 * state (queued bufs, etc) and install the new
+			 * interface altsetting. */
+			raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
+			value = DELAYED_STATUS;
+		}
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
+				USB_RECIP_INTERFACE))
+			break;
+		if (!fsg->config)
+			break;
+		if (ctrl->wIndex != 0) {
+			value = -EDOM;
+			break;
+		}
+		VDBG(fsg, "get interface\n");
+		*(u8 *) req->buf = 0;
+		value = min(ctrl->wLength, (u16) 1);
+		break;
+
+	default:
+		VDBG(fsg,
+			"unknown control req %02x.%02x v%04x i%04x l%u\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+	}
+
+	return value;
+}
+
+
+static int fsg_setup(struct usb_gadget *gadget,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	int			rc;
+
+	++fsg->ep0_req_tag;		// Record arrival of a new request
+	fsg->ep0req->context = NULL;
+	fsg->ep0req->length = 0;
+	dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
+		rc = class_setup_req(fsg, ctrl);
+	else
+		rc = standard_setup_req(fsg, ctrl);
+
+	/* Respond with data/status or defer until later? */
+	if (rc >= 0 && rc != DELAYED_STATUS) {
+		fsg->ep0req->length = rc;
+		fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
+				"ep0-in" : "ep0-out");
+		rc = ep0_queue(fsg);
+	}
+
+	/* Device either stalls (rc < 0) or reports success */
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* All the following routines run in process context */
+
+
+/* Use this for bulk or interrupt transfers, not ep0 */
+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
+		struct usb_request *req, volatile int *pbusy,
+		volatile enum fsg_buffer_state *state)
+{
+	int	rc;
+
+	if (ep == fsg->bulk_in)
+		dump_msg(fsg, "bulk-in", req->buf, req->length);
+	else if (ep == fsg->intr_in)
+		dump_msg(fsg, "intr-in", req->buf, req->length);
+	*pbusy = 1;
+	*state = BUF_STATE_BUSY;
+	rc = usb_ep_queue(ep, req, GFP_KERNEL);
+	if (rc != 0) {
+		*pbusy = 0;
+		*state = BUF_STATE_EMPTY;
+
+		/* We can't do much more than wait for a reset */
+
+		/* Note: currently the net2280 driver fails zero-length
+		 * submissions if DMA is enabled. */
+		if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
+						req->length == 0))
+			WARN(fsg, "error in submission: %s --> %d\n",
+					ep->name, rc);
+	}
+}
+
+
+static int sleep_thread(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	/* Wait until a signal arrives or we are woken up */
+	rc = wait_event_interruptible(fsg->thread_wqh,
+			fsg->thread_wakeup_needed);
+	fsg->thread_wakeup_needed = 0;
+	return (rc ? -EINTR : 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_read(struct fsg_dev *fsg)
+{
+	struct lun		*curlun = fsg->curlun;
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			rc;
+	u32			amount_left;
+	loff_t			file_offset, file_offset_tmp;
+	unsigned int		amount;
+	unsigned int		partial_page;
+	ssize_t			nread;
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	if (fsg->cmnd[0] == SC_READ_6)
+		lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
+	else {
+		lba = get_be32(&fsg->cmnd[2]);
+
+		/* We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = don't read from the
+		 * cache), but we don't implement them. */
+		if ((fsg->cmnd[1] & ~0x18) != 0) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+	file_offset = ((loff_t) lba) << 9;
+
+	/* Carry out the file reads */
+	amount_left = fsg->data_size_from_cmnd;
+	if (unlikely(amount_left == 0))
+		return -EIO;		// No default reply
+
+	for (;;) {
+
+		/* Figure out how much we need to read:
+		 * Try to read the remaining amount.
+		 * But don't read more than the buffer size.
+		 * And don't try to read past the end of the file.
+		 * Finally, if we're not at a page boundary, don't read past
+		 *	the next page.
+		 * If this means reading 0 then we were asked to read past
+		 *	the end of file. */
+		amount = min((unsigned int) amount_left, mod_data.buflen);
+		amount = min((loff_t) amount,
+				curlun->file_length - file_offset);
+		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
+		if (partial_page > 0)
+			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
+					partial_page);
+
+		/* Wait for the next buffer to become available */
+		bh = fsg->next_buffhd_to_fill;
+		while (bh->state != BUF_STATE_EMPTY) {
+			if ((rc = sleep_thread(fsg)) != 0)
+				return rc;
+		}
+
+		/* If we were asked to read past the end of file,
+		 * end with an empty buffer. */
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->sense_data_info = file_offset >> 9;
+			bh->inreq->length = 0;
+			bh->state = BUF_STATE_FULL;
+			break;
+		}
+
+		/* Perform the read */
+		file_offset_tmp = file_offset;
+		nread = curlun->filp->f_op->read(curlun->filp,
+				(char *) bh->buf,
+				amount, &file_offset_tmp);
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+				(unsigned long long) file_offset,
+				(int) nread);
+		if (signal_pending(current))
+			return -EINTR;
+
+		if (nread < 0) {
+			LDBG(curlun, "error in file read: %d\n",
+					(int) nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file read: %d/%u\n",
+					(int) nread, amount);
+			nread -= (nread & 511);	// Round down to a block
+		}
+		file_offset  += nread;
+		amount_left  -= nread;
+		fsg->residue -= nread;
+		bh->inreq->length = nread;
+		bh->state = BUF_STATE_FULL;
+
+		/* If an error occurred, report it and its position */
+		if (nread < amount) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->sense_data_info = file_offset >> 9;
+			break;
+		}
+
+		if (amount_left == 0)
+			break;		// No more left to read
+
+		/* Send this buffer and go read some more */
+		bh->inreq->zero = 0;
+		start_transfer(fsg, fsg->bulk_in, bh->inreq,
+				&bh->inreq_busy, &bh->state);
+		fsg->next_buffhd_to_fill = bh->next;
+	}
+
+	return -EIO;		// No default reply
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_write(struct fsg_dev *fsg)
+{
+	struct lun		*curlun = fsg->curlun;
+	u32			lba;
+	struct fsg_buffhd	*bh;
+	int			get_some_more;
+	u32			amount_left_to_req, amount_left_to_write;
+	loff_t			usb_offset, file_offset, file_offset_tmp;
+	unsigned int		amount;
+	unsigned int		partial_page;
+	ssize_t			nwritten;
+	int			rc;
+
+	if (curlun->ro) {
+		curlun->sense_data = SS_WRITE_PROTECTED;
+		return -EINVAL;
+	}
+	curlun->filp->f_flags &= ~O_SYNC;	// Default is not to wait
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	if (fsg->cmnd[0] == SC_WRITE_6)
+		lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
+	else {
+		lba = get_be32(&fsg->cmnd[2]);
+
+		/* We allow DPO (Disable Page Out = don't save data in the
+		 * cache) and FUA (Force Unit Access = write directly to the
+		 * medium).  We don't implement DPO; we implement FUA by
+		 * performing synchronous output. */
+		if ((fsg->cmnd[1] & ~0x18) != 0) {
+			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+		if (fsg->cmnd[1] & 0x08)	// FUA
+			curlun->filp->f_flags |= O_SYNC;
+	}
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/* Carry out the file writes */
+	get_some_more = 1;
+	file_offset = usb_offset = ((loff_t) lba) << 9;
+	amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
+
+	while (amount_left_to_write > 0) {
+
+		/* Queue a request for more data from the host */
+		bh = fsg->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+			/* Figure out how much we want to get:
+			 * Try to get the remaining amount.
+			 * But don't get more than the buffer size.
+			 * And don't try to go past the end of the file.
+			 * If we're not at a page boundary,
+			 *	don't go past the next page.
+			 * If this means getting 0, then we were asked
+			 *	to write past the end of file.
+			 * Finally, round down to a block boundary. */
+			amount = min(amount_left_to_req, mod_data.buflen);
+			amount = min((loff_t) amount, curlun->file_length -
+					usb_offset);
+			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
+			if (partial_page > 0)
+				amount = min(amount,
+	(unsigned int) PAGE_CACHE_SIZE - partial_page);
+
+			if (amount == 0) {
+				get_some_more = 0;
+				curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+				curlun->sense_data_info = usb_offset >> 9;
+				continue;
+			}
+			amount -= (amount & 511);
+			if (amount == 0) {
+
+				/* Why were we were asked to transfer a
+				 * partial block? */
+				get_some_more = 0;
+				continue;
+			}
+
+			/* Get the next buffer */
+			usb_offset += amount;
+			fsg->usb_amount_left -= amount;
+			amount_left_to_req -= amount;
+			if (amount_left_to_req == 0)
+				get_some_more = 0;
+
+			/* amount is always divisible by 512, hence by
+			 * the bulk-out maxpacket size */
+			bh->outreq->length = bh->bulk_out_intended_length =
+					amount;
+			start_transfer(fsg, fsg->bulk_out, bh->outreq,
+					&bh->outreq_busy, &bh->state);
+			fsg->next_buffhd_to_fill = bh->next;
+			continue;
+		}
+
+		/* Write the received data to the backing file */
+		bh = fsg->next_buffhd_to_drain;
+		if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+			break;			// We stopped early
+		if (bh->state == BUF_STATE_FULL) {
+			fsg->next_buffhd_to_drain = bh->next;
+			bh->state = BUF_STATE_EMPTY;
+
+			/* Did something go wrong with the transfer? */
+			if (bh->outreq->status != 0) {
+				curlun->sense_data = SS_COMMUNICATION_FAILURE;
+				curlun->sense_data_info = file_offset >> 9;
+				break;
+			}
+
+			amount = bh->outreq->actual;
+			if (curlun->file_length - file_offset < amount) {
+				LERROR(curlun,
+	"write %u @ %llu beyond end %llu\n",
+	amount, (unsigned long long) file_offset,
+	(unsigned long long) curlun->file_length);
+				amount = curlun->file_length - file_offset;
+			}
+
+			/* Perform the write */
+			file_offset_tmp = file_offset;
+			nwritten = curlun->filp->f_op->write(curlun->filp,
+					(char *) bh->buf,
+					amount, &file_offset_tmp);
+			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
+					(unsigned long long) file_offset,
+					(int) nwritten);
+			if (signal_pending(current))
+				return -EINTR;		// Interrupted!
+
+			if (nwritten < 0) {
+				LDBG(curlun, "error in file write: %d\n",
+						(int) nwritten);
+				nwritten = 0;
+			} else if (nwritten < amount) {
+				LDBG(curlun, "partial file write: %d/%u\n",
+						(int) nwritten, amount);
+				nwritten -= (nwritten & 511);
+						// Round down to a block
+			}
+			file_offset += nwritten;
+			amount_left_to_write -= nwritten;
+			fsg->residue -= nwritten;
+
+			/* If an error occurred, report it and its position */
+			if (nwritten < amount) {
+				curlun->sense_data = SS_WRITE_ERROR;
+				curlun->sense_data_info = file_offset >> 9;
+				break;
+			}
+
+			/* Did the host decide to stop early? */
+			if (bh->outreq->actual != bh->outreq->length) {
+				fsg->short_packet_received = 1;
+				break;
+			}
+			continue;
+		}
+
+		/* Wait for something to happen */
+		if ((rc = sleep_thread(fsg)) != 0)
+			return rc;
+	}
+
+	return -EIO;		// No default reply
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Sync the file data, don't bother with the metadata.
+ * This code was copied from fs/buffer.c:sys_fdatasync(). */
+static int fsync_sub(struct lun *curlun)
+{
+	struct file	*filp = curlun->filp;
+	struct inode	*inode;
+	int		rc, err;
+
+	if (curlun->ro || !filp)
+		return 0;
+	if (!filp->f_op->fsync)
+		return -EINVAL;
+
+	inode = filp->f_dentry->d_inode;
+	down(&inode->i_sem);
+	rc = filemap_fdatasync(inode->i_mapping);
+	err = filp->f_op->fsync(filp, filp->f_dentry, 1);
+	if (!rc)
+		rc = err;
+	err = filemap_fdatawait(inode->i_mapping);
+	if (!rc)
+		rc = err;
+	up(&inode->i_sem);
+	VLDBG(curlun, "fdatasync -> %d\n", rc);
+	return rc;
+}
+
+static void fsync_all(struct fsg_dev *fsg)
+{
+	int	i;
+
+	for (i = 0; i < fsg->nluns; ++i)
+		fsync_sub(&fsg->luns[i]);
+}
+
+static int do_synchronize_cache(struct fsg_dev *fsg)
+{
+	struct lun	*curlun = fsg->curlun;
+	int		rc;
+
+	/* We ignore the requested LBA and write out all file's
+	 * dirty data buffers. */
+	rc = fsync_sub(curlun);
+	if (rc)
+		curlun->sense_data = SS_WRITE_ERROR;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void invalidate_sub(struct lun *curlun)
+{
+	struct file	*filp = curlun->filp;
+	struct inode	*inode = filp->f_dentry->d_inode;
+
+	invalidate_inode_pages(inode);
+}
+
+static int do_verify(struct fsg_dev *fsg)
+{
+	struct lun		*curlun = fsg->curlun;
+	u32			lba;
+	u32			verification_length;
+	struct fsg_buffhd	*bh = fsg->next_buffhd_to_fill;
+	loff_t			file_offset, file_offset_tmp;
+	u32			amount_left;
+	unsigned int		amount;
+	ssize_t			nread;
+
+	/* Get the starting Logical Block Address and check that it's
+	 * not too big */
+	lba = get_be32(&fsg->cmnd[2]);
+	if (lba >= curlun->num_sectors) {
+		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/* We allow DPO (Disable Page Out = don't save data in the
+	 * cache) but we don't implement it. */
+	if ((fsg->cmnd[1] & ~0x10) != 0) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	verification_length = get_be16(&fsg->cmnd[7]);
+	if (unlikely(verification_length == 0))
+		return -EIO;		// No default reply
+
+	/* Prepare to carry out the file verify */
+	amount_left = verification_length << 9;
+	file_offset = ((loff_t) lba) << 9;
+
+	/* Write out all the dirty buffers before invalidating them */
+	fsync_sub(curlun);
+	if (signal_pending(current))
+		return -EINTR;
+
+	invalidate_sub(curlun);
+	if (signal_pending(current))
+		return -EINTR;
+
+	/* Just try to read the requested blocks */
+	while (amount_left > 0) {
+
+		/* Figure out how much we need to read:
+		 * Try to read the remaining amount, but not more than
+		 * the buffer size.
+		 * And don't try to read past the end of the file.
+		 * If this means reading 0 then we were asked to read
+		 * past the end of file. */
+		amount = min((unsigned int) amount_left, mod_data.buflen);
+		amount = min((loff_t) amount,
+				curlun->file_length - file_offset);
+		if (amount == 0) {
+			curlun->sense_data =
+					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+			curlun->sense_data_info = file_offset >> 9;
+			break;
+		}
+
+		/* Perform the read */
+		file_offset_tmp = file_offset;
+		nread = curlun->filp->f_op->read(curlun->filp,
+				(char *) bh->buf,
+				amount, &file_offset_tmp);
+		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+				(unsigned long long) file_offset,
+				(int) nread);
+		if (signal_pending(current))
+			return -EINTR;
+
+		if (nread < 0) {
+			LDBG(curlun, "error in file verify: %d\n",
+					(int) nread);
+			nread = 0;
+		} else if (nread < amount) {
+			LDBG(curlun, "partial file verify: %d/%u\n",
+					(int) nread, amount);
+			nread -= (nread & 511);	// Round down to a sector
+		}
+		if (nread == 0) {
+			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
+			curlun->sense_data_info = file_offset >> 9;
+			break;
+		}
+		file_offset += nread;
+		amount_left -= nread;
+	}
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	u8	*buf = (u8 *) bh->buf;
+
+	static char vendor_id[] = "Linux   ";
+	static char product_id[] = "File-Stor Gadget";
+
+	if (!fsg->curlun) {		// Unsupported LUNs are okay
+		fsg->bad_lun_okay = 1;
+		memset(buf, 0, 36);
+		buf[0] = 0x7f;		// Unsupported, no device-type
+		return 36;
+	}
+
+	memset(buf, 0, 8);	// Non-removable, direct-access device
+	if (mod_data.removable)
+		buf[1] = 0x80;
+	buf[2] = 2;		// ANSI SCSI level 2
+	buf[3] = 2;		// SCSI-2 INQUIRY data format
+	buf[4] = 31;		// Additional length
+				// No special options
+	sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,
+			DRIVER_VERSION_NUM);
+	return 36;
+}
+
+
+static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct lun	*curlun = fsg->curlun;
+	u8		*buf = (u8 *) bh->buf;
+	u32		sd, sdinfo;
+
+	/*
+	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):
+	 *
+	 * If a REQUEST SENSE command is received from an initiator
+	 * with a pending unit attention condition (before the target
+	 * generates the contingent allegiance condition), then the
+	 * target shall either:
+	 *   a) report any pending sense data and preserve the unit
+	 *	attention condition on the logical unit, or,
+	 *   b) report the unit attention condition, may discard any
+	 *	pending sense data, and clear the unit attention
+	 *	condition on the logical unit for that initiator.
+	 *
+	 * FSG normally uses option a); enable this code to use option b).
+	 */
+#if 0
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+	}
+#endif
+
+	if (!curlun) {		// Unsupported LUNs are okay
+		fsg->bad_lun_okay = 1;
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+		sdinfo = 0;
+	} else {
+		sd = curlun->sense_data;
+		sdinfo = curlun->sense_data_info;
+		curlun->sense_data = SS_NO_SENSE;
+		curlun->sense_data_info = 0;
+	}
+
+	memset(buf, 0, 18);
+	buf[0] = 0x80 | 0x70;			// Valid, current error
+	buf[2] = SK(sd);
+	put_be32(&buf[3], sdinfo);		// Sense information
+	buf[7] = 18 - 7;			// Additional sense length
+	buf[12] = ASC(sd);
+	buf[13] = ASCQ(sd);
+	return 18;
+}
+
+
+static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct lun	*curlun = fsg->curlun;
+	u32		lba = get_be32(&fsg->cmnd[2]);
+	int		pmi = fsg->cmnd[8];
+	u8		*buf = (u8 *) bh->buf;
+
+	/* Check the PMI and LBA fields */
+	if (pmi > 1 || (pmi == 0 && lba != 0)) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	put_be32(&buf[0], curlun->num_sectors - 1);	// Max logical block
+	put_be32(&buf[4], 512);				// Block length
+	return 8;
+}
+
+
+static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct lun	*curlun = fsg->curlun;
+	int		mscmnd = fsg->cmnd[0];
+	u8		*buf = (u8 *) bh->buf;
+	u8		*buf0 = buf;
+	int		pc, page_code;
+	int		changeable_values, all_pages;
+	int		valid_page = 0;
+	int		len, limit;
+
+	if ((fsg->cmnd[1] & ~0x08) != 0) {		// Mask away DBD
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+	pc = fsg->cmnd[2] >> 6;
+	page_code = fsg->cmnd[2] & 0x3f;
+	if (pc == 3) {
+		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
+		return -EINVAL;
+	}
+	changeable_values = (pc == 1);
+	all_pages = (page_code == 0x3f);
+
+	/* Write the mode parameter header.  Fixed values are: default
+	 * medium type, no cache control (DPOFUA), and no block descriptors.
+	 * The only variable value is the WriteProtect bit.  We will fill in
+	 * the mode data length later. */
+	memset(buf, 0, 8);
+	if (mscmnd == SC_MODE_SENSE_6) {
+		buf[2] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA
+		buf += 4;
+		limit = 255;
+	} else {			// SC_MODE_SENSE_10
+		buf[3] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA
+		buf += 8;
+		limit = 65535;		// Should really be mod_data.buflen
+	}
+
+	/* No block descriptors */
+
+	/* The mode pages, in numerical order.  The only page we support
+	 * is the Caching page. */
+	if (page_code == 0x08 || all_pages) {
+		valid_page = 1;
+		buf[0] = 0x08;		// Page code
+		buf[1] = 10;		// Page length
+		memset(buf+2, 0, 10);	// None of the fields are changeable
+
+		if (!changeable_values) {
+			buf[2] = 0x04;	// Write cache enable,
+					// Read cache not disabled
+					// No cache retention priorities
+			put_be16(&buf[4], 0xffff);  // Don't disable prefetch
+					// Minimum prefetch = 0
+			put_be16(&buf[8], 0xffff);  // Maximum prefetch
+			put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling
+		}
+		buf += 12;
+	}
+
+	/* Check that a valid page was requested and the mode data length
+	 * isn't too long. */
+	len = buf - buf0;
+	if (!valid_page || len > limit) {
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	/*  Store the mode data length */
+	if (mscmnd == SC_MODE_SENSE_6)
+		buf0[0] = len - 1;
+	else
+		put_be16(buf0, len - 2);
+	return len;
+}
+
+
+static int do_start_stop(struct fsg_dev *fsg)
+{
+	struct lun	*curlun = fsg->curlun;
+	int		loej, start;
+
+	if (!mod_data.removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	}
+
+	// int immed = fsg->cmnd[1] & 0x01;
+	loej = fsg->cmnd[4] & 0x02;
+	start = fsg->cmnd[4] & 0x01;
+
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+	if ((fsg->cmnd[1] & ~0x01) != 0 ||		// Mask away Immed
+			(fsg->cmnd[4] & ~0x03) != 0) {	// Mask LoEj, Start
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	if (!start) {
+
+		/* Are we allowed to unload the media? */
+		if (curlun->prevent_medium_removal) {
+			LDBG(curlun, "unload attempt prevented\n");
+			curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
+			return -EINVAL;
+		}
+		if (loej) {		// Simulate an unload/eject
+			up_read(&fsg->filesem);
+			down_write(&fsg->filesem);
+			close_backing_file(curlun);
+			up_write(&fsg->filesem);
+			down_read(&fsg->filesem);
+		}
+	} else {
+
+		/* Our emulation doesn't support mounting; the medium is
+		 * available for use as soon as it is loaded. */
+		if (!backing_file_is_open(curlun)) {
+			curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+			return -EINVAL;
+		}
+	}
+#endif
+	return 0;
+}
+
+
+static int do_prevent_allow(struct fsg_dev *fsg)
+{
+	struct lun	*curlun = fsg->curlun;
+	int		prevent;
+
+	if (!mod_data.removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
+		return -EINVAL;
+	}
+
+	prevent = fsg->cmnd[4] & 0x01;
+	if ((fsg->cmnd[4] & ~0x01) != 0) {		// Mask away Prevent
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	if (curlun->prevent_medium_removal && !prevent)
+		fsync_sub(curlun);
+	curlun->prevent_medium_removal = prevent;
+	return 0;
+}
+
+
+static int do_read_format_capacities(struct fsg_dev *fsg,
+			struct fsg_buffhd *bh)
+{
+	struct lun	*curlun = fsg->curlun;
+	u8		*buf = (u8 *) bh->buf;
+
+	buf[0] = buf[1] = buf[2] = 0;
+	buf[3] = 8;		// Only the Current/Maximum Capacity Descriptor
+	buf += 4;
+
+	put_be32(&buf[0], curlun->num_sectors);		// Number of blocks
+	put_be32(&buf[4], 512);				// Block length
+	buf[4] = 0x02;					// Current capacity
+	return 12;
+}
+
+
+static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct lun	*curlun = fsg->curlun;
+
+	/* We don't support MODE SELECT */
+	curlun->sense_data = SS_INVALID_COMMAND;
+	return -EINVAL;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+	int	rc;
+
+	rc = fsg_set_halt(fsg, fsg->bulk_in);
+	if (rc == -EAGAIN)
+		VDBG(fsg, "delayed bulk-in endpoint halt\n");
+	while (rc != 0) {
+		if (rc != -EAGAIN) {
+			WARN(fsg, "usb_ep_set_halt -> %d\n", rc);
+			rc = 0;
+			break;
+		}
+
+		/* Wait for a short time and then try again */
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout(HZ / 10) != 0)
+			return -EINTR;
+		rc = usb_ep_set_halt(fsg->bulk_in);
+	}
+	return rc;
+}
+
+static int pad_with_zeros(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh = fsg->next_buffhd_to_fill;
+	u32			nkeep = bh->inreq->length;
+	u32			nsend;
+	int			rc;
+
+	bh->state = BUF_STATE_EMPTY;		// For the first iteration
+	fsg->usb_amount_left = nkeep + fsg->residue;
+	while (fsg->usb_amount_left > 0) {
+
+		/* Wait for the next buffer to be free */
+		while (bh->state != BUF_STATE_EMPTY) {
+			if ((rc = sleep_thread(fsg)) != 0)
+				return rc;
+		}
+
+		nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen);
+		memset(bh->buf + nkeep, 0, nsend - nkeep);
+		bh->inreq->length = nsend;
+		bh->inreq->zero = 0;
+		start_transfer(fsg, fsg->bulk_in, bh->inreq,
+				&bh->inreq_busy, &bh->state);
+		bh = fsg->next_buffhd_to_fill = bh->next;
+		fsg->usb_amount_left -= nsend;
+		nkeep = 0;
+	}
+	return 0;
+}
+
+static int throw_away_data(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh;
+	u32			amount;
+	int			rc;
+
+	while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
+			fsg->usb_amount_left > 0) {
+
+		/* Throw away the data in a filled buffer */
+		if (bh->state == BUF_STATE_FULL) {
+			bh->state = BUF_STATE_EMPTY;
+			fsg->next_buffhd_to_drain = bh->next;
+
+			/* A short packet or an error ends everything */
+			if (bh->outreq->actual != bh->outreq->length ||
+					bh->outreq->status != 0) {
+				raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+				return -EINTR;
+			}
+			continue;
+		}
+
+		/* Try to submit another request if we need one */
+		bh = fsg->next_buffhd_to_fill;
+		if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
+			amount = min(fsg->usb_amount_left,
+					(u32) mod_data.buflen);
+
+			/* amount is always divisible by 512, hence by
+			 * the bulk-out maxpacket size */
+			bh->outreq->length = bh->bulk_out_intended_length =
+					amount;
+			start_transfer(fsg, fsg->bulk_out, bh->outreq,
+					&bh->outreq_busy, &bh->state);
+			fsg->next_buffhd_to_fill = bh->next;
+			fsg->usb_amount_left -= amount;
+			continue;
+		}
+
+		/* Otherwise wait for something to happen */
+		if ((rc = sleep_thread(fsg)) != 0)
+			return rc;
+	}
+	return 0;
+}
+
+
+static int finish_reply(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh = fsg->next_buffhd_to_fill;
+	int			rc = 0;
+
+	switch (fsg->data_dir) {
+	case DATA_DIR_NONE:
+		break;			// Nothing to send
+
+	/* If we don't know whether the host wants to read or write,
+	 * this must be CB or CBI with an unknown command.  We mustn't
+	 * try to send or receive any data.  So stall both bulk pipes
+	 * if we can and wait for a reset. */
+	case DATA_DIR_UNKNOWN:
+		if (mod_data.can_stall) {
+			fsg_set_halt(fsg, fsg->bulk_out);
+			rc = halt_bulk_in_endpoint(fsg);
+		}
+		break;
+
+	/* All but the last buffer of data must have already been sent */
+	case DATA_DIR_TO_HOST:
+		if (fsg->data_size == 0)
+			;		// Nothing to send
+
+		/* If there's no residue, simply send the last buffer */
+		else if (fsg->residue == 0) {
+			bh->inreq->zero = 0;
+			start_transfer(fsg, fsg->bulk_in, bh->inreq,
+					&bh->inreq_busy, &bh->state);
+			fsg->next_buffhd_to_fill = bh->next;
+		}
+
+		/* There is a residue.  For CB and CBI, simply mark the end
+		 * of the data with a short packet.  However, if we are
+		 * allowed to stall, there was no data at all (residue ==
+		 * data_size), and the command failed (invalid LUN or
+		 * sense data is set), then halt the bulk-in endpoint
+		 * instead. */
+		else if (!transport_is_bbb()) {
+			if (mod_data.can_stall &&
+					fsg->residue == fsg->data_size &&
+	(!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
+				bh->state = BUF_STATE_EMPTY;
+				rc = halt_bulk_in_endpoint(fsg);
+			} else {
+				bh->inreq->zero = 1;
+				start_transfer(fsg, fsg->bulk_in, bh->inreq,
+						&bh->inreq_busy, &bh->state);
+				fsg->next_buffhd_to_fill = bh->next;
+			}
+		}
+
+		/* For Bulk-only, if we're allowed to stall then send the
+		 * short packet and halt the bulk-in endpoint.  If we can't
+		 * stall, pad out the remaining data with 0's. */
+		else {
+			if (mod_data.can_stall) {
+				bh->inreq->zero = 1;
+				start_transfer(fsg, fsg->bulk_in, bh->inreq,
+						&bh->inreq_busy, &bh->state);
+				fsg->next_buffhd_to_fill = bh->next;
+				rc = halt_bulk_in_endpoint(fsg);
+			} else
+				rc = pad_with_zeros(fsg);
+		}
+		break;
+
+	/* We have processed all we want from the data the host has sent.
+	 * There may still be outstanding bulk-out requests. */
+	case DATA_DIR_FROM_HOST:
+		if (fsg->residue == 0)
+			;		// Nothing to receive
+
+		/* Did the host stop sending unexpectedly early? */
+		else if (fsg->short_packet_received) {
+			raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+		}
+
+		/* We haven't processed all the incoming data.  If we are
+		 * allowed to stall, halt the bulk-out endpoint and cancel
+		 * any outstanding requests. */
+		else if (mod_data.can_stall) {
+			fsg_set_halt(fsg, fsg->bulk_out);
+			raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
+			rc = -EINTR;
+		}
+
+		/* We can't stall.  Read in the excess data and throw it
+		 * all away. */
+		else
+			rc = throw_away_data(fsg);
+		break;
+	}
+	return rc;
+}
+
+
+static int send_status(struct fsg_dev *fsg)
+{
+	struct lun		*curlun = fsg->curlun;
+	struct fsg_buffhd	*bh;
+	int			rc;
+	u8			status = USB_STATUS_PASS;
+	u32			sd, sdinfo = 0;
+
+	/* Wait for the next buffer to become available */
+	bh = fsg->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		if ((rc = sleep_thread(fsg)) != 0)
+			return rc;
+	}
+
+	if (curlun) {
+		sd = curlun->sense_data;
+		sdinfo = curlun->sense_data_info;
+	} else if (fsg->bad_lun_okay)
+		sd = SS_NO_SENSE;
+	else
+		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+	if (fsg->phase_error) {
+		DBG(fsg, "sending phase-error status\n");
+		status = USB_STATUS_PHASE_ERROR;
+		sd = SS_INVALID_COMMAND;
+	} else if (sd != SS_NO_SENSE) {
+		DBG(fsg, "sending command-failure status\n");
+		status = USB_STATUS_FAIL;
+		VDBG(fsg, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+				"  info x%x\n",
+				SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+	}
+
+	if (transport_is_bbb()) {
+		struct bulk_cs_wrap	*csw = (struct bulk_cs_wrap *) bh->buf;
+
+		/* Store and send the Bulk-only CSW */
+		csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
+		csw->Tag = fsg->tag;
+		csw->Residue = fsg->residue;
+		csw->Status = status;
+
+		bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+		bh->inreq->zero = 0;
+		start_transfer(fsg, fsg->bulk_in, bh->inreq,
+				&bh->inreq_busy, &bh->state);
+
+	} else if (mod_data.transport_type == USB_PR_CB) {
+
+		/* Control-Bulk transport has no status stage! */
+		return 0;
+
+	} else {			// USB_PR_CBI
+		struct interrupt_data	*buf = (struct interrupt_data *)
+						bh->buf;
+
+		/* Store and send the Interrupt data.  UFI sends the ASC
+		 * and ASCQ bytes.  Everything else sends a Type (which
+		 * is always 0) and the status Value. */
+		if (mod_data.protocol_type == USB_SC_UFI) {
+			buf->bType = ASC(sd);
+			buf->bValue = ASCQ(sd);
+		} else {
+			buf->bType = 0;
+			buf->bValue = status;
+		}
+		fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
+
+		fsg->intr_buffhd = bh;		// Point to the right buffhd
+		fsg->intreq->buf = bh->inreq->buf;
+		fsg->intreq->dma = bh->inreq->dma;
+		fsg->intreq->context = bh;
+		start_transfer(fsg, fsg->intr_in, fsg->intreq,
+				&fsg->intreq_busy, &bh->state);
+	}
+
+	fsg->next_buffhd_to_fill = bh->next;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Check whether the command is properly formed and whether its data size
+ * and direction agree with the values we already have. */
+static int check_command(struct fsg_dev *fsg, int cmnd_size,
+		enum data_direction data_dir, unsigned int mask,
+		int needs_medium, const char *name)
+{
+	int			i;
+	int			lun = fsg->cmnd[1] >> 5;
+	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
+	char			hdlen[20];
+	struct lun		*curlun;
+
+	/* Adjust the expected cmnd_size for protocol encapsulation padding.
+	 * Transparent SCSI doesn't pad. */
+	if (protocol_is_scsi())
+		;
+
+	/* There's some disagreement as to whether RBC pads commands or not.
+	 * We'll play it safe and accept either form. */
+	else if (mod_data.protocol_type == USB_SC_RBC) {
+		if (fsg->cmnd_size == 12)
+			cmnd_size = 12;
+
+	/* All the other protocols pad to 12 bytes */
+	} else
+		cmnd_size = 12;
+
+	hdlen[0] = 0;
+	if (fsg->data_dir != DATA_DIR_UNKNOWN)
+		sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
+				fsg->data_size);
+	VDBG(fsg, "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
+			name, cmnd_size, dirletter[(int) data_dir],
+			fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
+
+	/* We can't reply at all until we know the correct data direction
+	 * and size. */
+	if (fsg->data_size_from_cmnd == 0)
+		data_dir = DATA_DIR_NONE;
+	if (fsg->data_dir == DATA_DIR_UNKNOWN) {	// CB or CBI
+		fsg->data_dir = data_dir;
+		fsg->data_size = fsg->data_size_from_cmnd;
+
+	} else {					// Bulk-only
+		if (fsg->data_size < fsg->data_size_from_cmnd) {
+
+			/* Host data size < Device data size is a phase error.
+			 * Carry out the command, but only transfer as much
+			 * as we are allowed. */
+			fsg->data_size_from_cmnd = fsg->data_size;
+			fsg->phase_error = 1;
+		}
+	}
+	fsg->residue = fsg->usb_amount_left = fsg->data_size;
+
+	/* Conflicting data directions is a phase error */
+	if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0)
+		goto phase_error;
+
+	/* Verify the length of the command itself */
+	if (cmnd_size != fsg->cmnd_size) {
+
+		/* Special case workaround: MS-Windows issues REQUEST SENSE
+		 * with cbw->Length == 12 (it should be 6). */
+		if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12)
+			cmnd_size = fsg->cmnd_size;
+		else
+			goto phase_error;
+	}
+
+	/* Check that the LUN values are oonsistent */
+	if (transport_is_bbb()) {
+		if (fsg->lun != lun)
+			DBG(fsg, "using LUN %d from CBW, "
+					"not LUN %d from CDB\n",
+					fsg->lun, lun);
+	} else
+		fsg->lun = lun;		// Use LUN from the command
+
+	/* Check the LUN */
+	if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
+		fsg->curlun = curlun = &fsg->luns[fsg->lun];
+		if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
+			curlun->sense_data = SS_NO_SENSE;
+			curlun->sense_data_info = 0;
+		}
+	} else {
+		fsg->curlun = curlun = NULL;
+		fsg->bad_lun_okay = 0;
+
+		/* INQUIRY and REQUEST SENSE commands are explicitly allowed
+		 * to use unsupported LUNs; all others may not. */
+		if (fsg->cmnd[0] != SC_INQUIRY &&
+				fsg->cmnd[0] != SC_REQUEST_SENSE) {
+			DBG(fsg, "unsupported LUN %d\n", fsg->lun);
+			return -EINVAL;
+		}
+	}
+
+	/* If a unit attention condition exists, only INQUIRY and
+	 * REQUEST SENSE commands are allowed; anything else must fail. */
+	if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+			fsg->cmnd[0] != SC_INQUIRY &&
+			fsg->cmnd[0] != SC_REQUEST_SENSE) {
+		curlun->sense_data = curlun->unit_attention_data;
+		curlun->unit_attention_data = SS_NO_SENSE;
+		return -EINVAL;
+	}
+
+	/* Check that only command bytes listed in the mask are non-zero */
+	fsg->cmnd[1] &= 0x1f;			// Mask away the LUN
+	for (i = 1; i < cmnd_size; ++i) {
+		if (fsg->cmnd[i] && !(mask & (1 << i))) {
+			if (curlun)
+				curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			return -EINVAL;
+		}
+	}
+
+	/* If the medium isn't mounted and the command needs to access
+	 * it, return an error. */
+	if (curlun && !backing_file_is_open(curlun) && needs_medium) {
+		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+		return -EINVAL;
+	}
+
+	return 0;
+
+phase_error:
+	fsg->phase_error = 1;
+	return -EINVAL;
+}
+
+
+static int do_scsi_command(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh;
+	int			rc;
+	int			reply = -EINVAL;
+	int			i;
+	static char		unknown[16];
+
+	dump_cdb(fsg);
+
+	/* Wait for the next buffer to become available for data or status */
+	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
+	while (bh->state != BUF_STATE_EMPTY) {
+		if ((rc = sleep_thread(fsg)) != 0)
+			return rc;
+		}
+	fsg->phase_error = 0;
+	fsg->short_packet_received = 0;
+
+	down_read(&fsg->filesem);	// We're using the backing file
+	switch (fsg->cmnd[0]) {
+
+	case SC_INQUIRY:
+		fsg->data_size_from_cmnd = fsg->cmnd[4];
+		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+				(1<<4), 0,
+				"INQUIRY")) == 0)
+			reply = do_inquiry(fsg, bh);
+		break;
+
+	case SC_MODE_SELECT_6:
+		fsg->data_size_from_cmnd = fsg->cmnd[4];
+		if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+				(1<<1) | (1<<4), 0,
+				"MODE SELECT(6)")) == 0)
+			reply = do_mode_select(fsg, bh);
+		break;
+
+	case SC_MODE_SELECT_10:
+		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+		if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+				(1<<1) | (3<<7), 0,
+				"MODE SELECT(10)")) == 0)
+			reply = do_mode_select(fsg, bh);
+		break;
+
+	case SC_MODE_SENSE_6:
+		fsg->data_size_from_cmnd = fsg->cmnd[4];
+		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+				(1<<1) | (1<<2) | (1<<4), 0,
+				"MODE SENSE(6)")) == 0)
+			reply = do_mode_sense(fsg, bh);
+		break;
+
+	case SC_MODE_SENSE_10:
+		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+				(1<<1) | (1<<2) | (3<<7), 0,
+				"MODE SENSE(10)")) == 0)
+			reply = do_mode_sense(fsg, bh);
+		break;
+
+	case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+		fsg->data_size_from_cmnd = 0;
+		if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
+				(1<<4), 0,
+				"PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
+			reply = do_prevent_allow(fsg);
+		break;
+
+	case SC_READ_6:
+		i = fsg->cmnd[4];
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+				(7<<1) | (1<<4), 1,
+				"READ(6)")) == 0)
+			reply = do_read(fsg);
+		break;
+
+	case SC_READ_10:
+		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
+		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+				(1<<1) | (0xf<<2) | (3<<7), 1,
+				"READ(10)")) == 0)
+			reply = do_read(fsg);
+		break;
+
+	case SC_READ_12:
+		fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
+		if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
+				(1<<1) | (0xf<<2) | (0xf<<6), 1,
+				"READ(12)")) == 0)
+			reply = do_read(fsg);
+		break;
+
+	case SC_READ_CAPACITY:
+		fsg->data_size_from_cmnd = 8;
+		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+				(0xf<<2) | (1<<8), 1,
+				"READ CAPACITY")) == 0)
+			reply = do_read_capacity(fsg, bh);
+		break;
+
+	case SC_READ_FORMAT_CAPACITIES:
+		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+				(3<<7), 1,
+				"READ FORMAT CAPACITIES")) == 0)
+			reply = do_read_format_capacities(fsg, bh);
+		break;
+
+	case SC_REQUEST_SENSE:
+		fsg->data_size_from_cmnd = fsg->cmnd[4];
+		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+				(1<<4), 0,
+				"REQUEST SENSE")) == 0)
+			reply = do_request_sense(fsg, bh);
+		break;
+
+	case SC_START_STOP_UNIT:
+		fsg->data_size_from_cmnd = 0;
+		if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
+				(1<<1) | (1<<4), 0,
+				"START-STOP UNIT")) == 0)
+			reply = do_start_stop(fsg);
+		break;
+
+	case SC_SYNCHRONIZE_CACHE:
+		fsg->data_size_from_cmnd = 0;
+		if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
+				(0xf<<2) | (3<<7), 1,
+				"SYNCHRONIZE CACHE")) == 0)
+			reply = do_synchronize_cache(fsg);
+		break;
+
+	case SC_TEST_UNIT_READY:
+		fsg->data_size_from_cmnd = 0;
+		reply = check_command(fsg, 6, DATA_DIR_NONE,
+				0, 1,
+				"TEST UNIT READY");
+		break;
+
+	/* Although optional, this command is used by MS-Windows.  We
+	 * support a minimal version: BytChk must be 0. */
+	case SC_VERIFY:
+		fsg->data_size_from_cmnd = 0;
+		if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
+				(1<<1) | (0xf<<2) | (3<<7), 1,
+				"VERIFY")) == 0)
+			reply = do_verify(fsg);
+		break;
+
+	case SC_WRITE_6:
+		i = fsg->cmnd[4];
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+				(7<<1) | (1<<4), 1,
+				"WRITE(6)")) == 0)
+			reply = do_write(fsg);
+		break;
+
+	case SC_WRITE_10:
+		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
+		if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+				(1<<1) | (0xf<<2) | (3<<7), 1,
+				"WRITE(10)")) == 0)
+			reply = do_write(fsg);
+		break;
+
+	case SC_WRITE_12:
+		fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
+		if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
+				(1<<1) | (0xf<<2) | (0xf<<6), 1,
+				"WRITE(12)")) == 0)
+			reply = do_write(fsg);
+		break;
+
+	/* Some mandatory commands that we recognize but don't implement.
+	 * They don't mean much in this setting.  It's left as an exercise
+	 * for anyone interested to implement RESERVE and RELEASE in terms
+	 * of Posix locks. */
+	case SC_FORMAT_UNIT:
+	case SC_RELEASE:
+	case SC_RESERVE:
+	case SC_SEND_DIAGNOSTIC:
+		// Fall through
+
+	default:
+		fsg->data_size_from_cmnd = 0;
+		sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
+		if ((reply = check_command(fsg, fsg->cmnd_size,
+				DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) {
+			fsg->curlun->sense_data = SS_INVALID_COMMAND;
+			reply = -EINVAL;
+		}
+		break;
+	}
+	up_read(&fsg->filesem);
+
+	if (reply == -EINTR || signal_pending(current))
+		return -EINTR;
+
+	/* Set up the single reply buffer for finish_reply() */
+	if (reply == -EINVAL)
+		reply = 0;		// Error reply length
+	if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
+		reply = min((u32) reply, fsg->data_size_from_cmnd);
+		bh->inreq->length = reply;
+		bh->state = BUF_STATE_FULL;
+		fsg->residue -= reply;
+	}				// Otherwise it's already set
+
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+	struct usb_request	*req = bh->outreq;
+	struct bulk_cb_wrap	*cbw = (struct bulk_cb_wrap *) req->buf;
+
+	/* Was this a real packet? */
+	if (req->status)
+		return -EINVAL;
+
+	/* Is the CBW valid? */
+	if (req->actual != USB_BULK_CB_WRAP_LEN ||
+			cbw->Signature != __constant_cpu_to_le32(
+				USB_BULK_CB_SIG)) {
+		DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
+				req->actual,
+				le32_to_cpu(cbw->Signature));
+
+		/* The Bulk-only spec says we MUST stall the bulk pipes!
+		 * If we want to avoid stalls, set a flag so that we will
+		 * clear the endpoint halts at the next reset. */
+		if (!mod_data.can_stall)
+			set_bit(CLEAR_BULK_HALTS, &fsg->atomic_bitflags);
+		fsg_set_halt(fsg, fsg->bulk_out);
+		halt_bulk_in_endpoint(fsg);
+		return -EINVAL;
+	}
+
+	/* Is the CBW meaningful? */
+	if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+			cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
+				"cmdlen %u\n",
+				cbw->Lun, cbw->Flags, cbw->Length);
+
+		/* We can do anything we want here, so let's stall the
+		 * bulk pipes if we are allowed to. */
+		if (mod_data.can_stall) {
+			fsg_set_halt(fsg, fsg->bulk_out);
+			halt_bulk_in_endpoint(fsg);
+		}
+		return -EINVAL;
+	}
+
+	/* Save the command for later */
+	fsg->cmnd_size = cbw->Length;
+	memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
+	if (cbw->Flags & USB_BULK_IN_FLAG)
+		fsg->data_dir = DATA_DIR_TO_HOST;
+	else
+		fsg->data_dir = DATA_DIR_FROM_HOST;
+	fsg->data_size = cbw->DataTransferLength;
+	if (fsg->data_size == 0)
+		fsg->data_dir = DATA_DIR_NONE;
+	fsg->lun = cbw->Lun;
+	fsg->tag = cbw->Tag;
+	return 0;
+}
+
+
+static int get_next_command(struct fsg_dev *fsg)
+{
+	struct fsg_buffhd	*bh;
+	int			rc = 0;
+
+	if (transport_is_bbb()) {
+
+		/* Wait for the next buffer to become available */
+		bh = fsg->next_buffhd_to_fill;
+		while (bh->state != BUF_STATE_EMPTY) {
+			if ((rc = sleep_thread(fsg)) != 0)
+				return rc;
+			}
+
+		/* Queue a request to read a Bulk-only CBW */
+		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
+		start_transfer(fsg, fsg->bulk_out, bh->outreq,
+				&bh->outreq_busy, &bh->state);
+
+		/* We will drain the buffer in software, which means we
+		 * can reuse it for the next filling.  No need to advance
+		 * next_buffhd_to_fill. */
+
+		/* Wait for the CBW to arrive */
+		while (bh->state != BUF_STATE_FULL) {
+			if ((rc = sleep_thread(fsg)) != 0)
+				return rc;
+			}
+		rc = received_cbw(fsg, bh);
+		bh->state = BUF_STATE_EMPTY;
+
+	} else {		// USB_PR_CB or USB_PR_CBI
+
+		/* Wait for the next command to arrive */
+		while (fsg->cbbuf_cmnd_size == 0) {
+			if ((rc = sleep_thread(fsg)) != 0)
+				return rc;
+			}
+
+		/* Is the previous status interrupt request still busy?
+		 * The host is allowed to skip reading the status,
+		 * so we must cancel it. */
+		if (fsg->intreq_busy)
+			usb_ep_dequeue(fsg->intr_in, fsg->intreq);
+
+		/* Copy the command and mark the buffer empty */
+		fsg->data_dir = DATA_DIR_UNKNOWN;
+		spin_lock_irq(&fsg->lock);
+		fsg->cmnd_size = fsg->cbbuf_cmnd_size;
+		memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
+		fsg->cbbuf_cmnd_size = 0;
+		spin_unlock_irq(&fsg->lock);
+	}
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *d)
+{
+	int	rc;
+
+	ep->driver_data = fsg;
+	rc = usb_ep_enable(ep, d);
+	if (rc)
+		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
+	return rc;
+}
+
+static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
+		struct usb_request **preq)
+{
+	*preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (*preq)
+		return 0;
+	ERROR(fsg, "can't allocate request for %s\n", ep->name);
+	return -ENOMEM;
+}
+
+/*
+ * Reset interface setting and re-init endpoint state (toggle etc).
+ * Call with altsetting < 0 to disable the interface.  The only other
+ * available altsetting is 0, which enables the interface.
+ */
+static int do_set_interface(struct fsg_dev *fsg, int altsetting)
+{
+	int	rc = 0;
+	int	i;
+	const struct usb_endpoint_descriptor	*d;
+
+	if (fsg->running)
+		DBG(fsg, "reset interface\n");
+
+reset:
+	/* Deallocate the requests */
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		struct fsg_buffhd *bh = &fsg->buffhds[i];
+
+		if (bh->inreq) {
+			usb_ep_free_request(fsg->bulk_in, bh->inreq);
+			bh->inreq = NULL;
+		}
+		if (bh->outreq) {
+			usb_ep_free_request(fsg->bulk_out, bh->outreq);
+			bh->outreq = NULL;
+		}
+	}
+	if (fsg->intreq) {
+		usb_ep_free_request(fsg->intr_in, fsg->intreq);
+		fsg->intreq = NULL;
+	}
+
+	/* Disable the endpoints */
+	if (fsg->bulk_in_enabled) {
+		usb_ep_disable(fsg->bulk_in);
+		fsg->bulk_in_enabled = 0;
+	}
+	if (fsg->bulk_out_enabled) {
+		usb_ep_disable(fsg->bulk_out);
+		fsg->bulk_out_enabled = 0;
+	}
+	if (fsg->intr_in_enabled) {
+		usb_ep_disable(fsg->intr_in);
+		fsg->intr_in_enabled = 0;
+	}
+
+	fsg->running = 0;
+	if (altsetting < 0 || rc != 0)
+		return rc;
+
+	DBG(fsg, "set interface %d\n", altsetting);
+
+	/* Enable the endpoints */
+	d = ep_desc(fsg->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc);
+	if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
+		goto reset;
+	fsg->bulk_in_enabled = 1;
+
+	d = ep_desc(fsg->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc);
+	if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
+		goto reset;
+	fsg->bulk_out_enabled = 1;
+
+	if (transport_is_cbi()) {
+		d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc);
+		if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
+			goto reset;
+		fsg->intr_in_enabled = 1;
+	}
+
+	/* Allocate the requests */
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		struct fsg_buffhd	*bh = &fsg->buffhds[i];
+
+		if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
+			goto reset;
+		if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
+			goto reset;
+		bh->inreq->buf = bh->outreq->buf = bh->buf;
+		bh->inreq->dma = bh->outreq->dma = bh->dma;
+		bh->inreq->context = bh->outreq->context = bh;
+		bh->inreq->complete = bulk_in_complete;
+		bh->outreq->complete = bulk_out_complete;
+	}
+	if (transport_is_cbi()) {
+		if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
+			goto reset;
+		fsg->intreq->complete = intr_in_complete;
+	}
+
+	fsg->running = 1;
+	for (i = 0; i < fsg->nluns; ++i)
+		fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+	return rc;
+}
+
+
+/*
+ * Change our operational configuration.  This code must agree with the code
+ * that returns config descriptors, and with interface altsetting code.
+ *
+ * It's also responsible for power management interactions.  Some
+ * configurations might not work with our current power sources.
+ * For now we just assume the gadget is always self-powered.
+ */
+static int do_set_config(struct fsg_dev *fsg, u8 new_config)
+{
+	int	rc = 0;
+
+	/* Disable the single interface */
+	if (fsg->config != 0) {
+		DBG(fsg, "reset config\n");
+		fsg->config = 0;
+		rc = do_set_interface(fsg, -1);
+	}
+
+	/* Enable the interface */
+	if (new_config != 0) {
+		fsg->config = new_config;
+		if ((rc = do_set_interface(fsg, 0)) != 0)
+			fsg->config = 0;	// Reset on errors
+		else {
+			char *speed;
+
+			switch (fsg->gadget->speed) {
+			case USB_SPEED_LOW:	speed = "low";	break;
+			case USB_SPEED_FULL:	speed = "full";	break;
+			case USB_SPEED_HIGH:	speed = "high";	break;
+			default: 		speed = "?";	break;
+			}
+			INFO(fsg, "%s speed config #%d\n", speed, fsg->config);
+		}
+	}
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_dev *fsg)
+{
+	siginfo_t		info;
+	int			sig;
+	int			i;
+	int			num_active;
+	struct fsg_buffhd	*bh;
+	enum fsg_state		old_state;
+	u8			new_config;
+	struct lun		*curlun;
+	unsigned int		exception_req_tag;
+	int			rc;
+
+	/* Clear the existing signals.  Anything but SIGUSR1 is converted
+	 * into a high-priority EXIT exception. */
+	for (;;) {
+		spin_lock_irq(&current->sigmask_lock);
+		sig = dequeue_signal(&fsg->thread_signal_mask, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+		if (!sig)
+			break;
+		if (sig != SIGUSR1) {
+			if (fsg->state < FSG_STATE_EXIT)
+				DBG(fsg, "Main thread exiting on signal\n");
+			raise_exception(fsg, FSG_STATE_EXIT);
+		}
+	}
+
+	/* Cancel all the pending transfers */
+	if (fsg->intreq_busy)
+		usb_ep_dequeue(fsg->intr_in, fsg->intreq);
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		bh = &fsg->buffhds[i];
+		if (bh->inreq_busy)
+			usb_ep_dequeue(fsg->bulk_in, bh->inreq);
+		if (bh->outreq_busy)
+			usb_ep_dequeue(fsg->bulk_out, bh->outreq);
+	}
+
+	/* Wait until everything is idle */
+	for (;;) {
+		num_active = fsg->intreq_busy;
+		for (i = 0; i < NUM_BUFFERS; ++i) {
+			bh = &fsg->buffhds[i];
+			num_active += bh->inreq_busy + bh->outreq_busy;
+		}
+		if (num_active == 0)
+			break;
+		if (sleep_thread(fsg))
+			return;
+	}
+
+	/* Clear out the controller's fifos */
+	if (fsg->bulk_in_enabled)
+		usb_ep_fifo_flush(fsg->bulk_in);
+	if (fsg->bulk_out_enabled)
+		usb_ep_fifo_flush(fsg->bulk_out);
+	if (fsg->intr_in_enabled)
+		usb_ep_fifo_flush(fsg->intr_in);
+
+	/* Reset the I/O buffer states and pointers, the SCSI
+	 * state, and the exception.  Then invoke the handler. */
+	spin_lock_irq(&fsg->lock);
+
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		bh = &fsg->buffhds[i];
+		bh->state = BUF_STATE_EMPTY;
+	}
+	fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
+			&fsg->buffhds[0];
+
+	exception_req_tag = fsg->exception_req_tag;
+	new_config = fsg->new_config;
+	old_state = fsg->state;
+
+	if (old_state == FSG_STATE_ABORT_BULK_OUT)
+		fsg->state = FSG_STATE_STATUS_PHASE;
+	else {
+		for (i = 0; i < fsg->nluns; ++i) {
+			curlun = &fsg->luns[i];
+			curlun->prevent_medium_removal = 0;
+			curlun->sense_data = curlun->unit_attention_data =
+					SS_NO_SENSE;
+			curlun->sense_data_info = 0;
+		}
+		fsg->state = FSG_STATE_IDLE;
+	}
+	spin_unlock_irq(&fsg->lock);
+
+	/* Carry out any extra actions required for the exception */
+	switch (old_state) {
+	default:
+		break;
+
+	case FSG_STATE_ABORT_BULK_OUT:
+		send_status(fsg);
+		spin_lock_irq(&fsg->lock);
+		if (fsg->state == FSG_STATE_STATUS_PHASE)
+			fsg->state = FSG_STATE_IDLE;
+		spin_unlock_irq(&fsg->lock);
+		break;
+
+	case FSG_STATE_RESET:
+		/* In case we were forced against our will to halt a
+		 * bulk endpoint, clear the halt now.  (The SuperH UDC
+		 * requires this.) */
+		if (test_and_clear_bit(CLEAR_BULK_HALTS,
+				&fsg->atomic_bitflags)) {
+			usb_ep_clear_halt(fsg->bulk_in);
+			usb_ep_clear_halt(fsg->bulk_out);
+		}
+
+		if (transport_is_bbb()) {
+			if (fsg->ep0_req_tag == exception_req_tag)
+				ep0_queue(fsg);	// Complete the status stage
+
+		} else if (transport_is_cbi())
+			send_status(fsg);	// Status by interrupt pipe
+
+		/* Technically this should go here, but it would only be
+		 * a waste of time.  Ditto for the INTERFACE_CHANGE and
+		 * CONFIG_CHANGE cases. */
+		// for (i = 0; i < fsg->nluns; ++i)
+		//	fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+		break;
+
+	case FSG_STATE_INTERFACE_CHANGE:
+		rc = do_set_interface(fsg, 0);
+		if (fsg->ep0_req_tag != exception_req_tag)
+			break;
+		if (rc != 0)			// STALL on errors
+			fsg_set_halt(fsg, fsg->ep0);
+		else				// Complete the status stage
+			ep0_queue(fsg);
+		break;
+
+	case FSG_STATE_CONFIG_CHANGE:
+		rc = do_set_config(fsg, new_config);
+		if (fsg->ep0_req_tag != exception_req_tag)
+			break;
+		if (rc != 0)			// STALL on errors
+			fsg_set_halt(fsg, fsg->ep0);
+		else				// Complete the status stage
+			ep0_queue(fsg);
+		break;
+
+	case FSG_STATE_DISCONNECT:
+		fsync_all(fsg);
+		do_set_config(fsg, 0);		// Unconfigured state
+		break;
+
+	case FSG_STATE_EXIT:
+	case FSG_STATE_TERMINATED:
+		do_set_config(fsg, 0);			// Free resources
+		spin_lock_irq(&fsg->lock);
+		fsg->state = FSG_STATE_TERMINATED;	// Stop the thread
+		spin_unlock_irq(&fsg->lock);
+		break;
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_main_thread(void *fsg_)
+{
+	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
+
+	fsg->thread_task = current;
+
+	/* Release all our userspace resources */
+	daemonize();
+	reparent_to_init();
+	strncpy(current->comm, "file-storage-gadget",
+			sizeof(current->comm) - 1);
+
+	/* Allow the thread to be killed by a signal, but set the signal mask
+	 * to block everything but INT, TERM, KILL, and USR1. */
+	siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
+			sigmask(SIGTERM) | sigmask(SIGKILL) |
+			sigmask(SIGUSR1));
+	spin_lock_irq(&current->sigmask_lock);
+	flush_signals(current);
+	current->blocked = fsg->thread_signal_mask;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	/* Arrange for userspace references to be interpreted as kernel
+	 * pointers.  That way we can pass a kernel pointer to a routine
+	 * that expects a __user pointer and it will work okay. */
+	set_fs(get_ds());
+
+	/* Wait for the gadget registration to finish up */
+	wait_for_completion(&fsg->thread_notifier);
+
+	/* The main loop */
+	while (fsg->state != FSG_STATE_TERMINATED) {
+		if (exception_in_progress(fsg) || signal_pending(current)) {
+			handle_exception(fsg);
+			continue;
+		}
+
+		if (!fsg->running) {
+			sleep_thread(fsg);
+			continue;
+		}
+
+		if (get_next_command(fsg))
+			continue;
+
+		spin_lock_irq(&fsg->lock);
+		if (!exception_in_progress(fsg))
+			fsg->state = FSG_STATE_DATA_PHASE;
+		spin_unlock_irq(&fsg->lock);
+
+		if (do_scsi_command(fsg) || finish_reply(fsg))
+			continue;
+
+		spin_lock_irq(&fsg->lock);
+		if (!exception_in_progress(fsg))
+			fsg->state = FSG_STATE_STATUS_PHASE;
+		spin_unlock_irq(&fsg->lock);
+
+		if (send_status(fsg))
+			continue;
+
+		spin_lock_irq(&fsg->lock);
+		if (!exception_in_progress(fsg))
+			fsg->state = FSG_STATE_IDLE;
+		spin_unlock_irq(&fsg->lock);
+		}
+
+	fsg->thread_task = NULL;
+	flush_signals(current);
+
+	/* In case we are exiting because of a signal, unregister the
+	 * gadget driver and close the backing file. */
+	if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) {
+		usb_gadget_unregister_driver(&fsg_driver);
+		close_all_backing_files(fsg);
+	}
+
+	/* Let the unbind and cleanup routines know the thread has exited */
+	complete_and_exit(&fsg->thread_notifier, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing. */
+
+static int NORMALLY_INIT open_backing_file(struct lun *curlun,
+		const char *filename)
+{
+	int				ro;
+	struct file			*filp = NULL;
+	int				rc = -EINVAL;
+	struct inode			*inode = NULL;
+	loff_t				size;
+	loff_t				num_sectors;
+
+	/* R/W if we can, R/O if we must */
+	ro = curlun->ro;
+	if (!ro) {
+		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
+		if (-EROFS == PTR_ERR(filp))
+			ro = 1;
+	}
+	if (ro)
+		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
+	if (IS_ERR(filp)) {
+		LINFO(curlun, "unable to open backing file: %s\n", filename);
+		return PTR_ERR(filp);
+	}
+
+	if (!(filp->f_mode & FMODE_WRITE))
+		ro = 1;
+
+	if (filp->f_dentry)
+		inode = filp->f_dentry->d_inode;
+	if (inode && S_ISBLK(inode->i_mode)) {
+		kdev_t		dev = inode->i_rdev;
+
+		if (blk_size[MAJOR(dev)])
+			size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] <<
+					BLOCK_SIZE_BITS;
+		else {
+			LINFO(curlun, "unable to find file size: %s\n",
+					filename);
+			goto out;
+		}
+	} else if (inode && S_ISREG(inode->i_mode))
+		size = inode->i_size;
+	else {
+		LINFO(curlun, "invalid file type: %s\n", filename);
+		goto out;
+	}
+
+	/* If we can't read the file, it's no good.
+	 * If we can't write the file, use it read-only. */
+	if (!filp->f_op || !filp->f_op->read) {
+		LINFO(curlun, "file not readable: %s\n", filename);
+		goto out;
+	}
+	if (IS_RDONLY(inode) || !filp->f_op->write)
+		ro = 1;
+
+	num_sectors = size >> 9;	// File size in 512-byte sectors
+	if (num_sectors == 0) {
+		LINFO(curlun, "file too small: %s\n", filename);
+		rc = -ETOOSMALL;
+		goto out;
+	}
+
+	get_file(filp);
+	curlun->ro = ro;
+	curlun->filp = filp;
+	curlun->file_length = size;
+	curlun->num_sectors = num_sectors;
+	LDBG(curlun, "open backing file: %s\n", filename);
+	rc = 0;
+
+out:
+	filp_close(filp, current->files);
+	return rc;
+}
+
+
+static void close_backing_file(struct lun *curlun)
+{
+	if (curlun->filp) {
+		LDBG(curlun, "close backing file\n");
+		fput(curlun->filp);
+		curlun->filp = NULL;
+	}
+}
+
+static void close_all_backing_files(struct fsg_dev *fsg)
+{
+	int	i;
+
+	for (i = 0; i < fsg->nluns; ++i)
+		close_backing_file(&fsg->luns[i]);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void fsg_unbind(struct usb_gadget *gadget)
+{
+	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	int			i;
+	struct usb_request	*req = fsg->ep0req;
+
+	DBG(fsg, "unbind\n");
+	clear_bit(REGISTERED, &fsg->atomic_bitflags);
+
+	/* If the thread isn't already dead, tell it to exit now */
+	if (fsg->state != FSG_STATE_TERMINATED) {
+		raise_exception(fsg, FSG_STATE_EXIT);
+		wait_for_completion(&fsg->thread_notifier);
+
+		/* The cleanup routine waits for this completion also */
+		complete(&fsg->thread_notifier);
+	}
+
+	/* Free the data buffers */
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		struct fsg_buffhd	*bh = &fsg->buffhds[i];
+
+		if (bh->buf)
+			usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
+					mod_data.buflen);
+	}
+
+	/* Free the request and buffer for endpoint 0 */
+	if (req) {
+		if (req->buf)
+			usb_ep_free_buffer(fsg->ep0, req->buf,
+					req->dma, EP0_BUFSIZE);
+		usb_ep_free_request(fsg->ep0, req);
+	}
+
+	set_gadget_data(gadget, 0);
+}
+
+
+static int __init check_parameters(struct fsg_dev *fsg)
+{
+	int	prot;
+
+	/* Store the default values */
+	mod_data.transport_type = USB_PR_BULK;
+	mod_data.transport_name = "Bulk-only";
+	mod_data.protocol_type = USB_SC_SCSI;
+	mod_data.protocol_name = "Transparent SCSI";
+
+	prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
+
+#ifdef CONFIG_USB_FILE_STORAGE_TEST
+	if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
+		;		// Use default setting
+	} else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
+		mod_data.transport_type = USB_PR_CB;
+		mod_data.transport_name = "Control-Bulk";
+	} else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
+		mod_data.transport_type = USB_PR_CBI;
+		mod_data.transport_name = "Control-Bulk-Interrupt";
+	} else {
+		INFO(fsg, "invalid transport: %s\n", mod_data.transport_parm);
+		return -EINVAL;
+	}
+
+	if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
+			prot == USB_SC_SCSI) {
+		;		// Use default setting
+	} else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
+			prot == USB_SC_RBC) {
+		mod_data.protocol_type = USB_SC_RBC;
+		mod_data.protocol_name = "RBC";
+	} else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
+			strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
+			prot == USB_SC_8020) {
+		mod_data.protocol_type = USB_SC_8020;
+		mod_data.protocol_name = "8020i (ATAPI)";
+	} else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
+			prot == USB_SC_QIC) {
+		mod_data.protocol_type = USB_SC_QIC;
+		mod_data.protocol_name = "QIC-157";
+	} else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
+			prot == USB_SC_UFI) {
+		mod_data.protocol_type = USB_SC_UFI;
+		mod_data.protocol_name = "UFI";
+	} else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
+			prot == USB_SC_8070) {
+		mod_data.protocol_type = USB_SC_8070;
+		mod_data.protocol_name = "8070i";
+	} else {
+		INFO(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
+		return -EINVAL;
+	}
+
+	mod_data.buflen &= PAGE_CACHE_MASK;
+	if (mod_data.buflen <= 0) {
+		INFO(fsg, "invalid buflen\n");
+		return -ETOOSMALL;
+	}
+#endif /* CONFIG_USB_FILE_STORAGE_TEST */
+
+	return 0;
+}
+
+
+static int __init fsg_bind(struct usb_gadget *gadget)
+{
+	struct fsg_dev		*fsg = the_fsg;
+	int			rc;
+	int			i;
+	struct lun		*curlun;
+	struct usb_ep		*ep;
+	struct usb_request	*req;
+	char			*pathbuf, *p;
+
+	fsg->gadget = gadget;
+	set_gadget_data(gadget, fsg);
+	fsg->ep0 = gadget->ep0;
+	fsg->ep0->driver_data = fsg;
+
+	if ((rc = check_parameters(fsg)) != 0)
+		goto out;
+
+	/* Find out how many LUNs there should be */
+	i = mod_data.nluns;
+	if (i == 0) {
+		for (i = MAX_LUNS; i > 1; --i) {
+			if (file[i - 1])
+				break;
+		}
+	}
+	if (i > MAX_LUNS) {
+		INFO(fsg, "invalid number of LUNs: %d\n", i);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Create the LUNs and open their backing files.  We can't register
+	 * the LUN devices until the gadget itself is registered, which
+	 * doesn't happen until after fsg_bind() returns. */
+	fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL);
+	if (!fsg->luns) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(fsg->luns, 0, i * sizeof(struct lun));
+	fsg->nluns = i;
+
+	for (i = 0; i < fsg->nluns; ++i) {
+		curlun = &fsg->luns[i];
+		curlun->ro = ro[i];
+		curlun->dev.driver_data = fsg;
+		snprintf(curlun->dev.name, BUS_ID_SIZE,
+				"%s-lun%d", gadget->name, i);
+
+		if (file[i] && *file[i]) {
+			if ((rc = open_backing_file(curlun, file[i])) != 0)
+				goto out;
+		} else if (!mod_data.removable) {
+			INFO(fsg, "no file given for LUN%d\n", i);
+			rc = -EINVAL;
+			goto out;
+		}
+	}
+
+	/* Fix up the descriptors */
+	device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
+#ifdef HIGHSPEED
+	dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;		// ???
+#endif
+	device_desc.idVendor = cpu_to_le16(mod_data.vendor);
+	device_desc.idProduct = cpu_to_le16(mod_data.product);
+	device_desc.bcdDevice = cpu_to_le16(mod_data.release);
+
+	i = (transport_is_cbi() ? 3 : 2);	// Number of endpoints
+	config_desc.wTotalLength = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE
+			+ USB_DT_ENDPOINT_SIZE * i;
+	intf_desc.bNumEndpoints = i;
+	intf_desc.bInterfaceSubClass = mod_data.protocol_type;
+	intf_desc.bInterfaceProtocol = mod_data.transport_type;
+
+	/* Find all the endpoints we will use */
+	gadget_for_each_ep(ep, gadget) {
+		if (strcmp(ep->name, EP_BULK_IN_NAME) == 0)
+			fsg->bulk_in = ep;
+		else if (strcmp(ep->name, EP_BULK_OUT_NAME) == 0)
+			fsg->bulk_out = ep;
+		else if (strcmp(ep->name, EP_INTR_IN_NAME) == 0)
+			fsg->intr_in = ep;
+	}
+	if (!fsg->bulk_in || !fsg->bulk_out ||
+			(transport_is_cbi() && !fsg->intr_in)) {
+		DBG(fsg, "unable to find all endpoints\n");
+		rc = -ENOTSUPP;
+		goto out;
+	}
+	fsg->bulk_out_maxpacket = (gadget->speed == USB_SPEED_HIGH ? 512 :
+			FS_BULK_OUT_MAXPACKET);
+
+	rc = -ENOMEM;
+
+	/* Allocate the request and buffer for endpoint 0 */
+	fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
+	if (!req)
+		goto out;
+	req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
+			&req->dma, GFP_KERNEL);
+	if (!req->buf)
+		goto out;
+	req->complete = ep0_complete;
+
+	/* Allocate the data buffers */
+	for (i = 0; i < NUM_BUFFERS; ++i) {
+		struct fsg_buffhd	*bh = &fsg->buffhds[i];
+
+		bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,
+				&bh->dma, GFP_KERNEL);
+		if (!bh->buf)
+			goto out;
+		bh->next = bh + 1;
+	}
+	fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0];
+
+	/* This should reflect the actual gadget power source */
+	usb_gadget_set_selfpowered(gadget);
+
+	/* On a real device, serial[] would be loaded from permanent
+	 * storage.  We just encode it from the driver version string. */
+	for (i = 0; i < sizeof(serial) - 2; i += 2) {
+		unsigned char		c = DRIVER_VERSION[i / 2];
+
+		if (!c)
+			break;
+		sprintf(&serial[i], "%02X", c);
+	}
+
+	if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS |
+			CLONE_FILES))) < 0)
+		goto out;
+	fsg->thread_pid = rc;
+
+	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
+
+	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+	for (i = 0; i < fsg->nluns; ++i) {
+		curlun = &fsg->luns[i];
+		if (backing_file_is_open(curlun)) {
+			p = NULL;
+			if (pathbuf) {
+				p = d_path(curlun->filp->f_dentry,
+					curlun->filp->f_vfsmnt,
+					pathbuf, PATH_MAX);
+				if (IS_ERR(p))
+					p = NULL;
+			}
+			LINFO(curlun, "ro=%d, file: %s\n",
+					curlun->ro, (p ? p : "(error)"));
+		}
+	}
+	kfree(pathbuf);
+
+	DBG(fsg, "transport=%s (x%02x)\n",
+			mod_data.transport_name, mod_data.transport_type);
+	DBG(fsg, "protocol=%s (x%02x)\n",
+			mod_data.protocol_name, mod_data.protocol_type);
+	DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
+			mod_data.vendor, mod_data.product, mod_data.release);
+	DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
+			mod_data.removable, mod_data.can_stall,
+			mod_data.buflen);
+	DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid);
+	return 0;
+
+out:
+	fsg->state = FSG_STATE_TERMINATED;	// The thread is dead
+	fsg_unbind(gadget);
+	close_all_backing_files(fsg);
+	return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver		fsg_driver = {
+#ifdef HIGHSPEED
+	.speed		= USB_SPEED_HIGH,
+#else
+	.speed		= USB_SPEED_FULL,
+#endif
+	.function	= (char *) longname,
+	.bind		= fsg_bind,
+	.unbind		= fsg_unbind,
+	.disconnect	= fsg_disconnect,
+	.setup		= fsg_setup,
+
+	.driver		= {
+		.name		= (char *) shortname,
+		// .release = ...
+		// .suspend = ...
+		// .resume = ...
+	},
+};
+
+
+static int __init fsg_alloc(void)
+{
+	struct fsg_dev		*fsg;
+
+	fsg = kmalloc(sizeof *fsg, GFP_KERNEL);
+	if (!fsg)
+		return -ENOMEM;
+	memset(fsg, 0, sizeof *fsg);
+	spin_lock_init(&fsg->lock);
+	init_rwsem(&fsg->filesem);
+	init_waitqueue_head(&fsg->thread_wqh);
+	init_completion(&fsg->thread_notifier);
+
+	the_fsg = fsg;
+	return 0;
+}
+
+
+static void fsg_free(struct fsg_dev *fsg)
+{
+	kfree(fsg->luns);
+	kfree(fsg);
+}
+
+
+static int __init fsg_init(void)
+{
+	int		rc;
+	struct fsg_dev	*fsg;
+
+	/* Put the module parameters where they belong -- arghh! */
+	mod_data.nluns = luns;
+	mod_data.transport_parm = transport;
+	mod_data.protocol_parm = protocol;
+	mod_data.removable = removable;
+	mod_data.vendor = vendor;
+	mod_data.product = product;
+	mod_data.release = release;
+	mod_data.buflen = buflen;
+	mod_data.can_stall = stall;
+
+	if ((rc = fsg_alloc()) != 0)
+		return rc;
+	fsg = the_fsg;
+	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) {
+		fsg_free(fsg);
+		return rc;
+	}
+	set_bit(REGISTERED, &fsg->atomic_bitflags);
+
+	/* Tell the thread to start working */
+	complete(&fsg->thread_notifier);
+	return 0;
+}
+module_init(fsg_init);
+
+
+static void __exit fsg_cleanup(void)
+{
+	struct fsg_dev	*fsg = the_fsg;
+
+	/* Unregister the driver iff the thread hasn't already done so */
+	if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
+		usb_gadget_unregister_driver(&fsg_driver);
+
+	/* Wait for the thread to finish up */
+	wait_for_completion(&fsg->thread_notifier);
+
+	close_all_backing_files(fsg);
+	fsg_free(fsg);
+}
+module_exit(fsg_cleanup);
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/goku_udc.c linux-2.4.25-pre8/drivers/usb/gadget/goku_udc.c
--- linux-2.4.25-pre7/drivers/usb/gadget/goku_udc.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/goku_udc.c	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,1975 @@
+/*
+ * Toshiba TC86C001 ("Goku-S") USB Device Controller driver
+ *
+ * Copyright (C) 2000-2002 Lineo
+ *      by Stuart Lynne, Tom Rushworth, and Bruce Balden
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2003 MontaVista Software (source@mvista.com)
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * This device has ep0 and three semi-configurable bulk/interrupt endpoints.
+ *
+ *  - Endpoint numbering is fixed: ep{1,2,3}-bulk
+ *  - Gadget drivers can choose ep maxpacket (8/16/32/64)
+ *  - Gadget drivers can choose direction (IN, OUT)
+ *  - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
+ */
+
+#undef DEBUG
+// #define	VERBOSE		/* extra debug messages (success too) */
+// #define	USB_TRACE	/* packet-level success messages */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+#include "goku_udc.h"
+
+#define	DRIVER_DESC		"TC86C001 USB Device Controller"
+#define	DRIVER_VERSION		"30-Oct 2003"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+static const char driver_name [] = "goku_udc";
+static const char driver_desc [] = DRIVER_DESC;
+
+MODULE_AUTHOR("source@mvista.com");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+
+/*
+ * IN dma behaves ok under testing, though the IN-dma abort paths don't
+ * seem to behave quite as expected.  Used by default.
+ *
+ * OUT dma documents design problems handling the common "short packet"
+ * transfer termination policy; it couldn't enabled by default, even
+ * if the OUT-dma abort problems had a resolution.
+ */
+static unsigned use_dma = 1;
+
+#if 0
+//#include <linux/moduleparam.h>
+/* "modprobe goku_udc use_dma=1" etc
+ *	0 to disable dma
+ *	1 to use IN dma only (normal operation)
+ *	2 to use IN and OUT dma
+ */
+module_param(use_dma, uint, S_IRUGO);
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void nuke(struct goku_ep *, int status);
+
+static inline void
+command(struct goku_udc_regs *regs, int command, unsigned epnum)
+{
+	writel(COMMAND_EP(epnum) | command, &regs->Command);
+	udelay(300);
+}
+
+static int
+goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct goku_udc	*dev;
+	struct goku_ep	*ep;
+	u32		mode;
+	u16		max;
+	unsigned long	flags;
+
+	ep = container_of(_ep, struct goku_ep, ep);
+	if (!_ep || !desc || ep->desc
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+	dev = ep->dev;
+	if (ep == &dev->ep[0])
+		return -EINVAL;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+	if (ep->num != (desc->bEndpointAddress & 0x0f))
+		return -EINVAL;
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((readl(ep->reg_status) & EPxSTATUS_EP_MASK)
+			!= EPxSTATUS_EP_INVALID)
+		return -EBUSY;
+
+	/* enabling the no-toggle interrupt mode would need an api hook */
+	mode = 0;
+	max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+	switch (max) {
+	case 64:	mode++;
+	case 32:	mode++;
+	case 16:	mode++;
+	case 8:		mode <<= 3;
+			break;
+	default:
+		return -EINVAL;
+	}
+	mode |= 2 << 1;		/* bulk, or intr-with-toggle */
+
+	/* ep1/ep2 dma direction is chosen early; it works in the other
+	 * direction, with pio.  be cautious with out-dma.
+	 */
+	ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
+	if (ep->is_in) {
+		mode |= 1;
+		ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT);
+	} else {
+		ep->dma = (use_dma == 2) && (ep->num == UDC_MSTWR_ENDPOINT);
+		if (ep->dma)
+			DBG(dev, "%s out-dma hides short packets\n",
+				ep->ep.name);
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* ep1 and ep2 can do double buffering and/or dma */
+	if (ep->num < 3) {
+		struct goku_udc_regs	*regs = ep->dev->regs;
+		u32			tmp;
+
+		/* double buffer except (for now) with pio in */
+		tmp = ((ep->dma || !ep->is_in)
+				? 0x10	/* double buffered */
+				: 0x11	/* single buffer */
+			) << ep->num;
+		tmp |= readl(&regs->EPxSingle);
+		writel(tmp, &regs->EPxSingle);
+
+		tmp = (ep->dma ? 0x10/*dma*/ : 0x11/*pio*/) << ep->num;
+		tmp |= readl(&regs->EPxBCS);
+		writel(tmp, &regs->EPxBCS);
+	}
+	writel(mode, ep->reg_mode);
+	command(ep->dev->regs, COMMAND_RESET, ep->num);
+	ep->ep.maxpacket = max;
+	ep->stopped = 0;
+	ep->desc = desc;
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name,
+		ep->is_in ? "IN" : "OUT",
+		ep->dma ? "dma" : "pio",
+		max);
+
+	return 0;
+}
+
+static void ep_reset(struct goku_udc_regs *regs, struct goku_ep *ep)
+{
+	struct goku_udc		*dev = ep->dev;
+
+	if (regs) {
+		command(regs, COMMAND_INVALID, ep->num);
+		if (ep->num) {
+			if (ep->num == UDC_MSTWR_ENDPOINT)
+				dev->int_enable &= ~(INT_MSTWREND
+							|INT_MSTWRTMOUT);
+			else if (ep->num == UDC_MSTRD_ENDPOINT)
+				dev->int_enable &= ~INT_MSTRDEND;
+			dev->int_enable &= ~INT_EPxDATASET (ep->num);
+		} else
+			dev->int_enable &= ~INT_EP0;
+		writel(dev->int_enable, &regs->int_enable);
+		readl(&regs->int_enable);
+		if (ep->num < 3) {
+			struct goku_udc_regs	*regs = ep->dev->regs;
+			u32			tmp;
+
+			tmp = readl(&regs->EPxSingle);
+			tmp &= ~(0x11 << ep->num);
+			writel(tmp, &regs->EPxSingle);
+
+			tmp = readl(&regs->EPxBCS);
+			tmp &= ~(0x11 << ep->num);
+			writel(tmp, &regs->EPxBCS);
+		}
+		/* reset dma in case we're still using it */
+		if (ep->dma) {
+			u32	master;
+
+			master = readl(&regs->dma_master) & MST_RW_BITS;
+			if (ep->num == UDC_MSTWR_ENDPOINT) {
+				master &= ~MST_W_BITS;
+				master |= MST_WR_RESET;
+			} else {
+				master &= ~MST_R_BITS;
+				master |= MST_RD_RESET;
+			}
+			writel(master, &regs->dma_master);
+		}
+	}
+
+	ep->ep.maxpacket = MAX_FIFO_SIZE;
+	ep->desc = 0;
+	ep->stopped = 1;
+	ep->irqs = 0;
+	ep->dma = 0;
+}
+
+static int goku_ep_disable(struct usb_ep *_ep)
+{
+	struct goku_ep	*ep;
+	struct goku_udc	*dev;
+	unsigned long	flags;
+
+	ep = container_of(_ep, struct goku_ep, ep);
+	if (!_ep || !ep->desc)
+		return -ENODEV;
+	dev = ep->dev;
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	VDBG(dev, "disable %s\n", _ep->name);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	nuke(ep, -ESHUTDOWN);
+	ep_reset(dev->regs, ep);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+goku_alloc_request(struct usb_ep *_ep, int gfp_flags)
+{
+	struct goku_request	*req;
+
+	if (!_ep)
+		return 0;
+	req = kmalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return 0;
+
+	memset(req, 0, sizeof *req);
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void
+goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct goku_request	*req;
+
+	if (!_ep || !_req)
+		return;
+
+	req = container_of(_req, struct goku_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#undef USE_KMALLOC
+
+/* many common platforms have dma-coherent caches, which means that it's
+ * safe to use kmalloc() memory for all i/o buffers without using any
+ * cache flushing calls.  (unless you're trying to share cache lines
+ * between dma and non-dma activities, which is a slow idea in any case.)
+ *
+ * other platforms need more care, with 2.6 having a moderately general
+ * solution except for the common "buffer is smaller than a page" case.
+ */
+#if	defined(CONFIG_X86)
+#define USE_KMALLOC
+
+#elif	defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+
+#elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+#define USE_KMALLOC
+
+#endif
+
+/* allocating buffers this way eliminates dma mapping overhead, which
+ * on some platforms will mean eliminating a per-io buffer copy.  with
+ * some kinds of system caches, further tweaks may still be needed.
+ */
+static void *
+goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+			dma_addr_t *dma, int  gfp_flags)
+{
+	void		*retval;
+	struct goku_ep	*ep;
+
+	ep = container_of(_ep, struct goku_ep, ep);
+	if (!_ep)
+		return 0;
+	*dma = DMA_ADDR_INVALID;
+
+#if	defined(USE_KMALLOC)
+	retval = kmalloc(bytes, gfp_flags);
+	if (retval)
+		*dma = virt_to_phys(retval);
+#else
+	if (ep->dma) {
+		/* one problem with this call is that it wastes memory on
+		 * typical 1/N page allocations: it allocates 1-N pages.
+		 * another is that it always uses GFP_ATOMIC.
+		 */
+#warning Using pci_alloc_consistent even with buffers smaller than a page.
+		retval = pci_alloc_consistent(ep->dev->pdev, bytes, dma);
+	} else
+		retval = kmalloc(bytes, gfp_flags);
+#endif
+	return retval;
+}
+
+static void
+goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes)
+{
+	/* free memory into the right allocator */
+#ifndef	USE_KMALLOC
+	if (dma != DMA_ADDR_INVALID) {
+		struct goku_ep	*ep;
+
+		ep = container_of(_ep, struct goku_ep, ep);
+		if (!_ep)
+			return;
+		/* one problem with this call is that some platforms
+		 * don't allow it to be used in_irq().
+		 */
+		pci_free_consistent(ep->dev->pdev, bytes, buf, dma);
+	} else
+#endif
+		kfree (buf);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+done(struct goku_ep *ep, struct goku_request *req, int status)
+{
+	struct goku_udc		*dev;
+	unsigned		stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	dev = ep->dev;
+	if (req->mapped) {
+		pci_unmap_single(dev->pdev, req->req.dma, req->req.length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+#ifndef USB_TRACE
+	if (status && status != -ESHUTDOWN)
+#endif
+		VDBG(dev, "complete %s req %p stat %d len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	spin_unlock(&dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+write_packet(u32 *fifo, u8 *buf, struct goku_request *req, unsigned max)
+{
+	unsigned	length, count;
+
+	length = min(req->req.length - req->req.actual, max);
+	req->req.actual += length;
+
+	count = length;
+	while (likely(count--))
+		writel(*buf++, fifo);
+	return length;
+}
+
+// return:  0 = still running, 1 = completed, negative = errno
+static int write_fifo(struct goku_ep *ep, struct goku_request *req)
+{
+	struct goku_udc	*dev = ep->dev;
+	u32		tmp;
+	u8		*buf;
+	unsigned	count;
+	int		is_last;
+
+	tmp = readl(&dev->regs->DataSet);
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+
+	dev = ep->dev;
+	if (unlikely(ep->num == 0 && dev->ep0state != EP0_IN))
+		return -EL2HLT;
+
+	/* NOTE:  just single-buffered PIO-IN for now.  */
+	if (unlikely((tmp & DATASET_A(ep->num)) != 0))
+		return 0;
+
+	/* clear our "packet available" irq */
+	if (ep->num != 0)
+		writel(~INT_EPxDATASET(ep->num), &dev->regs->int_status);
+
+	count = write_packet(ep->reg_fifo, buf, req, ep->ep.maxpacket);
+
+	/* last packet often short (sometimes a zlp, especially on ep0) */
+	if (unlikely(count != ep->ep.maxpacket)) {
+		writel(~(1<<ep->num), &dev->regs->EOP);
+		if (ep->num == 0) {
+			dev->ep[0].stopped = 1;
+			dev->ep0state = EP0_STATUS;
+		}
+		is_last = 1;
+	} else {
+		if (likely(req->req.length != req->req.actual)
+				|| req->req.zero)
+			is_last = 0;
+		else
+			is_last = 1;
+	}
+#if 0		/* printk seemed to trash is_last...*/
+//#ifdef USB_TRACE
+	VDBG(dev, "wrote %s %u bytes%s IN %u left %p\n",
+		ep->ep.name, count, is_last ? "/last" : "",
+		req->req.length - req->req.actual, req);
+#endif
+
+	/* requests complete when all IN data is in the FIFO,
+	 * or sometimes later, if a zlp was needed.
+	 */
+	if (is_last) {
+		done(ep, req, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int read_fifo(struct goku_ep *ep, struct goku_request *req)
+{
+	struct goku_udc_regs	*regs;
+	u32			size, set;
+	u8			*buf;
+	unsigned		bufferspace, is_short, dbuff;
+
+	regs = ep->dev->regs;
+top:
+	buf = req->req.buf + req->req.actual;
+	prefetchw(buf);
+
+	if (unlikely(ep->num == 0 && ep->dev->ep0state != EP0_OUT))
+		return -EL2HLT;
+
+	dbuff = (ep->num == 1 || ep->num == 2);
+	do {
+		/* ack dataset irq matching the status we'll handle */
+		if (ep->num != 0)
+			writel(~INT_EPxDATASET(ep->num), &regs->int_status);
+
+		set = readl(&regs->DataSet) & DATASET_AB(ep->num);
+		size = readl(&regs->EPxSizeLA[ep->num]);
+		bufferspace = req->req.length - req->req.actual;
+
+		/* usually do nothing without an OUT packet */
+		if (likely(ep->num != 0 || bufferspace != 0)) {
+			if (unlikely(set == 0))
+				break;
+			/* use ep1/ep2 double-buffering for OUT */
+			if (!(size & PACKET_ACTIVE))
+				size = readl(&regs->EPxSizeLB[ep->num]);
+			if (!(size & PACKET_ACTIVE)) 	// "can't happen"
+				break;
+			size &= DATASIZE;	/* EPxSizeH == 0 */
+
+		/* ep0out no-out-data case for set_config, etc */
+		} else
+			size = 0;
+
+		/* read all bytes from this packet */
+		req->req.actual += size;
+		is_short = (size < ep->ep.maxpacket);
+#ifdef USB_TRACE
+		VDBG(ep->dev, "read %s %u bytes%s OUT req %p %u/%u\n",
+			ep->ep.name, size, is_short ? "/S" : "",
+			req, req->req.actual, req->req.length);
+#endif
+		while (likely(size-- != 0)) {
+			u8	byte = (u8) readl(ep->reg_fifo);
+
+			if (unlikely(bufferspace == 0)) {
+				/* this happens when the driver's buffer
+				 * is smaller than what the host sent.
+				 * discard the extra data in this packet.
+				 */
+				if (req->req.status != -EOVERFLOW)
+					DBG(ep->dev, "%s overflow %u\n",
+						ep->ep.name, size);
+				req->req.status = -EOVERFLOW;
+			} else {
+				*buf++ = byte;
+				bufferspace--;
+			}
+		}
+
+		/* completion */
+		if (unlikely(is_short || req->req.actual == req->req.length)) {
+			if (unlikely(ep->num == 0)) {
+				/* non-control endpoints now usable? */
+				if (ep->dev->req_config)
+					writel(ep->dev->configured
+							? USBSTATE_CONFIGURED
+							: 0,
+						&regs->UsbState);
+				/* ep0out status stage */
+				writel(~(1<<0), &regs->EOP);
+				ep->stopped = 1;
+				ep->dev->ep0state = EP0_STATUS;
+			}
+			done(ep, req, 0);
+
+			/* empty the second buffer asap */
+			if (dbuff && !list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+						struct goku_request, queue);
+				goto top;
+			}
+			return 1;
+		}
+	} while (dbuff);
+	return 0;
+}
+
+static inline void
+pio_irq_enable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
+{
+	dev->int_enable |= INT_EPxDATASET (epnum);
+	writel(dev->int_enable, &regs->int_enable);
+	/* write may still be posted */
+}
+
+static inline void
+pio_irq_disable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
+{
+	dev->int_enable &= ~INT_EPxDATASET (epnum);
+	writel(dev->int_enable, &regs->int_enable);
+	/* write may still be posted */
+}
+
+static inline void
+pio_advance(struct goku_ep *ep)
+{
+	struct goku_request	*req;
+
+	if (unlikely(list_empty (&ep->queue)))
+		return;
+	req = list_entry(ep->queue.next, struct goku_request, queue);
+	(ep->is_in ? write_fifo : read_fifo)(ep, req);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+// return:  0 = q running, 1 = q stopped, negative = errno
+static int start_dma(struct goku_ep *ep, struct goku_request *req)
+{
+	struct goku_udc_regs	*regs = ep->dev->regs;
+	u32			master;
+	u32			start = req->req.dma;
+	u32			end = start + req->req.length - 1;
+
+	master = readl(&regs->dma_master) & MST_RW_BITS;
+
+	/* re-init the bits affecting IN dma; careful with zlps */
+	if (likely(ep->is_in)) {
+		if (unlikely(master & MST_RD_ENA)) {
+			DBG (ep->dev, "start, IN active dma %03x!!\n",
+				master);
+//			return -EL2HLT;
+		}
+		writel(end, &regs->in_dma_end);
+		writel(start, &regs->in_dma_start);
+
+		master &= ~MST_R_BITS;
+		if (unlikely(req->req.length == 0))
+			master = MST_RD_ENA | MST_RD_EOPB;
+		else if ((req->req.length % ep->ep.maxpacket) != 0
+					|| req->req.zero)
+			master = MST_RD_ENA | MST_EOPB_ENA;
+		else
+			master = MST_RD_ENA | MST_EOPB_DIS;
+
+		ep->dev->int_enable |= INT_MSTRDEND;
+
+	/* Goku DMA-OUT merges short packets, which plays poorly with
+	 * protocols where short packets mark the transfer boundaries.
+	 * The chip supports a nonstandard policy with INT_MSTWRTMOUT,
+	 * ending transfers after 3 SOFs; we don't turn it on.
+	 */
+	} else {
+		if (unlikely(master & MST_WR_ENA)) {
+			DBG (ep->dev, "start, OUT active dma %03x!!\n",
+				master);
+//			return -EL2HLT;
+		}
+		writel(end, &regs->out_dma_end);
+		writel(start, &regs->out_dma_start);
+
+		master &= ~MST_W_BITS;
+		master |= MST_WR_ENA | MST_TIMEOUT_DIS;
+
+		ep->dev->int_enable |= INT_MSTWREND|INT_MSTWRTMOUT;
+	}
+
+	writel(master, &regs->dma_master);
+	writel(ep->dev->int_enable, &regs->int_enable);
+	return 0;
+}
+
+static void dma_advance(struct goku_udc *dev, struct goku_ep *ep)
+{
+	struct goku_request	*req;
+	struct goku_udc_regs	*regs = ep->dev->regs;
+	u32			master;
+
+	master = readl(&regs->dma_master);
+
+	if (unlikely(list_empty(&ep->queue))) {
+stop:
+		if (ep->is_in)
+			dev->int_enable &= ~INT_MSTRDEND;
+		else
+			dev->int_enable &= ~(INT_MSTWREND|INT_MSTWRTMOUT);
+		writel(dev->int_enable, &regs->int_enable);
+		return;
+	}
+	req = list_entry(ep->queue.next, struct goku_request, queue);
+
+	/* normal hw dma completion (not abort) */
+	if (likely(ep->is_in)) {
+		if (unlikely(master & MST_RD_ENA))
+			return;
+		req->req.actual = readl(&regs->in_dma_current);
+	} else {
+		if (unlikely(master & MST_WR_ENA))
+			return;
+
+		/* hardware merges short packets, and also hides packet
+		 * overruns.  a partial packet MAY be in the fifo here.
+		 */
+		req->req.actual = readl(&regs->out_dma_current);
+	}
+	req->req.actual -= req->req.dma;
+	req->req.actual++;
+
+#ifdef USB_TRACE
+	VDBG(dev, "done %s %s dma, %u/%u bytes, req %p\n",
+		ep->ep.name, ep->is_in ? "IN" : "OUT",
+		req->req.actual, req->req.length, req);
+#endif
+	done(ep, req, 0);
+	if (list_empty(&ep->queue))
+		goto stop;
+	req = list_entry(ep->queue.next, struct goku_request, queue);
+	(void) start_dma(ep, req);
+}
+
+static void abort_dma(struct goku_ep *ep, int status)
+{
+	struct goku_udc_regs	*regs = ep->dev->regs;
+	struct goku_request	*req;
+	u32			curr, master;
+
+	/* NAK future host requests, hoping the implicit delay lets the
+	 * dma engine finish reading (or writing) its latest packet and
+	 * empty the dma buffer (up to 16 bytes).
+	 *
+	 * This avoids needing to clean up a partial packet in the fifo;
+	 * we can't do that for IN without side effects to HALT and TOGGLE.
+	 */
+	command(regs, COMMAND_FIFO_DISABLE, ep->num);
+	req = list_entry(ep->queue.next, struct goku_request, queue);
+	master = readl(&regs->dma_master) & MST_RW_BITS;
+
+	/* FIXME using these resets isn't usably documented. this may
+	 * not work unless it's followed by disabling the endpoint.
+	 *
+	 * FIXME the OUT reset path doesn't even behave consistently.
+	 */
+	if (ep->is_in) {
+		if (unlikely((readl(&regs->dma_master) & MST_RD_ENA) == 0))
+			goto finished;
+		curr = readl(&regs->in_dma_current);
+
+		writel(curr, &regs->in_dma_end);
+		writel(curr, &regs->in_dma_start);
+
+		master &= ~MST_R_BITS;
+		master |= MST_RD_RESET;
+		writel(master, &regs->dma_master);
+
+		if (readl(&regs->dma_master) & MST_RD_ENA)
+			DBG(ep->dev, "IN dma active after reset!\n");
+
+	} else {
+		if (unlikely((readl(&regs->dma_master) & MST_WR_ENA) == 0))
+			goto finished;
+		curr = readl(&regs->out_dma_current);
+
+		writel(curr, &regs->out_dma_end);
+		writel(curr, &regs->out_dma_start);
+
+		master &= ~MST_W_BITS;
+		master |= MST_WR_RESET;
+		writel(master, &regs->dma_master);
+
+		if (readl(&regs->dma_master) & MST_WR_ENA)
+			DBG(ep->dev, "OUT dma active after reset!\n");
+	}
+	req->req.actual = (curr - req->req.dma) + 1;
+	req->req.status = status;
+
+	VDBG(ep->dev, "%s %s %s %d/%d\n", __FUNCTION__, ep->ep.name,
+		ep->is_in ? "IN" : "OUT",
+		req->req.actual, req->req.length);
+
+	command(regs, COMMAND_FIFO_ENABLE, ep->num);
+
+	return;
+
+finished:
+	/* dma already completed; no abort needed */
+	command(regs, COMMAND_FIFO_ENABLE, ep->num);
+	req->req.actual = req->req.length;
+	req->req.status = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+	struct goku_request	*req;
+	struct goku_ep		*ep;
+	struct goku_udc		*dev;
+	unsigned long		flags;
+	int			status;
+
+	/* always require a cpu-view buffer so pio works */
+	req = container_of(_req, struct goku_request, req);
+	if (unlikely(!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)))
+		return -EINVAL;
+	ep = container_of(_ep, struct goku_ep, ep);
+	if (unlikely(!_ep || (!ep->desc && ep->num != 0)))
+		return -EINVAL;
+	dev = ep->dev;
+	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
+		return -ESHUTDOWN;
+
+	/* can't touch registers when suspended */
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	/* set up dma mapping in case the caller didn't */
+	if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
+		_req->dma = pci_map_single(dev->pdev, _req->buf, _req->length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		req->mapped = 1;
+	}
+
+#ifdef USB_TRACE
+	VDBG(dev, "%s queue req %p, len %u buf %p\n",
+			_ep->name, _req, _req->length, _req->buf);
+#endif
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* for ep0 IN without premature status, zlp is required and
+	 * writing EOP starts the status stage (OUT).
+	 */
+	if (unlikely(ep->num == 0 && ep->is_in))
+		_req->zero = 1;
+
+	/* kickstart this i/o queue? */
+	status = 0;
+	if (list_empty(&ep->queue) && likely(!ep->stopped)) {
+		/* dma:  done after dma completion IRQ (or error)
+		 * pio:  done after last fifo operation
+		 */
+		if (ep->dma)
+			status = start_dma(ep, req);
+		else
+			status = (ep->is_in ? write_fifo : read_fifo)(ep, req);
+
+		if (unlikely(status != 0)) {
+			if (status > 0)
+				status = 0;
+			req = 0;
+		}
+
+	} /* else pio or dma irq handler advances the queue. */
+
+	if (likely(req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	if (likely(!list_empty(&ep->queue))
+			&& likely(ep->num != 0)
+			&& !ep->dma
+			&& !(dev->int_enable & INT_EPxDATASET (ep->num)))
+		pio_irq_enable(dev, dev->regs, ep->num);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	/* pci writes may still be posted */
+	return status;
+}
+
+/* dequeue ALL requests */
+static void nuke(struct goku_ep *ep, int status)
+{
+	struct goku_request	*req;
+
+	ep->stopped = 1;
+	if (list_empty(&ep->queue))
+		return;
+	if (ep->dma)
+		abort_dma(ep, status);
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct goku_request, queue);
+		done(ep, req, status);
+	}
+}
+
+/* dequeue JUST ONE request */
+static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct goku_request	*req;
+	struct goku_ep		*ep;
+	struct goku_udc		*dev;
+	unsigned long		flags;
+
+	ep = container_of(_ep, struct goku_ep, ep);
+	if (!_ep || !_req || (!ep->desc && ep->num != 0))
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver)
+		return -ESHUTDOWN;
+
+	/* we can't touch (dma) registers when suspended */
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	VDBG(dev, "%s %s %s %s %p\n", __FUNCTION__, _ep->name,
+		ep->is_in ? "IN" : "OUT",
+		ep->dma ? "dma" : "pio",
+		_req);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore (&dev->lock, flags);
+		return -EINVAL;
+	}
+
+	if (ep->dma && ep->queue.next == &req->queue && !ep->stopped) {
+		abort_dma(ep, -ECONNRESET);
+		done(ep, req, -ECONNRESET);
+		dma_advance(dev, ep);
+	} else if (!list_empty(&req->queue))
+		done(ep, req, -ECONNRESET);
+	else
+		req = 0;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return req ? 0 : -EOPNOTSUPP;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void goku_clear_halt(struct goku_ep *ep)
+{
+	// assert (ep->num !=0)
+	VDBG(ep->dev, "%s clear halt\n", ep->ep.name);
+	command(ep->dev->regs, COMMAND_SETDATA0, ep->num);
+	command(ep->dev->regs, COMMAND_STALL_CLEAR, ep->num);
+	if (ep->stopped) {
+		ep->stopped = 0;
+		if (ep->dma) {
+			struct goku_request	*req;
+
+			if (list_empty(&ep->queue))
+				return;
+			req = list_entry(ep->queue.next, struct goku_request,
+						queue);
+			(void) start_dma(ep, req);
+		} else
+			pio_advance(ep);
+	}
+}
+
+static int goku_set_halt(struct usb_ep *_ep, int value)
+{
+	struct goku_ep	*ep;
+	unsigned long	flags;
+	int		retval = 0;
+
+	if (!_ep)
+		return -ENODEV;
+	ep = container_of (_ep, struct goku_ep, ep);
+
+	if (ep->num == 0) {
+		if (value) {
+			ep->dev->ep0state = EP0_STALL;
+			ep->dev->ep[0].stopped = 1;
+		} else
+			return -EINVAL;
+
+	/* don't change EPxSTATUS_EP_INVALID to READY */
+	} else if (!ep->desc) {
+		DBG(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	if (!list_empty(&ep->queue))
+		retval = -EAGAIN;
+	else if (ep->is_in && value
+			/* data in (either) packet buffer? */
+			&& (ep->dev->regs->DataSet & DATASET_AB(ep->num)))
+		retval = -EAGAIN;
+	else if (!value)
+		goku_clear_halt(ep);
+	else {
+		ep->stopped = 1;
+		VDBG(ep->dev, "%s set halt\n", ep->ep.name);
+		command(ep->dev->regs, COMMAND_STALL, ep->num);
+		readl(ep->reg_status);
+	}
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return retval;
+}
+
+static int goku_fifo_status(struct usb_ep *_ep)
+{
+	struct goku_ep		*ep;
+	struct goku_udc_regs	*regs;
+	u32			size;
+
+	if (!_ep)
+		return -ENODEV;
+	ep = container_of(_ep, struct goku_ep, ep);
+
+	/* size is only reported sanely for OUT */
+	if (ep->is_in)
+		return -EOPNOTSUPP;
+
+	/* ignores 16-byte dma buffer; SizeH == 0 */
+	regs = ep->dev->regs;
+	size = readl(&regs->EPxSizeLA[ep->num]) & DATASIZE;
+	size += readl(&regs->EPxSizeLB[ep->num]) & DATASIZE;
+	VDBG(ep->dev, "%s %s %u\n", __FUNCTION__, ep->ep.name, size);
+	return size;
+}
+
+static void goku_fifo_flush(struct usb_ep *_ep)
+{
+	struct goku_ep		*ep;
+	struct goku_udc_regs	*regs;
+	u32			size;
+
+	if (!_ep)
+		return;
+	ep = container_of(_ep, struct goku_ep, ep);
+	VDBG(ep->dev, "%s %s\n", __FUNCTION__, ep->ep.name);
+
+	/* don't change EPxSTATUS_EP_INVALID to READY */
+	if (!ep->desc && ep->num != 0) {
+		DBG(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
+		return;
+	}
+
+	regs = ep->dev->regs;
+	size = readl(&regs->EPxSizeLA[ep->num]);
+	size &= DATASIZE;
+
+	/* Non-desirable behavior:  FIFO_CLEAR also clears the
+	 * endpoint halt feature.  For OUT, we _could_ just read
+	 * the bytes out (PIO, if !ep->dma); for in, no choice.
+	 */
+	if (size)
+		command(regs, COMMAND_FIFO_CLEAR, ep->num);
+}
+
+static struct usb_ep_ops goku_ep_ops = {
+	.enable		= goku_ep_enable,
+	.disable	= goku_ep_disable,
+
+	.alloc_request	= goku_alloc_request,
+	.free_request	= goku_free_request,
+
+	.alloc_buffer	= goku_alloc_buffer,
+	.free_buffer	= goku_free_buffer,
+
+	.queue		= goku_queue,
+	.dequeue	= goku_dequeue,
+
+	.set_halt	= goku_set_halt,
+	.fifo_status	= goku_fifo_status,
+	.fifo_flush	= goku_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int goku_get_frame(struct usb_gadget *_gadget)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct usb_gadget_ops goku_ops = {
+	.get_frame	= goku_get_frame,
+	// no remote wakeup
+	// not selfpowered
+};
+
+/*-------------------------------------------------------------------------*/
+
+static inline char *dmastr(void)
+{
+	if (use_dma == 0)
+		return "(dma disabled)";
+	else if (use_dma == 2)
+		return "(dma IN and OUT)";
+	else
+		return "(dma IN)";
+}
+
+/* if we're trying to save space, don't bother with this proc file */
+
+#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)
+#  define	UDC_PROC_FILE
+#endif
+
+#ifdef UDC_PROC_FILE
+
+static const char proc_node_name [] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void
+dump_intmask(const char *label, u32 mask, char **next, unsigned *size)
+{
+	int t;
+
+	/* int_status is the same format ... */
+	t = snprintf(*next, *size,
+		"%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",
+		label, mask,
+		(mask & INT_PWRDETECT) ? " power" : "",
+		(mask & INT_SYSERROR) ? " sys" : "",
+		(mask & INT_MSTRDEND) ? " in-dma" : "",
+		(mask & INT_MSTWRTMOUT) ? " wrtmo" : "",
+
+		(mask & INT_MSTWREND) ? " out-dma" : "",
+		(mask & INT_MSTWRSET) ? " wrset" : "",
+		(mask & INT_ERR) ? " err" : "",
+		(mask & INT_SOF) ? " sof" : "",
+
+		(mask & INT_EP3NAK) ? " ep3nak" : "",
+		(mask & INT_EP2NAK) ? " ep2nak" : "",
+		(mask & INT_EP1NAK) ? " ep1nak" : "",
+		(mask & INT_EP3DATASET) ? " ep3" : "",
+
+		(mask & INT_EP2DATASET) ? " ep2" : "",
+		(mask & INT_EP1DATASET) ? " ep1" : "",
+		(mask & INT_STATUSNAK) ? " ep0snak" : "",
+		(mask & INT_STATUS) ? " ep0status" : "",
+
+		(mask & INT_SETUP) ? " setup" : "",
+		(mask & INT_ENDPOINT0) ? " ep0" : "",
+		(mask & INT_USBRESET) ? " reset" : "",
+		(mask & INT_SUSPEND) ? " suspend" : "");
+	*size -= t;
+	*next += t;
+}
+
+
+static int
+udc_proc_read(char *buffer, char **start, off_t off, int count,
+		int *eof, void *_dev)
+{
+	char			*buf = buffer;
+	struct goku_udc		*dev = _dev;
+	struct goku_udc_regs	*regs = dev->regs;
+	char			*next = buf;
+	unsigned		size = count;
+	unsigned long		flags;
+	int			i, t, is_usb_connected;
+	u32			tmp;
+
+	if (off != 0)
+		return 0;
+
+	local_irq_save(flags);
+
+	/* basic device status */
+	tmp = readl(&regs->power_detect);
+	is_usb_connected = tmp & PW_DETECT;
+	t = snprintf(next, size,
+		"%s - %s\n"
+		"%s version: %s %s\n"
+		"Gadget driver: %s\n"
+		"Host %s, %s\n"
+		"\n",
+		pci_name(dev->pdev), driver_desc,
+		driver_name, DRIVER_VERSION, dmastr(),
+		dev->driver ? dev->driver->driver.name : "(none)",
+		is_usb_connected
+			? ((tmp & PW_PULLUP) ? "full speed" : "powered")
+			: "disconnected",
+		({char *tmp;
+		switch(dev->ep0state){
+		case EP0_DISCONNECT:	tmp = "ep0_disconnect"; break;
+		case EP0_IDLE:		tmp = "ep0_idle"; break;
+		case EP0_IN:		tmp = "ep0_in"; break;
+		case EP0_OUT:		tmp = "ep0_out"; break;
+		case EP0_STATUS:	tmp = "ep0_status"; break;
+		case EP0_STALL:		tmp = "ep0_stall"; break;
+		case EP0_SUSPEND:	tmp = "ep0_suspend"; break;
+		default:		tmp = "ep0_?"; break;
+		} tmp; })
+		);
+	size -= t;
+	next += t;
+
+	dump_intmask("int_status", readl(&regs->int_status), &next, &size);
+	dump_intmask("int_enable", readl(&regs->int_enable), &next, &size);
+
+	if (!is_usb_connected || !dev->driver || (tmp & PW_PULLUP) == 0)
+		goto done;
+
+	/* registers for (active) device and ep0 */
+	t = snprintf(next, size, "\nirqs %lu\ndataset %02x "
+			"single.bcs %02x.%02x state %x addr %u\n",
+			dev->irqs, readl(&regs->DataSet),
+			readl(&regs->EPxSingle), readl(&regs->EPxBCS),
+			readl(&regs->UsbState),
+			readl(&regs->address));
+	size -= t;
+	next += t;
+
+	tmp = readl(&regs->dma_master);
+	t = snprintf(next, size,
+		"dma %03X =" EIGHTBITS "%s %s\n", tmp,
+		(tmp & MST_EOPB_DIS) ? " eopb-" : "",
+		(tmp & MST_EOPB_ENA) ? " eopb+" : "",
+		(tmp & MST_TIMEOUT_DIS) ? " tmo-" : "",
+		(tmp & MST_TIMEOUT_ENA) ? " tmo+" : "",
+
+		(tmp & MST_RD_EOPB) ? " eopb" : "",
+		(tmp & MST_RD_RESET) ? " in_reset" : "",
+		(tmp & MST_WR_RESET) ? " out_reset" : "",
+		(tmp & MST_RD_ENA) ? " IN" : "",
+
+		(tmp & MST_WR_ENA) ? " OUT" : "",
+		(tmp & MST_CONNECTION)
+			? "ep1in/ep2out"
+			: "ep1out/ep2in");
+	size -= t;
+	next += t;
+
+	/* dump endpoint queues */
+	for (i = 0; i < 4; i++) {
+		struct goku_ep		*ep = &dev->ep [i];
+		struct goku_request	*req;
+		int			t;
+
+		if (i && !ep->desc)
+			continue;
+
+		tmp = readl(ep->reg_status);
+		t = snprintf(next, size,
+			"%s %s max %u %s, irqs %lu, "
+			"status %02x (%s) " FOURBITS "\n",
+			ep->ep.name,
+			ep->is_in ? "in" : "out",
+			ep->ep.maxpacket,
+			ep->dma ? "dma" : "pio",
+			ep->irqs,
+			tmp, ({ char *s;
+			switch (tmp & EPxSTATUS_EP_MASK) {
+			case EPxSTATUS_EP_READY:
+				s = "ready"; break;
+			case EPxSTATUS_EP_DATAIN:
+				s = "packet"; break;
+			case EPxSTATUS_EP_FULL:
+				s = "full"; break;
+			case EPxSTATUS_EP_TX_ERR:	// host will retry
+				s = "tx_err"; break;
+			case EPxSTATUS_EP_RX_ERR:
+				s = "rx_err"; break;
+			case EPxSTATUS_EP_BUSY:		/* ep0 only */
+				s = "busy"; break;
+			case EPxSTATUS_EP_STALL:
+				s = "stall"; break;
+			case EPxSTATUS_EP_INVALID:	// these "can't happen"
+				s = "invalid"; break;
+			default:
+				s = "?"; break;
+			}; s; }),
+			(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",
+			(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",
+			(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "",
+			(tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : ""
+			);
+		if (t <= 0 || t > size)
+			goto done;
+		size -= t;
+		next += t;
+
+		if (list_empty(&ep->queue)) {
+			t = snprintf(next, size, "\t(nothing queued)\n");
+			if (t <= 0 || t > size)
+				goto done;
+			size -= t;
+			next += t;
+			continue;
+		}
+		list_for_each_entry(req, &ep->queue, queue) {
+			if (ep->dma && req->queue.prev == &ep->queue) {
+				if (i == UDC_MSTRD_ENDPOINT)
+					tmp = readl(&regs->in_dma_current);
+				else
+					tmp = readl(&regs->out_dma_current);
+				tmp -= req->req.dma;
+				tmp++;
+			} else
+				tmp = req->req.actual;
+
+			t = snprintf(next, size,
+				"\treq %p len %u/%u buf %p\n",
+				&req->req, tmp, req->req.length,
+				req->req.buf);
+			if (t <= 0 || t > size)
+				goto done;
+			size -= t;
+			next += t;
+		}
+	}
+
+done:
+	local_irq_restore(flags);
+	*eof = 1;
+	return count - size;
+}
+
+#endif	/* UDC_PROC_FILE */
+
+/*-------------------------------------------------------------------------*/
+
+static void udc_reinit (struct goku_udc *dev)
+{
+	static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };
+	
+	unsigned i;
+
+	INIT_LIST_HEAD (&dev->gadget.ep_list);
+	dev->gadget.ep0 = &dev->ep [0].ep;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	dev->ep0state = EP0_DISCONNECT;
+	dev->irqs = 0;
+
+	for (i = 0; i < 4; i++) {
+		struct goku_ep	*ep = &dev->ep[i];
+
+		ep->num = i;
+		ep->ep.name = names[i];
+		ep->reg_fifo = &dev->regs->ep_fifo [i];
+		ep->reg_status = &dev->regs->ep_status [i];
+		ep->reg_mode = &dev->regs->ep_mode[i];
+
+		ep->ep.ops = &goku_ep_ops;
+		list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+		ep->dev = dev;
+		INIT_LIST_HEAD (&ep->queue);
+
+		ep_reset(0, ep);
+	}
+
+	dev->ep[0].reg_mode = 0;
+	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
+	list_del_init (&dev->ep[0].ep.ep_list);
+}
+
+static void udc_reset(struct goku_udc *dev)
+{
+	struct goku_udc_regs	*regs = dev->regs;
+
+	writel(0, &regs->power_detect);
+	writel(0, &regs->int_enable);
+	readl(&regs->int_enable);
+	dev->int_enable = 0;
+
+	/* deassert reset, leave USB D+ at hi-Z (no pullup)
+	 * don't let INT_PWRDETECT sequence begin
+	 */
+	udelay(250);
+	writel(PW_RESETB, &regs->power_detect);
+	readl(&regs->int_enable);
+}
+
+static void ep0_start(struct goku_udc *dev)
+{
+	struct goku_udc_regs	*regs = dev->regs;
+	unsigned		i;
+
+	VDBG(dev, "%s\n", __FUNCTION__);
+
+	udc_reset(dev);
+	udc_reinit (dev);
+	//writel(MST_EOPB_ENA | MST_TIMEOUT_ENA, &regs->dma_master);
+
+	/* hw handles set_address, set_feature, get_status; maybe more */
+	writel(   G_REQMODE_SET_INTF | G_REQMODE_GET_INTF
+		| G_REQMODE_SET_CONF | G_REQMODE_GET_CONF
+		| G_REQMODE_GET_DESC
+		| G_REQMODE_CLEAR_FEAT
+		, &regs->reqmode);
+
+	for (i = 0; i < 4; i++)
+		dev->ep[i].irqs = 0;
+
+	/* can't modify descriptors after writing UsbReady */
+	for (i = 0; i < DESC_LEN; i++)
+		writel(0, &regs->descriptors[i]);
+	writel(0, &regs->UsbReady);
+
+	/* expect ep0 requests when the host drops reset */
+	writel(PW_RESETB | PW_PULLUP, &regs->power_detect);
+	dev->int_enable = INT_DEVWIDE | INT_EP0;
+	writel(dev->int_enable, &dev->regs->int_enable);
+	readl(&regs->int_enable);
+	dev->gadget.speed = USB_SPEED_FULL;
+	dev->ep0state = EP0_IDLE;
+}
+
+static void udc_enable(struct goku_udc *dev)
+{
+	/* start enumeration now, or after power detect irq */
+	if (readl(&dev->regs->power_detect) & PW_DETECT)
+		ep0_start(dev);
+	else {
+		DBG(dev, "%s\n", __FUNCTION__);
+		dev->int_enable = INT_PWRDETECT;
+		writel(dev->int_enable, &dev->regs->int_enable);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* keeping it simple:
+ * - one bus driver, initted first;
+ * - one function driver, initted second
+ */
+
+static struct goku_udc	*the_controller;
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * disconnect is reported.  then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct goku_udc	*dev = the_controller;
+	int			retval;
+
+	if (!driver
+			|| driver->speed != USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->unbind
+			|| !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	/* hook up the driver */
+	dev->driver = driver;
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		DBG(dev, "bind to driver %s --> error %d\n",
+				driver->driver.name, retval);
+		dev->driver = 0;
+		return retval;
+	}
+
+	/* then enable host detection and ep0; and we're ready
+	 * for set_configuration as well as eventual disconnect.
+	 */
+	udc_enable(dev);
+
+	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void
+stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
+{
+	unsigned	i;
+
+	DBG (dev, "%s\n", __FUNCTION__);
+
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = 0;
+
+	/* disconnect gadget driver after quiesceing hw and the driver */
+	udc_reset (dev);
+	for (i = 0; i < 4; i++)
+		nuke(&dev->ep [i], -ESHUTDOWN);
+	if (driver) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+
+	if (dev->driver)
+		udc_enable(dev);
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct goku_udc	*dev = the_controller;
+	unsigned long	flags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->driver = 0;
+	stop_activity(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+
+	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+static void ep0_setup(struct goku_udc *dev)
+{
+	struct goku_udc_regs	*regs = dev->regs;
+	struct usb_ctrlrequest	ctrl;
+	int			tmp;
+
+	/* read SETUP packet and enter DATA stage */
+	ctrl.bRequestType = readl(&regs->bRequestType);
+	ctrl.bRequest = readl(&regs->bRequest);
+	ctrl.wValue  = (readl(&regs->wValueH)  << 8) | readl(&regs->wValueL);
+	ctrl.wIndex  = (readl(&regs->wIndexH)  << 8) | readl(&regs->wIndexL);
+	ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
+	writel(0, &regs->SetupRecv);
+
+	nuke(&dev->ep[0], 0);
+	dev->ep[0].stopped = 0;
+	if (likely(ctrl.bRequestType & USB_DIR_IN)) {
+		dev->ep[0].is_in = 1;
+		dev->ep0state = EP0_IN;
+		/* detect early status stages */
+		writel(ICONTROL_STATUSNAK, &dev->regs->IntControl);
+	} else {
+		dev->ep[0].is_in = 0;
+		dev->ep0state = EP0_OUT;
+
+		/* NOTE:  CLEAR_FEATURE is done in software so that we can
+		 * synchronize transfer restarts after bulk IN stalls.  data
+		 * won't even enter the fifo until the halt is cleared.
+		 */
+		switch (ctrl.bRequest) {
+		case USB_REQ_CLEAR_FEATURE:
+			switch (ctrl.bRequestType) {
+			case USB_RECIP_ENDPOINT:
+				tmp = ctrl.wIndex & 0x0f;
+				/* active endpoint */
+				if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
+					goto stall;
+				if (ctrl.wIndex & USB_DIR_IN) {
+					if (!dev->ep[tmp].is_in)
+						goto stall;
+				} else {
+					if (dev->ep[tmp].is_in)
+						goto stall;
+				}
+				/* endpoint halt */
+				if (ctrl.wValue != 0)
+					goto stall;
+				if (tmp)
+					goku_clear_halt(&dev->ep[tmp]);
+succeed:
+				/* start ep0out status stage */
+				writel(~(1<<0), &regs->EOP);
+				dev->ep[0].stopped = 1;
+				dev->ep0state = EP0_STATUS;
+				return;
+			case USB_RECIP_DEVICE:
+				/* device remote wakeup: always clear */
+				if (ctrl.wValue != 1)
+					goto stall;
+				VDBG(dev, "clear dev remote wakeup\n");
+				goto succeed;
+			case USB_RECIP_INTERFACE:
+				goto stall;
+			default:		/* pass to gadget driver */
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+#ifdef USB_TRACE
+	VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+		ctrl.bRequestType, ctrl.bRequest,
+		ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+#endif
+
+	/* hw wants to know when we're configured (or not) */
+	dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
+				&& ctrl.bRequestType == USB_RECIP_DEVICE);
+	if (unlikely(dev->req_config))
+		dev->configured = (ctrl.wValue != 0);
+
+	/* delegate everything to the gadget driver.
+	 * it may respond after this irq handler returns.
+	 */
+	spin_unlock (&dev->lock);
+	tmp = dev->driver->setup(&dev->gadget, &ctrl);
+	spin_lock (&dev->lock);
+	if (unlikely(tmp < 0)) {
+stall:
+#ifdef USB_TRACE
+		VDBG(dev, "req %02x.%02x protocol STALL; err %d\n",
+				ctrl.bRequestType, ctrl.bRequest, tmp);
+#endif
+		command(regs, COMMAND_STALL, 0);
+		dev->ep[0].stopped = 1;
+		dev->ep0state = EP0_STALL;
+	}
+
+	/* expect at least one data or status stage irq */
+}
+
+#define ACK(irqbit) { \
+		stat &= ~irqbit; \
+		writel(~irqbit, &regs->int_status); \
+		handled = 1; \
+		}
+
+static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r)
+{
+	struct goku_udc		*dev = _dev;
+	struct goku_udc_regs	*regs = dev->regs;
+	struct goku_ep		*ep;
+	u32			stat, handled = 0;
+	unsigned		i, rescans = 5;
+
+	spin_lock(&dev->lock);
+
+rescan:
+	stat = readl(&regs->int_status) & dev->int_enable;
+        if (!stat)
+		goto done;
+	dev->irqs++;
+
+	/* device-wide irqs */
+	if (unlikely(stat & INT_DEVWIDE)) {
+		if (stat & INT_SYSERROR) {
+			ERROR(dev, "system error\n");
+			stop_activity(dev, dev->driver);
+			stat = 0;
+			handled = 1;
+			// FIXME have a neater way to prevent re-enumeration
+			dev->driver = 0;
+			goto done;
+		}
+		if (stat & INT_PWRDETECT) {
+			writel(~stat, &regs->int_status);
+			if (readl(&dev->regs->power_detect) & PW_DETECT) {
+				VDBG(dev, "connect\n");
+				ep0_start(dev);
+			} else {
+				DBG(dev, "disconnect\n");
+				if (dev->gadget.speed == USB_SPEED_FULL)
+					stop_activity(dev, dev->driver);
+				dev->ep0state = EP0_DISCONNECT;
+				dev->int_enable = INT_DEVWIDE;
+				writel(dev->int_enable, &dev->regs->int_enable);
+			}
+			stat = 0;
+			handled = 1;
+			goto done;
+		}
+		if (stat & INT_SUSPEND) {
+			ACK(INT_SUSPEND);
+			if (readl(&regs->ep_status[0]) & EPxSTATUS_SUSPEND) {
+				switch (dev->ep0state) {
+				case EP0_DISCONNECT:
+				case EP0_SUSPEND:
+					goto pm_next;
+				default:
+					break;
+				}
+				DBG(dev, "USB suspend\n");
+				dev->ep0state = EP0_SUSPEND;
+				if (dev->gadget.speed != USB_SPEED_UNKNOWN
+						&& dev->driver
+						&& dev->driver->suspend) {
+					spin_unlock(&dev->lock);
+					dev->driver->suspend(&dev->gadget);
+					spin_lock(&dev->lock);
+				}
+			} else {
+				if (dev->ep0state != EP0_SUSPEND) {
+					DBG(dev, "bogus USB resume %d\n",
+						dev->ep0state);
+					goto pm_next;
+				}
+				DBG(dev, "USB resume\n");
+				dev->ep0state = EP0_IDLE;
+				if (dev->gadget.speed != USB_SPEED_UNKNOWN
+						&& dev->driver
+						&& dev->driver->resume) {
+					spin_unlock(&dev->lock);
+					dev->driver->resume(&dev->gadget);
+					spin_lock(&dev->lock);
+				}
+			}
+		}
+pm_next:
+		if (stat & INT_USBRESET) {		/* hub reset done */
+			ACK(INT_USBRESET);
+			INFO(dev, "USB reset done, gadget %s\n",
+				dev->driver->driver.name);
+		}
+		// and INT_ERR on some endpoint's crc/bitstuff/... problem
+	}
+
+	/* progress ep0 setup, data, or status stages.
+	 * no transition {EP0_STATUS, EP0_STALL} --> EP0_IDLE; saves irqs
+	 */
+	if (stat & INT_SETUP) {
+		ACK(INT_SETUP);
+		dev->ep[0].irqs++;
+		ep0_setup(dev);
+	}
+        if (stat & INT_STATUSNAK) {
+		ACK(INT_STATUSNAK|INT_ENDPOINT0);
+		if (dev->ep0state == EP0_IN) {
+			ep = &dev->ep[0];
+			ep->irqs++;
+			nuke(ep, 0);
+			writel(~(1<<0), &regs->EOP);
+			dev->ep0state = EP0_STATUS;
+		}
+	}
+        if (stat & INT_ENDPOINT0) {
+		ACK(INT_ENDPOINT0);
+		ep = &dev->ep[0];
+		ep->irqs++;
+		pio_advance(ep);
+        }
+
+	/* dma completion */
+        if (stat & INT_MSTRDEND) {	/* IN */
+		ACK(INT_MSTRDEND);
+		ep = &dev->ep[UDC_MSTRD_ENDPOINT];
+		ep->irqs++;
+		dma_advance(dev, ep);
+        }
+        if (stat & INT_MSTWREND) {	/* OUT */
+		ACK(INT_MSTWREND);
+		ep = &dev->ep[UDC_MSTWR_ENDPOINT];
+		ep->irqs++;
+		dma_advance(dev, ep);
+        }
+        if (stat & INT_MSTWRTMOUT) {	/* OUT */
+		ACK(INT_MSTWRTMOUT);
+		ep = &dev->ep[UDC_MSTWR_ENDPOINT];
+		ep->irqs++;
+		ERROR(dev, "%s write timeout ?\n", ep->ep.name);
+		// reset dma? then dma_advance()
+        }
+
+	/* pio */
+	for (i = 1; i < 4; i++) {
+		u32		tmp = INT_EPxDATASET(i);
+
+		if (!(stat & tmp))
+			continue;
+		ep = &dev->ep[i];
+		pio_advance(ep);
+		if (list_empty (&ep->queue))
+			pio_irq_disable(dev, regs, i);
+		stat &= ~tmp;
+		handled = 1;
+		ep->irqs++;
+	}
+
+	if (rescans--)
+		goto rescan;
+
+done:
+	(void)readl(&regs->int_enable);
+	spin_unlock(&dev->lock);
+	if (stat)
+		DBG(dev, "unhandled irq status: %05x (%05x, %05x)\n", stat,
+				readl(&regs->int_status), dev->int_enable);
+	return IRQ_RETVAL(handled);
+}
+
+#undef ACK
+
+/*-------------------------------------------------------------------------*/
+
+/* tear down the binding between this driver and the pci device */
+
+static void goku_remove(struct pci_dev *pdev)
+{
+	struct goku_udc		*dev = pci_get_drvdata(pdev);
+
+	DBG(dev, "%s\n", __FUNCTION__);
+	/* start with the driver above us */
+	if (dev->driver) {
+		/* should have been done already by driver model core */
+		WARN(dev, "pci remove, driver '%s' is still registered\n",
+				dev->driver->driver.name);
+		usb_gadget_unregister_driver(dev->driver);
+	}
+
+#ifdef	UDC_PROC_FILE
+	remove_proc_entry(proc_node_name, NULL);
+#endif
+	if (dev->regs)
+		udc_reset(dev);
+	if (dev->got_irq)
+		free_irq(pdev->irq, dev);
+	if (dev->regs)
+		iounmap(dev->regs);
+	if (dev->got_region)
+		release_mem_region(pci_resource_start (pdev, 0),
+				pci_resource_len (pdev, 0));
+	if (dev->enabled)
+		pci_disable_device(pdev);
+
+	pci_set_drvdata(pdev, 0);
+	dev->regs = 0;
+	the_controller = 0;
+
+	INFO(dev, "unbind\n");
+}
+
+/* wrap this driver around the specified pci device, but
+ * don't respond over USB until a gadget driver binds to us.
+ */
+
+static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct goku_udc		*dev = 0;
+	unsigned long		resource, len;
+	void			*base = 0;
+	int			retval;
+	char			buf [8], *bufp;
+
+	/* if you want to support more than one controller in a system,
+	 * usb_gadget_driver_{register,unregister}() must change.
+	 */
+	if (the_controller) {
+		WARN(dev, "ignoring %s\n", pci_name(pdev));
+		return -EBUSY;
+	}
+	if (!pdev->irq) {
+		printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
+		retval = -ENODEV;
+		goto done;
+	}
+
+	/* alloc, and start init */
+	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	if (dev == NULL){
+		pr_debug("enomem %s\n", pci_name(pdev));
+		retval = -ENOMEM;
+		goto done;
+	}
+
+	memset(dev, 0, sizeof *dev);
+	spin_lock_init(&dev->lock);
+	dev->pdev = pdev;
+	dev->gadget.ops = &goku_ops;
+
+	/* the "gadget" abstracts/virtualizes the controller */
+	dev->gadget.dev.bus_id = "gadget";
+	dev->gadget.name = driver_name;
+
+	/* now all the pci goodies ... */
+	retval = pci_enable_device(pdev);
+	if (retval < 0) {
+		DBG(dev, "can't enable, %d\n", retval);
+		goto done;
+	}
+	dev->enabled = 1;
+
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+	if (!request_mem_region(resource, len, driver_name)) {
+		DBG(dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->got_region = 1;
+
+	base = ioremap_nocache(resource, len);
+	if (base == NULL) {
+		DBG(dev, "can't map memory\n");
+		retval = -EFAULT;
+		goto done;
+	}
+	dev->regs = (struct goku_udc_regs *) base;
+
+	pci_set_drvdata(pdev, dev);
+	INFO(dev, "%s\n", driver_desc);
+	INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr());
+#ifndef __sparc__
+	snprintf(buf, sizeof buf, "%d", pdev->irq);
+	bufp = buf;
+#else
+	bufp = __irq_itoa(pdev->irq);
+#endif
+	INFO(dev, "irq %s, pci mem %p\n", bufp, base);
+
+	/* init to known state, then setup irqs */
+	udc_reset(dev);
+	udc_reinit (dev);
+	if (request_irq(pdev->irq, goku_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/,
+			driver_name, dev) != 0) {
+		DBG(dev, "request interrupt %s failed\n", bufp);
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->got_irq = 1;
+	if (use_dma)
+		pci_set_master(pdev);
+
+
+#ifdef	UDC_PROC_FILE
+	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
+#endif
+
+	/* done */
+	the_controller = dev;
+
+	return 0;
+
+done:
+	if (dev)
+		goku_remove (pdev);
+	return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct pci_device_id pci_ids [] = { {
+	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask = 	~0,
+	.vendor =	0x102f,		/* Toshiba */
+	.device =	0x0107,		/* this UDC */
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+static struct pci_driver goku_pci_driver = {
+	.name =		(char *) driver_name,
+	.id_table =	pci_ids,
+
+	.probe =	goku_probe,
+	.remove =	goku_remove,
+
+	/* FIXME add power management support */
+};
+
+static int __init init (void)
+{
+	return pci_module_init (&goku_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+	pci_unregister_driver (&goku_pci_driver);
+}
+module_exit (cleanup);
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/goku_udc.h linux-2.4.25-pre8/drivers/usb/gadget/goku_udc.h
--- linux-2.4.25-pre7/drivers/usb/gadget/goku_udc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/goku_udc.h	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,321 @@
+/*
+ * Toshiba TC86C001 ("Goku-S") USB Device Controller driver
+ *
+ * Copyright (C) 2000-2002 Lineo
+ *      by Stuart Lynne, Tom Rushworth, and Bruce Balden
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2003 MontaVista Software (source@mvista.com)
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * PCI BAR 0 points to these registers.
+ */
+struct goku_udc_regs {
+	/* irq management */
+	u32	int_status;		/* 0x000 */
+	u32	int_enable;
+#define INT_SUSPEND		0x00001		/* or resume */
+#define INT_USBRESET		0x00002
+#define INT_ENDPOINT0		0x00004
+#define INT_SETUP		0x00008
+#define INT_STATUS		0x00010
+#define INT_STATUSNAK		0x00020
+#define INT_EPxDATASET(n)	(0x00020 << (n))	/* 0 < n < 4 */
+#	define INT_EP1DATASET		0x00040
+#	define INT_EP2DATASET		0x00080
+#	define INT_EP3DATASET		0x00100
+#define INT_EPnNAK(n)		(0x00100 < (n))		/* 0 < n < 4 */
+#	define INT_EP1NAK		0x00200
+#	define INT_EP2NAK		0x00400
+#	define INT_EP3NAK		0x00800
+#define INT_SOF			0x01000
+#define INT_ERR			0x02000
+#define INT_MSTWRSET		0x04000
+#define INT_MSTWREND		0x08000
+#define INT_MSTWRTMOUT		0x10000
+#define INT_MSTRDEND		0x20000
+#define INT_SYSERROR		0x40000
+#define INT_PWRDETECT		0x80000
+
+#define	INT_DEVWIDE		(INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
+#define	INT_EP0 		(INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
+
+	u32	dma_master;
+#define MST_EOPB_DIS		0x0800
+#define MST_EOPB_ENA		0x0400
+#define MST_TIMEOUT_DIS		0x0200
+#define MST_TIMEOUT_ENA		0x0100
+#define MST_RD_EOPB		0x0080		/* write-only */
+#define MST_RD_RESET		0x0040
+#define MST_WR_RESET		0x0020
+#define MST_RD_ENA		0x0004		/* 1:start, 0:ignore */
+#define MST_WR_ENA		0x0002		/* 1:start, 0:ignore */
+#define MST_CONNECTION		0x0001		/* 0 for ep1out/ep2in */
+
+#define MST_R_BITS		(MST_EOPB_DIS|MST_EOPB_ENA \
+					|MST_RD_ENA|MST_RD_RESET)
+#define MST_W_BITS		(MST_TIMEOUT_DIS|MST_TIMEOUT_ENA \
+					|MST_WR_ENA|MST_WR_RESET)
+#define MST_RW_BITS		(MST_R_BITS|MST_W_BITS \
+					|MST_CONNECTION)
+
+/* these values assume (dma_master & MST_CONNECTION) == 0 */
+#define UDC_MSTWR_ENDPOINT        1
+#define UDC_MSTRD_ENDPOINT        2
+
+	/* dma master write */
+	u32	out_dma_start;
+	u32	out_dma_end;
+	u32	out_dma_current;
+
+	/* dma master read */
+	u32	in_dma_start;
+	u32	in_dma_end;
+	u32	in_dma_current;
+
+	u32	power_detect;
+#define PW_DETECT		0x04
+#define PW_RESETB		0x02
+#define PW_PULLUP		0x01
+
+	u8	_reserved0 [0x1d8];
+
+	/* endpoint registers */
+	u32	ep_fifo [4];		/* 0x200 */
+	u8	_reserved1 [0x10];
+	u32	ep_mode [4];		/* only 1-3 valid */
+	u8	_reserved2 [0x10];
+
+	u32	ep_status [4];
+#define EPxSTATUS_TOGGLE	0x40
+#define EPxSTATUS_SUSPEND	0x20
+#define EPxSTATUS_EP_MASK	(0x07<<2)
+#	define EPxSTATUS_EP_READY	(0<<2)
+#	define EPxSTATUS_EP_DATAIN	(1<<2)
+#	define EPxSTATUS_EP_FULL	(2<<2)
+#	define EPxSTATUS_EP_TX_ERR	(3<<2)
+#	define EPxSTATUS_EP_RX_ERR	(4<<2)
+#	define EPxSTATUS_EP_BUSY	(5<<2)
+#	define EPxSTATUS_EP_STALL	(6<<2)
+#	define EPxSTATUS_EP_INVALID	(7<<2)
+#define EPxSTATUS_FIFO_DISABLE	0x02
+#define EPxSTATUS_STAGE_ERROR	0x01
+
+	u8	_reserved3 [0x10];
+	u32	EPxSizeLA[4];
+#define PACKET_ACTIVE		(1<<7)
+#define DATASIZE		0x7f
+	u8	_reserved3a [0x10];
+	u32	EPxSizeLB[4];		/* only 1,2 valid */
+	u8	_reserved3b [0x10];
+	u32	EPxSizeHA[4];		/* only 1-3 valid */
+	u8	_reserved3c [0x10];
+	u32	EPxSizeHB[4];		/* only 1,2 valid */
+	u8	_reserved4[0x30];
+
+	/* SETUP packet contents */
+	u32	bRequestType;		/* 0x300 */
+	u32	bRequest;
+	u32	wValueL;
+	u32	wValueH;
+	u32	wIndexL;
+	u32	wIndexH;
+	u32	wLengthL;
+	u32	wLengthH;
+
+	/* command interaction/handshaking */
+	u32	SetupRecv;		/* 0x320 */
+	u32	CurrConfig;
+	u32	StdRequest;
+	u32	Request;
+	u32	DataSet;
+#define DATASET_A(epnum)	(1<<(2*(epnum)))
+#define DATASET_B(epnum)	(2<<(2*(epnum)))
+#define DATASET_AB(epnum)	(3<<(2*(epnum)))
+	u8	_reserved5[4];
+
+	u32	UsbState;
+#define USBSTATE_CONFIGURED	0x04
+#define USBSTATE_ADDRESSED	0x02
+#define USBSTATE_DEFAULT	0x01
+
+	u32	EOP;
+
+	u32	Command;		/* 0x340 */
+#define COMMAND_SETDATA0	2
+#define COMMAND_RESET		3
+#define COMMAND_STALL		4
+#define COMMAND_INVALID		5
+#define COMMAND_FIFO_DISABLE	7
+#define COMMAND_FIFO_ENABLE	8
+#define COMMAND_INIT_DESCRIPTOR	9
+#define COMMAND_FIFO_CLEAR	10	/* also stall */
+#define COMMAND_STALL_CLEAR	11
+#define COMMAND_EP(n)		((n) << 4)
+
+	u32	EPxSingle;
+	u8	_reserved6[4];
+	u32	EPxBCS;
+	u8	_reserved7[8];
+	u32	IntControl;
+#define ICONTROL_STATUSNAK	1
+	u8	_reserved8[4];
+
+	u32	reqmode;	// 0x360 standard request mode, low 8 bits
+#define G_REQMODE_SET_INTF	(1<<7)
+#define G_REQMODE_GET_INTF	(1<<6)
+#define G_REQMODE_SET_CONF	(1<<5)
+#define G_REQMODE_GET_CONF	(1<<4)
+#define G_REQMODE_GET_DESC	(1<<3)
+#define G_REQMODE_SET_FEAT	(1<<2)
+#define G_REQMODE_CLEAR_FEAT	(1<<1)
+#define G_REQMODE_GET_STATUS	(1<<0)
+
+	u32	ReqMode;
+	u8	_reserved9[0x18];
+	u32	PortStatus;		/* 0x380 */
+	u8	_reserved10[8];
+	u32	address;
+	u32	buff_test;
+	u8	_reserved11[4];
+	u32	UsbReady;
+	u8	_reserved12[4];
+	u32	SetDescStall;		/* 0x3a0 */
+	u8	_reserved13[0x45c];
+
+	/* hardware could handle limited GET_DESCRIPTOR duties */
+#define	DESC_LEN	0x80
+	u32	descriptors[DESC_LEN];	/* 0x800 */
+	u8	_reserved14[0x600];
+
+} __attribute__ ((packed));
+
+#define	MAX_FIFO_SIZE	64
+#define	MAX_EP0_SIZE	8		/* ep0 fifo is bigger, though */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+
+struct goku_ep {
+	struct usb_ep				ep;
+	struct goku_udc				*dev;
+	unsigned long				irqs;
+
+	unsigned				num:8,
+						dma:1,
+						is_in:1,
+						stopped:1;
+
+	/* analogous to a host-side qh */
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+
+	u32					*reg_fifo;
+	u32					*reg_mode;
+	u32					*reg_status;
+};
+
+struct goku_request {
+	struct usb_request		req;
+	struct list_head		queue;
+
+	unsigned			mapped:1;
+};
+
+enum ep0state {
+	EP0_DISCONNECT,		/* no host */
+	EP0_IDLE,		/* between STATUS ack and SETUP report */
+	EP0_IN, EP0_OUT, 	/* data stage */
+	EP0_STATUS,		/* status stage */
+	EP0_STALL,		/* data or status stages */
+	EP0_SUSPEND,		/* usb suspend */
+};
+
+struct goku_udc {
+	/* each pci device provides one gadget, several endpoints */
+	struct usb_gadget		gadget;
+	spinlock_t			lock;
+	struct goku_ep			ep[4];
+	struct usb_gadget_driver 	*driver;
+
+	enum ep0state			ep0state;
+	unsigned			got_irq:1,
+					got_region:1,
+					req_config:1,
+					configured:1,
+					enabled:1;
+
+	/* pci state used to access those endpoints */
+	struct pci_dev			*pdev;
+	struct goku_udc_regs		*regs;
+	u32				int_enable;
+
+	/* statistics... */
+	unsigned long			irqs;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(dev,level,fmt,args...) \
+	printk(level "%s %s: " fmt , driver_name , \
+			pci_name(dev->pdev) , ## args)
+
+#ifdef DEBUG
+#define DBG(dev,fmt,args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(dev,fmt,args...) \
+	do { } while (0)
+#endif	/* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+	xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* 2.5 stuff that's sometimes missing in 2.4 */
+
+#ifndef container_of
+#define	container_of	list_entry
+#endif
+
+#ifndef likely
+#define likely(x)	(x)
+#define unlikely(x)	(x)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef WARN_ON
+#define	WARN_ON(x)	do { } while (0)
+#endif
+
+#ifndef	IRQ_NONE
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+#endif
+
+#ifndef pci_name
+#define pci_name(pdev)	((pdev)->slot_name)
+#endif
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/net2280.c linux-2.4.25-pre8/drivers/usb/gadget/net2280.c
--- linux-2.4.25-pre7/drivers/usb/gadget/net2280.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/net2280.c	2004-01-29 10:58:21.000000000 -0800
@@ -25,9 +25,6 @@
  * rev1 chips.  Rev1a silicon (0110) fixes almost all of them.
  */
 
-#define USE_DMA_CHAINING
-
-
 /*
  * Copyright (C) 2003 David Brownell
  * Copyright (C) 2003 NetChip Technologies
@@ -47,14 +44,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define DEBUG	1
-// #define	VERBOSE		/* extra debug messages (success too) */
+#undef	DEBUG		/* messages on error and most fault paths */
+#undef	VERBOSE		/* extra debug messages (success too) */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
@@ -77,7 +73,7 @@
 
 
 #define	DRIVER_DESC		"NetChip 2280 USB Peripheral Controller"
-#define	DRIVER_VERSION		"Bastille Day 2003"
+#define	DRIVER_VERSION		"2004 Jan 14"
 
 #define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
 #define	EP_DONTUSE		13	/* nonzero */
@@ -95,7 +91,23 @@
 	"ep-e", "ep-f",
 };
 
+/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
+ * use_dma_chaining -- dma descriptor queueing gives even more irq reduction
+ *
+ * The net2280 DMA engines are not tightly integrated with their FIFOs;
+ * not all cases are (yet) handled well in this driver or the silicon.
+ * Some gadget drivers work better with the dma support here than others.
+ * These two parameters let you use PIO or more aggressive DMA.
+ */
 static int use_dma = 1;
+static int use_dma_chaining = 0;
+
+MODULE_PARM (use_dma, "i");
+MODULE_PARM_DESC (use_dma, "true to use dma controllers");
+
+MODULE_PARM (use_dma_chaining, "i");
+MODULE_PARM_DESC (use_dma_chaining, "true to use dma descriptor queues");
+
 
 /* mode 0 == ep-{a,b,c,d} 1K fifo each
  * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
@@ -103,9 +115,6 @@
  */
 static ushort fifo_mode = 0;
 
-MODULE_PARM (use_dma, "i");
-MODULE_PARM_DESC (use_dma, "true to use dma controllers");
-
 MODULE_PARM (fifo_mode, "h");
 MODULE_PARM_DESC (fifo_mode, "net2280 fifo mode");
 
@@ -162,6 +171,7 @@
 
 	/* ep_reset() has already been called */
 	ep->stopped = 0;
+	ep->out_overflow = 0;
 
 	/* set speed-dependent max packet; may kick in high bandwidth */
 	set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max);
@@ -169,8 +179,8 @@
 	/* FIFO lines can't go to different packets.  PIO is ok, so
 	 * use it instead of troublesome (non-bulk) multi-packet DMA.
 	 */
-	if (ep->is_in && ep->dma && (max % 4) != 0) {
-		DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n",
+	if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
+		DEBUG (ep->dev, "%s, no dma for maxpacket %d\n",
 			ep->ep.name, ep->ep.maxpacket);
 		ep->dma = 0;
 	}
@@ -179,17 +189,21 @@
 	writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
 	tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
 	if (tmp == USB_ENDPOINT_XFER_INT) {
-		/* not just because of erratum 0105; avoid ever
-		 * kicking in the "toggle-irrelevant" mode.
-		 */
-		tmp = USB_ENDPOINT_XFER_BULK;
+		/* erratum 0105 workaround prevents hs NYET */
+		if (dev->chiprev == 0100
+				&& dev->gadget.speed == USB_SPEED_HIGH
+				&& !(desc->bEndpointAddress & USB_DIR_IN))
+			writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE),
+				&ep->regs->ep_rsp);
 	} else if (tmp == USB_ENDPOINT_XFER_BULK) {
 		/* catch some particularly blatant driver bugs */
 		if ((dev->gadget.speed == USB_SPEED_HIGH
 					&& max != 512)
 				|| (dev->gadget.speed == USB_SPEED_FULL
-					&& max > 64))
+					&& max > 64)) {
+			spin_unlock_irqrestore (&dev->lock, flags);
 			return -ERANGE;
+		}
 	}
 	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
 	tmp <<= ENDPOINT_TYPE;
@@ -205,11 +219,6 @@
 
 	writel (tmp, &ep->regs->ep_cfg);
 
-#ifdef NET2280_DMA_OUT_WORKAROUND
-	if (!ep->is_in)
-		ep->dma = 0;
-#endif
-
 	/* enable irqs */
 	if (!ep->dma) {				/* pio, per-packet */
 		tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
@@ -388,6 +397,7 @@
 		}
 		td->dmacount = 0;	/* not VALID */
 		td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+		td->dmadesc = td->dmaaddr;
 		req->td = td;
 	}
 	return &req->req;
@@ -430,6 +440,9 @@
 #elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #define USE_KMALLOC
 
+#elif	defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+
 /* FIXME there are other cases, including an x86-64 one ...  */
 #endif
 
@@ -451,31 +464,23 @@
 	ep = container_of (_ep, struct net2280_ep, ep);
 	if (!_ep)
 		return 0;
-
 	*dma = DMA_ADDR_INVALID;
-	if (ep->dma) {
+
 #if	defined(USE_KMALLOC)
-		retval = kmalloc (bytes, gfp_flags);
-		if (retval)
-			*dma = virt_to_phys (retval);
-
-#elif	LINUX_VERSION_CODE > KERNEL_VERSION(2,5,58)
-#warning Using dma_alloc_consistent even with sub-page allocations
-		/* the main problem with this call is that it wastes memory
-		 * on typical 1/N page allocations: it allocates 1-N pages.
-		 */
-		retval = dma_alloc_coherent (&ep->dev->pdev->dev,
-				bytes, dma, gfp_flags);
+	retval = kmalloc(bytes, gfp_flags);
+	if (retval)
+		*dma = virt_to_phys(retval);
 #else
-#error No dma-coherent memory allocator is available
-		/* pci_alloc_consistent works, but pci_free_consistent()
-		 * isn't safe in_interrupt().  plus, in addition to the
-		 * 1/Nth page weakness, it doesn't understand gfp_flags.
+	if (ep->dma) {
+		/* one problem with this call is that it wastes memory on
+		 * typical 1/N page allocations: it allocates 1..N pages.
+		 * another is that it always uses GFP_ATOMIC.
 		 */
-#endif
+#warning Using pci_alloc_consistent even with buffers smaller than a page.
+		retval = pci_alloc_consistent(ep->dev->pdev, bytes, dma);
 	} else
-		retval = kmalloc (bytes, gfp_flags);
-
+		retval = kmalloc(bytes, gfp_flags);
+#endif
 	return retval;
 }
 
@@ -488,9 +493,17 @@
 ) {
 	/* free memory into the right allocator */
 #ifndef	USE_KMALLOC
-	if (dma != DMA_ADDR_INVALID)
-		dma_free_coherent (ep->dev->pdev, bytes, dma);
-	else
+	if (dma != DMA_ADDR_INVALID) {
+		struct net2280_ep	*ep;
+
+		ep = container_of(_ep, struct net2280_ep, ep);
+		if (!_ep)
+			return;
+		/* one problem with this call is that some platforms
+		 * don't allow it to be used in_irq().
+		 */
+		pci_free_consistent(ep->dev->pdev, bytes, buf, dma);
+	} else
 #endif
 		kfree (buf);
 }
@@ -541,8 +554,11 @@
 		count -= 4;
 	}
 
-	/* last fifo entry is "short" unless we wrote a full packet */
-	if (total < ep->ep.maxpacket) {
+	/* last fifo entry is "short" unless we wrote a full packet.
+	 * also explicitly validate last word in (periodic) transfers
+	 * when maxpacket is not a multiple of 4 bytes.
+	 */
+	if (count || total < ep->ep.maxpacket) {
 		tmp = count ? get_unaligned ((u32 *)buf) : count;
 		cpu_to_le32s (&tmp);
 		set_fifo_bytecount (ep, count & 0x03);
@@ -555,6 +571,9 @@
 /* work around erratum 0106: PCI and USB race over the OUT fifo.
  * caller guarantees chiprev 0100, out endpoint is NAKing, and
  * there's no real data in the fifo.
+ *
+ * NOTE:  also used in cases where that erratum doesn't apply:
+ * where the host wrote "too much" data to us.
  */
 static void out_flush (struct net2280_ep *ep)
 {
@@ -599,13 +618,13 @@
 	/* erratum 0106 ... packets coming in during fifo reads might
 	 * be incompletely rejected.  not all cases have workarounds.
 	 */
-	if (ep->dev->chiprev == 0x0100) {
+	if (ep->dev->chiprev == 0x0100
+			&& ep->dev->gadget.speed == USB_SPEED_FULL) {
+		udelay (1);
 		tmp = readl (&ep->regs->ep_stat);
 		if ((tmp & (1 << NAK_OUT_PACKETS)))
-			/* cleanup = 1 */;
-		else if ((tmp & (1 << FIFO_FULL))
-				/* don't break hs PING protocol ... */
-				|| ep->dev->gadget.speed == USB_SPEED_FULL) {
+			cleanup = 1;
+		else if ((tmp & (1 << FIFO_FULL))) {
 			start_out_naking (ep);
 			prevent = 1;
 		}
@@ -617,6 +636,15 @@
 	 */
 	prefetchw (buf);
 	count = readl (&regs->ep_avail);
+	if (unlikely (count == 0)) {
+		udelay (1);
+		tmp = readl (&ep->regs->ep_stat);
+		count = readl (&regs->ep_avail);
+		/* handled that data already? */
+		if (count == 0 && (tmp & (1 << NAK_OUT_PACKETS)) == 0)
+			return 0;
+	}
+
 	tmp = req->req.length - req->req.actual;
 	if (count > tmp) {
 		/* as with DMA, data overflow gets flushed */
@@ -626,7 +654,10 @@
 				ep->ep.name, count, tmp);
 			req->req.status = -EOVERFLOW;
 			cleanup = 1;
-		}
+			/* NAK_OUT_PACKETS will be set, so flushing is safe;
+			 * the next read will start with the next packet
+			 */
+		} /* else it's a ZLP, no worries */
 		count = tmp;
 	}
 	req->req.actual += count;
@@ -665,7 +696,7 @@
 }
 
 /* fill out dma descriptor to match a given request */
-static inline void
+static void
 fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
 {
 	struct net2280_dma	*td = req->td;
@@ -678,15 +709,13 @@
 	 */
 	if (ep->is_in)
 		dmacount |= (1 << DMA_DIRECTION);
-	else
+	else if ((dmacount % ep->ep.maxpacket) != 0)
 		dmacount |= (1 << END_OF_CHAIN);
 
 	req->valid = valid;
 	if (valid)
 		dmacount |= (1 << VALID_BIT);
-#ifdef USE_DMA_CHAINING
-	if (!req->req.no_interrupt)
-#endif
+	if (likely(!req->req.no_interrupt || !use_dma_chaining))
 		dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
 
 	/* td->dmadesc = previously set by caller */
@@ -698,7 +727,8 @@
 }
 
 static const u32 dmactl_default =
-		  (1 << DMA_CLEAR_COUNT_ENABLE)
+		  (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT)
+		| (1 << DMA_CLEAR_COUNT_ENABLE)
 		/* erratum 0116 workaround part 1 (use POLLING) */
 		| (POLL_100_USEC << DESCRIPTOR_POLLING_RATE)
 		| (1 << DMA_VALID_BIT_POLLING_ENABLE)
@@ -714,18 +744,41 @@
 
 static inline void stop_dma (struct net2280_dma_regs *dma)
 {
-	writel (dmactl_default & ~(1 << DMA_ENABLE), &dma->dmactl);
+	writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl);
 	spin_stop_dma (dma);
 }
 
+static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
+{
+	struct net2280_dma_regs	*dma = ep->dma;
+
+	writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION),
+			&dma->dmacount);
+	writel (readl (&dma->dmastat), &dma->dmastat);
+
+	writel (td_dma, &dma->dmadesc);
+	writel (dmactl, &dma->dmactl);
+
+	/* erratum 0116 workaround part 3:  pci arbiter away from net2280 */
+	(void) readl (&ep->dev->pci->pcimstctl);
+
+	writel ((1 << DMA_START), &dma->dmastat);
+
+	if (!ep->is_in)
+		stop_out_naking (ep);
+}
+
 static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
 {
 	u32			tmp;
-	int			clear_nak = 0;
 	struct net2280_dma_regs	*dma = ep->dma;
 
 	/* FIXME can't use DMA for ZLPs */
 
+	/* on this path we "know" there's no dma active (yet) */
+	WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
+	writel (0, &ep->dma->dmactl);
+
 	/* previous OUT packet might have been short */
 	if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
 		 		& (1 << NAK_OUT_PACKETS)) != 0) {
@@ -733,9 +786,9 @@
 			&ep->regs->ep_stat);
 
 		tmp = readl (&ep->regs->ep_avail);
-		if (tmp == 0)
-			clear_nak = 1;
-		else {
+		if (tmp) {
+			writel (readl (&dma->dmastat), &dma->dmastat);
+
 			/* transfer all/some fifo data */
 			writel (req->req.dma, &dma->dmaaddr);
 			tmp = min (tmp, req->req.length);
@@ -744,6 +797,8 @@
 			req->td->dmacount = cpu_to_le32 (req->req.length - tmp);
 			writel ((1 << DMA_DONE_INTERRUPT_ENABLE)
 				| tmp, &dma->dmacount);
+			req->td->dmadesc = 0;
+			req->valid = 1;
 
 			writel ((1 << DMA_ENABLE), &dma->dmactl);
 			writel ((1 << DMA_START), &dma->dmastat);
@@ -751,8 +806,6 @@
 		}
 	}
 
-	/* on this path we know there's no dma queue (yet) */
-	WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
 	tmp = dmactl_default;
 
 	/* force packet boundaries between dma requests, but prevent the
@@ -772,25 +825,10 @@
 	req->td->dmadesc = cpu_to_le32 (ep->td_dma);
 	fill_dma_desc (ep, req, 1);
 
-#ifdef USE_DMA_CHAINING
-	writel (  (1 << VALID_BIT)
-		| (ep->is_in << DMA_DIRECTION)
-		| 0, &dma->dmacount);
-#else
-	req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
-#endif
-
-	writel (req->td_dma, &dma->dmadesc);
-	writel (tmp, &dma->dmactl);
-
-	/* erratum 0116 workaround part 3:  pci arbiter away from net2280 */
-	(void) readl (&ep->dev->pci->pcimstctl);
+	if (!use_dma_chaining)
+		req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
 
-	writel ((1 << DMA_START), &dma->dmastat);
-
-	/* recover from previous short read; erratum 0112 workaround #1 */
-	if (clear_nak)
-		writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+	start_queue (ep, tmp, req->td_dma);
 }
 
 static inline void
@@ -893,7 +931,6 @@
 
 	_req->status = -EINPROGRESS;
 	_req->actual = 0;
-	req->dma_done = 0;
 
 	/* kickstart this i/o queue? */
 	if (list_empty (&ep->queue) && !ep->stopped) {
@@ -977,10 +1014,11 @@
 )
 {
 	req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);
-	rmb ();
 	done (ep, req, status);
 }
 
+static void restart_dma (struct net2280_ep *ep);
+
 static void scan_dma_completions (struct net2280_ep *ep)
 {
 	/* only look at descriptors that were "naturally" retired,
@@ -1000,14 +1038,37 @@
 			break;
 
 		/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
-		 * packets, including overruns, even when the transfer was
-		 * exactly the length requested (dmacount now zero).
-		 * FIXME there's an overrun case here too, where we expect
-		 * a short packet but receive a max length one (won't NAK).
+		 * cases where DMA must be aborted; this code handles
+		 * all non-abort DMA completions.
 		 */
-		if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) {
-			req->dma_done = 1;
+		if (unlikely (req->td->dmadesc == 0)) {
+			/* paranoia */
+			tmp = readl (&ep->dma->dmacount);
+			if (tmp & DMA_BYTE_COUNT_MASK)
+				break;
+			/* single transfer mode */
+			dma_done (ep, req, tmp, 0);
 			break;
+		} else if (!ep->is_in
+				&& (req->req.length % ep->ep.maxpacket) != 0) {
+			tmp = readl (&ep->regs->ep_stat);
+
+			/* AVOID TROUBLE HERE by not issuing short reads from
+			 * your gadget driver.  That helps avoids errata 0121,
+			 * 0122, and 0124; not all cases trigger the warning.
+			 */
+			if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+				WARN (ep->dev, "%s lost packet sync!\n",
+						ep->ep.name);
+				req->req.status = -EOVERFLOW;
+			} else if ((tmp = readl (&ep->regs->ep_avail)) != 0) {
+				/* fifo gets flushed later */
+				ep->out_overflow = 1;
+				DEBUG (ep->dev, "%s dma, discard %d len %d\n",
+						ep->ep.name, tmp,
+						req->req.length);
+				req->req.status = -EOVERFLOW;
+			}
 		}
 		dma_done (ep, req, tmp, 0);
 	}
@@ -1016,41 +1077,50 @@
 static void restart_dma (struct net2280_ep *ep)
 {
 	struct net2280_request	*req;
+	u32			dmactl = dmactl_default;
 
 	if (ep->stopped)
 		return;
 	req = list_entry (ep->queue.next, struct net2280_request, queue);
 
-#ifdef USE_DMA_CHAINING
+	if (!use_dma_chaining) {
+		start_dma (ep, req);
+		return;
+	}
+
 	/* the 2280 will be processing the queue unless queue hiccups after
 	 * the previous transfer:
 	 *  IN:   wanted automagic zlp, head doesn't (or vice versa)
+	 *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.
 	 *  OUT:  was "usb-short", we must restart.
 	 */
-	if (!req->valid) {
+	if (ep->is_in && !req->valid) {
 		struct net2280_request	*entry, *prev = 0;
-		int			qmode, reqmode, done = 0;
+		int			reqmode, done = 0;
 
 		DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
-		qmode = likely (req->req.zero
+		ep->in_fifo_validate = likely (req->req.zero
 			|| (req->req.length % ep->ep.maxpacket) != 0);
+		if (ep->in_fifo_validate)
+			dmactl |= (1 << DMA_FIFO_VALIDATE);
 		list_for_each_entry (entry, &ep->queue, queue) {
 			u32		dmacount;
 
-			if (entry != req)
+			if (entry == req)
 				continue;
 			dmacount = entry->td->dmacount;
 			if (!done) {
 				reqmode = likely (entry->req.zero
 					|| (entry->req.length
 						% ep->ep.maxpacket) != 0);
-				if (reqmode == qmode) {
+				if (reqmode == ep->in_fifo_validate) {
 					entry->valid = 1;
 					dmacount |= valid_bit;
 					entry->td->dmacount = dmacount;
 					prev = entry;
 					continue;
 				} else {
+					/* force a hiccup */
 					prev->td->dmacount |= dma_done_ie;
 					done = 1;
 				}
@@ -1062,22 +1132,21 @@
 			entry->td->dmacount = dmacount;
 			prev = entry;
 		}
-		start_dma (ep, req);
-	} else if (!ep->is_in
-			&& (readl (&ep->regs->ep_stat)
-				& (1 << NAK_OUT_PACKETS)) != 0)
-		start_dma (ep, req);
-#else
-	start_dma (ep, req);
-#endif
+	}
+
+	writel (0, &ep->dma->dmactl);
+	start_queue (ep, dmactl, req->td_dma);
 }
 
-static inline void abort_dma (struct net2280_ep *ep)
+static void abort_dma (struct net2280_ep *ep)
 {
 	/* abort the current transfer */
-	writel ((1 << DMA_ABORT), &ep->dma->dmastat);
-
-	/* collect completed transfers (except the current one) */
+	if (likely (!list_empty (&ep->queue))) {
+		/* FIXME work around errata 0121, 0122, 0124 */
+		writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+		spin_stop_dma (ep->dma);
+	} else
+		stop_dma (ep->dma);
 	scan_dma_completions (ep);
 }
 
@@ -1108,43 +1177,53 @@
 	int			stopped;
 
 	ep = container_of (_ep, struct net2280_ep, ep);
-	req = container_of (_req, struct net2280_request, req);
 	if (!_ep || (!ep->desc && ep->num != 0) || !_req)
 		return -EINVAL;
 
 	spin_lock_irqsave (&ep->dev->lock, flags);
 	stopped = ep->stopped;
 
-	/* pause dma while we scan the queue */
+	/* quiesce dma while we patch the queue */
 	dmactl = 0;
 	ep->stopped = 1;
 	if (ep->dma) {
 		dmactl = readl (&ep->dma->dmactl);
-		writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl);
-		/* force synch, clean any completed requests */
-		spin_stop_dma (ep->dma);
+		/* WARNING erratum 0127 may kick in ... */
+		stop_dma (ep->dma);
 		scan_dma_completions (ep);
 	}
 
+	/* make sure it's still queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore (&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
 	/* queue head may be partially complete. */
 	if (ep->queue.next == &req->queue) {
 		if (ep->dma) {
 			DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);
 			_req->status = -ECONNRESET;
 			abort_dma (ep);
-			if (likely (ep->queue.next == &req->queue))
+			if (likely (ep->queue.next == &req->queue)) {
+				// NOTE: misreports single-transfer mode
+				req->td->dmacount = 0;	/* invalidate */
 				dma_done (ep, req,
-					le32_to_cpup (&req->td->dmacount),
+					readl (&ep->dma->dmacount),
 					-ECONNRESET);
+			}
 		} else {
 			DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);
 			done (ep, req, -ECONNRESET);
 		}
 		req = 0;
 
-#ifdef USE_DMA_CHAINING
 	/* patch up hardware chaining data */
-	} else if (ep->dma) {
+	} else if (ep->dma && use_dma_chaining) {
 		if (req->queue.prev == ep->queue.next) {
 			writel (le32_to_cpu (req->td->dmadesc),
 				&ep->dma->dmadesc);
@@ -1161,7 +1240,6 @@
 			if (req->td->dmacount & dma_done_ie)
 				prev->td->dmacount |= dma_done_ie;
 		}
-#endif
 	}
 
 	if (req)
@@ -1188,10 +1266,14 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int net2280_fifo_status (struct usb_ep *_ep);
+
 static int
 net2280_set_halt (struct usb_ep *_ep, int value)
 {
 	struct net2280_ep	*ep;
+	unsigned long		flags;
+	int			retval = 0;
 
 	ep = container_of (_ep, struct net2280_ep, ep);
 	if (!_ep || (!ep->desc && ep->num != 0))
@@ -1202,19 +1284,27 @@
 						== USB_ENDPOINT_XFER_ISOC)
 		return -EINVAL;
 
-	VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
-
-	/* set/clear, then synch memory views with the device */
-	if (value) {
-		if (ep->num == 0)
-			ep->dev->protocol_stall = 1;
-		else
-			set_halt (ep);
-	} else
-		clear_halt (ep);
-	(void) readl (&ep->regs->ep_rsp);
+	spin_lock_irqsave (&ep->dev->lock, flags);
+	if (!list_empty (&ep->queue))
+		retval = -EAGAIN;
+	else if (ep->is_in && value && net2280_fifo_status (_ep) != 0)
+		retval = -EAGAIN;
+	else {
+		VDEBUG (ep->dev, "%s %s halt\n", _ep->name,
+				value ? "set" : "clear");
+		/* set/clear, then synch memory views with the device */
+		if (value) {
+			if (ep->num == 0)
+				ep->dev->protocol_stall = 1;
+			else
+				set_halt (ep);
+		} else
+			clear_halt (ep);
+		(void) readl (&ep->regs->ep_rsp);
+	}
+	spin_unlock_irqrestore (&ep->dev->lock, flags);
 
-	return 0;
+	return retval;
 }
 
 static int
@@ -1290,21 +1380,49 @@
 static int net2280_wakeup (struct usb_gadget *_gadget)
 {
 	struct net2280		*dev;
+	u32			tmp;
+	unsigned long		flags;
 
 	if (!_gadget)
 		return 0;
 	dev = container_of (_gadget, struct net2280, gadget);
-	writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
+
+	spin_lock_irqsave (&dev->lock, flags);
+	tmp = readl (&dev->usb->usbctl);
+	if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE))
+		writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
+	spin_unlock_irqrestore (&dev->lock, flags);
 
 	/* pci writes may still be posted */
 	return 0;
 }
 
+static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value)
+{
+	struct net2280		*dev;
+	u32			tmp;
+	unsigned long		flags;
+
+	if (!_gadget)
+		return 0;
+	dev = container_of (_gadget, struct net2280, gadget);
+
+	spin_lock_irqsave (&dev->lock, flags);
+	tmp = readl (&dev->usb->usbctl);
+	if (value)
+		tmp |= (1 << SELF_POWERED_STATUS);
+	else
+		tmp &= ~(1 << SELF_POWERED_STATUS);
+	writel (tmp, &dev->usb->usbctl);
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	return 0;
+}
+
 static const struct usb_gadget_ops net2280_ops = {
 	.get_frame	= net2280_get_frame,
 	.wakeup		= net2280_wakeup,
-
-	// .set_selfpowered = net2280_set_selfpowered,
+	.set_selfpowered = net2280_set_selfpowered,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1348,11 +1466,14 @@
 
 	/* Main Control Registers */
 	t = snprintf (next, size, "%s version " DRIVER_VERSION
-			", chiprev %04x\n"
+			", chiprev %04x, dma %s\n\n"
 			"devinit %03x fifoctl %08x gadget '%s'\n"
 			"pci irqenb0 %02x irqenb1 %08x "
 			"irqstat0 %04x irqstat1 %08x\n",
 			driver_name, dev->chiprev,
+			use_dma
+				? (use_dma_chaining ? "chaining" : "enabled")
+				: "disabled",
 			readl (&dev->regs->devinit),
 			readl (&dev->regs->fifoctl),
 			s,
@@ -1399,7 +1520,7 @@
 		t1 = readl (&ep->regs->ep_cfg);
 		t2 = readl (&ep->regs->ep_rsp) & 0xff;
 		t = snprintf (next, size,
-				"%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
+				"\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
 					"irqenb %02x\n",
 				ep->ep.name, t1, t2,
 				(t2 & (1 << CLEAR_NAK_OUT_PACKETS))
@@ -1453,7 +1574,7 @@
 		// none yet 
 
 	/* Statistics */
-	t = snprintf (next, size, "irqs:  ");
+	t = snprintf (next, size, "\nirqs:  ");
 	size -= t;
 	next += t;
 	for (i = 0; i < 7; i++) {
@@ -1462,7 +1583,7 @@
 		ep = &dev->ep [i];
 		if (i && !ep->irqs)
 			continue;
-		t = snprintf (next, size, " %s/%ld", ep->ep.name, ep->irqs);
+		t = snprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs);
 		size -= t;
 		next += t;
 
@@ -1504,7 +1625,7 @@
 				continue;
 			t = d->bEndpointAddress;
 			t = snprintf (next, size,
-				"%s (ep%d%s-%s) max %04x %s\n",
+				"\n%s (ep%d%s-%s) max %04x %s fifo %d\n",
 				ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
 				(t & USB_DIR_IN) ? "in" : "out",
 				({ char *val;
@@ -1517,7 +1638,7 @@
 				 	val = "iso"; break;
 				 }; val; }),
 				le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
-				ep->dma ? "dma" : "pio"
+				ep->dma ? "dma" : "pio", ep->fifo_size
 				);
 		} else /* ep0 should only have one transfer queued */
 			t = snprintf (next, size, "ep0 max 64 pio %s\n",
@@ -1552,6 +1673,20 @@
 				goto done;
 			size -= t;
 			next += t;
+
+			if (ep->dma) {
+				struct net2280_dma	*td;
+
+				td = req->td;
+				t = snprintf (next, size, "\t    td %08x "
+					" count %08x buf %08x desc %08x\n",
+					req->td_dma, td->dmacount,
+					td->dmaaddr, td->dmadesc);
+				if (t <= 0 || t > size)
+					goto done;
+				size -= t;
+				next += t;
+			}
 		}
 	}
 
@@ -1686,8 +1821,10 @@
 
 	/* clear old dma and irq state */
 	for (tmp = 0; tmp < 4; tmp++) {
-		writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat);
-		stop_dma (&dev->dma [tmp]);
+		struct net2280_ep	*ep = &dev->ep [tmp + 1];
+
+		if (ep->dma)
+			abort_dma (ep);
 	}
 	writel (~0, &dev->regs->irqstat0),
 	writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1),
@@ -1767,7 +1904,7 @@
 		| (1 << SELF_POWERED_USB_DEVICE)
 		| (1 << REMOTE_WAKEUP_SUPPORT)
 		| (1 << USB_DETECT_ENABLE)
-		| (1 << DEVICE_REMOTE_WAKEUP_ENABLE)
+		| (1 << SELF_POWERED_STATUS)
 		, &dev->usb->usbctl);
 
 	/* enable irqs so we can see ep0 and general operation  */
@@ -1939,6 +2076,8 @@
 					ep->stopped = 1;
 					set_halt (ep);
 				}
+				if (!req)
+					allow_status (ep);
 				mode = 2;
 			/* reply to extra IN data tokens with a zlp */
 			} else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {
@@ -1979,41 +2118,62 @@
 	if (likely (ep->dma != 0)) {
 		if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
 			u32	count;
+			int	stopped = ep->stopped;
 
 			/* TRANSFERRED works around OUT_DONE erratum 0112.
 			 * we expect (N <= maxpacket) bytes; host wrote M.
 			 * iff (M < N) we won't ever see a DMA interrupt.
 			 */
-			count = readl (&ep->dma->dmacount);
-			count &= DMA_BYTE_COUNT_MASK;
-			if (!req->dma_done) {
-				/* dma can finish with the FIFO non-empty,
-				 * on (M > N) errors.
+			ep->stopped = 1;
+			for (count = 0; ; t = readl (&ep->regs->ep_stat)) {
+
+				/* any preceding dma transfers must finish.
+				 * dma handles (M >= N), may empty the queue
+				 */
+				scan_dma_completions (ep);
+				if (unlikely (list_empty (&ep->queue)
+						|| ep->out_overflow)) {
+					req = 0;
+					break;
+				}
+				req = list_entry (ep->queue.next,
+					struct net2280_request, queue);
+
+				/* here either (M < N), a "real" short rx;
+				 * or (M == N) and the queue didn't empty
 				 */
-				while (count && (t & (1 << FIFO_EMPTY)) == 0) {
-					cpu_relax ();
-					t = readl (&ep->regs->ep_stat);
+				if (likely (t & (1 << FIFO_EMPTY))) {
 					count = readl (&ep->dma->dmacount);
 					count &= DMA_BYTE_COUNT_MASK;
+					if (readl (&ep->dma->dmadesc)
+							!= req->td_dma)
+						req = 0;
+					break;
 				}
+				udelay(1);
 			}
 
 			/* stop DMA, leave ep NAKing */
 			writel ((1 << DMA_ABORT), &ep->dma->dmastat);
 			spin_stop_dma (ep->dma);
 
-			/* buffer might have been too small */
-			t = readl (&ep->regs->ep_avail);
-			if (t != 0)
-				DEBUG (ep->dev, "%s dma, discard %d len %d\n",
-						ep->ep.name, t, count);
-			dma_done (ep, req, count, t ? -EOVERFLOW : 0);
+			if (likely (req != 0)) {
+				req->td->dmacount = 0;
+				t = readl (&ep->regs->ep_avail);
+				dma_done (ep, req, count, t);
+			}
 
 			/* also flush to prevent erratum 0106 trouble */
-			if (t || ep->dev->chiprev == 0x0100)
+			if (unlikely (ep->out_overflow
+					|| (ep->dev->chiprev == 0x0100
+						&& ep->dev->gadget.speed
+							== USB_SPEED_FULL))) {
 				out_flush (ep);
+				ep->out_overflow = 0;
+			}
 
-			/* restart dma (still NAKing OUT!) if needed */
+			/* (re)start dma if needed, stop NAKing */
+			ep->stopped = stopped;
 			if (!list_empty (&ep->queue))
 				restart_dma (ep);
 		} else
@@ -2184,11 +2344,12 @@
 		 * that'll mean a lot less irqs for some drivers.
 		 */
 		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
-		if (ep->is_in)
+		if (ep->is_in) {
 			scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
 				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
 				| (1 << DATA_IN_TOKEN_INTERRUPT);
-		else
+			stop_out_naking (ep);
+		} else
 			scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT)
 				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
 				| (1 << DATA_IN_TOKEN_INTERRUPT);
@@ -2390,18 +2551,18 @@
 		tmp = readl (&dma->dmastat);
 		writel (tmp, &dma->dmastat);
 
-#ifdef USE_DMA_CHAINING
-		/* chaining should stop only on error (which?)
+		/* chaining should stop on abort, short OUT from fifo,
 		 * or (stat0 codepath) short OUT transfer.
 		 */
-#else
-		if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) {
-			DEBUG (ep->dev, "%s no xact done? %08x\n",
-				ep->ep.name, tmp);
-			continue;
+		if (!use_dma_chaining) {
+			if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))
+					== 0) {
+				DEBUG (ep->dev, "%s no xact done? %08x\n",
+					ep->ep.name, tmp);
+				continue;
+			}
+			stop_dma (ep->dma);
 		}
-		stop_dma (ep->dma);
-#endif
 
 		/* OUT transfers terminate when the data from the
 		 * host is in our memory.  Process whatever's done.
@@ -2417,16 +2578,14 @@
 
 		/* disable dma on inactive queues; else maybe restart */
 		if (list_empty (&ep->queue)) {
-#ifdef USE_DMA_CHAINING
-			stop_dma (ep->dma);
-#endif
+			if (use_dma_chaining)
+				stop_dma (ep->dma);
 		} else {
 			tmp = readl (&dma->dmactl);
-			if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0
+			if (!use_dma_chaining
 					|| (tmp & (1 << DMA_ENABLE)) == 0)
 				restart_dma (ep);
-#ifdef USE_DMA_CHAINING
-			else if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			else if (ep->is_in && use_dma_chaining) {
 				struct net2280_request	*req;
 				u32			dmacount;
 
@@ -2441,12 +2600,9 @@
 				dmacount &= __constant_cpu_to_le32 (
 						(1 << VALID_BIT)
 						| DMA_BYTE_COUNT_MASK);
-				if (dmacount && (dmacount & valid_bit) == 0) {
-					stop_dma (ep->dma);
+				if (dmacount && (dmacount & valid_bit) == 0)
 					restart_dma (ep);
-				}
 			}
-#endif
 		}
 		ep->irqs++;
 	}
@@ -2646,20 +2802,20 @@
 		}
 		td->dmacount = 0;	/* not VALID */
 		td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+		td->dmadesc = td->dmaaddr;
 		dev->ep [i].dummy = td;
 	}
 
 	/* enable lower-overhead pci memory bursts during DMA */
-	writel ((1 << PCI_RETRY_ABORT_ENABLE)
-			| (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+	writel ( (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+			// 256 write retries may not be enough...
+			// | (1 << PCI_RETRY_ABORT_ENABLE)
 			| (1 << DMA_READ_MULTIPLE_ENABLE)
 			| (1 << DMA_READ_LINE_ENABLE)
 			, &dev->pci->pcimstctl);
 	/* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
 	pci_set_master (pdev);
-#ifdef	HAVE_PCI_SET_MWI
 	pci_set_mwi (pdev);
-#endif
 
 	/* ... also flushes any posted pci writes */
 	dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
@@ -2669,15 +2825,10 @@
 	INFO (dev, "%s\n", driver_desc);
 	INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
 			bufp, base, dev->chiprev);
-	bufp = DRIVER_VERSION
-#ifndef USE_DMA_CHAINING
-		" (no dma chain)"
-#endif
-#ifdef NET2280_DMA_OUT_WORKAROUND
-		" (no dma out)"
-#endif
-		;
-	INFO (dev, "version: %s\n", bufp);
+	INFO (dev, "version: " DRIVER_VERSION "; dma %s\n",
+			use_dma
+				? (use_dma_chaining ? "chaining" : "enabled")
+				: "disabled");
 	the_controller = dev;
 
 	return 0;
@@ -2720,6 +2871,8 @@
 
 static int __init init (void)
 {
+	if (!use_dma)
+		use_dma_chaining = 0;
 	return pci_module_init (&net2280_pci_driver);
 }
 module_init (init);
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/net2280.h linux-2.4.25-pre8/drivers/usb/gadget/net2280.h
--- linux-2.4.25-pre7/drivers/usb/gadget/net2280.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/net2280.h	2004-01-29 10:58:21.000000000 -0800
@@ -520,6 +520,7 @@
 	unsigned				num : 8,
 						fifo_size : 12,
 						in_fifo_validate : 1,
+						out_overflow : 1,
 						stopped : 1,
 						is_in : 1,
 						is_iso : 1;
@@ -529,6 +530,7 @@
 {
 	/* ep0 only */
 	writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+		| (1 << CLEAR_NAK_OUT_PACKETS)
 		| (1 << CLEAR_NAK_OUT_PACKETS_MODE)
 		, &ep->regs->ep_rsp);
 	ep->stopped = 1;
@@ -546,7 +548,6 @@
 	dma_addr_t			td_dma;
 	struct list_head		queue;
 	unsigned			mapped : 1,
-					dma_done : 1,
 					valid : 1;
 };
 
@@ -559,8 +560,7 @@
 	unsigned			enabled : 1,
 					protocol_stall : 1,
 					got_irq : 1,
-					region : 1,
-					selfpowered : 1;
+					region : 1;
 	u16				chiprev;
 
 	/* pci state used to access those endpoints */
diff -urN linux-2.4.25-pre7/drivers/usb/gadget/zero.c linux-2.4.25-pre8/drivers/usb/gadget/zero.c
--- linux-2.4.25-pre7/drivers/usb/gadget/zero.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/gadget/zero.c	2004-01-29 10:58:21.000000000 -0800
@@ -106,18 +106,14 @@
  *
  * CHIP ... hardware identifier
  * DRIVER_VERSION_NUM ... alerts the host side driver to differences
- * EP0_MAXPACKET ... controls packetization of control requests
  * EP_*_NAME ... which endpoints do we use for which purpose?
  * EP_*_NUM ... numbers for them (often limited by hardware)
  * HIGHSPEED ... define if ep0 and descriptors need high speed support
  * MAX_USB_POWER ... define if we use other than 100 mA bus current
- * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
+ * SELFPOWER ... if we can run on bus power, zero
  * WAKEUP ... if hardware supports remote wakeup AND we will issue the
  * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
  *
- * hw_optimize(gadget) ... for any hardware tweaks we want to kick in
- * 	before we enable our endpoints
- *
  * add other defines for other portability issues, like hardware that
  * for some reason doesn't handle full speed bulk maxpacket of 64.
  */
@@ -133,28 +129,16 @@
  * DMA channels to manage their FIFOs.  It supports high speed.
  * Those endpoints can be arranged in any desired configuration.
  */
-#ifdef	CONFIG_USB_ZERO_NET2280
+#ifdef	CONFIG_USB_GADGET_NET2280
 #define CHIP			"net2280"
 #define DRIVER_VERSION_NUM	0x0111
-#define EP0_MAXPACKET		64
 static const char EP_OUT_NAME [] = "ep-a";
 #define EP_OUT_NUM	2
 static const char EP_IN_NAME [] = "ep-b";
 #define EP_IN_NUM	2
 #define HIGHSPEED
 /* specific hardware configs could be bus-powered */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* supports remote wakeup, but this driver doesn't */
-
-extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
-
-static inline void hw_optimize (struct usb_gadget *gadget)
-{
-	/* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets
-	 * for highspeed bulk) because we're not using ep-c/ep-d.
-	 */
-	net2280_set_fifo_mode (gadget, 1);
-}
 #endif
 
 /*
@@ -168,20 +152,15 @@
  * can't use altsettings or reset the interfaces independently.
  * So stick to a single interface.
  */
-#ifdef	CONFIG_USB_ZERO_PXA2XX
+#ifdef	CONFIG_USB_GADGET_PXA2XX
 #define CHIP			"pxa2xx"
 #define DRIVER_VERSION_NUM	0x0113
-#define EP0_MAXPACKET		16
 static const char EP_OUT_NAME [] = "ep12out-bulk";
 #define EP_OUT_NUM	12
 static const char EP_IN_NAME [] = "ep11in-bulk";
 #define EP_IN_NUM	11
 /* doesn't support bus-powered operation */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* supports remote wakeup, but this driver doesn't */
-
-/* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0)
 #endif
 
 /*
@@ -195,20 +174,15 @@
  * in special situations.  So this is a case of "choose it right
  * during enumeration" ...
  */
-#ifdef	CONFIG_USB_ZERO_SA1100
+#ifdef	CONFIG_USB_GADGET_SA1100
 #define CHIP			"sa1100"
 #define DRIVER_VERSION_NUM	0x0115
-#define EP0_MAXPACKET		8
 static const char EP_OUT_NAME [] = "ep1out-bulk";
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2in-bulk";
 #define EP_IN_NUM	2
 /* doesn't support bus-powered operation */
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* doesn't support remote wakeup? */
-
-/* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0)
 #endif
 
 /*
@@ -216,23 +190,19 @@
  *
  * This has three semi-configurable full speed bulk/interrupt endpoints.
  */
-#ifdef	CONFIG_USB_ZERO_GOKU
+#ifdef	CONFIG_USB_GADGET_GOKU
 #define CHIP			"goku"
 #define DRIVER_VERSION_NUM	0x0116
-#define EP0_MAXPACKET		8
 static const char EP_OUT_NAME [] = "ep1-bulk";
 #define EP_OUT_NUM	1
 static const char EP_IN_NAME [] = "ep2-bulk";
 #define EP_IN_NUM	2
-#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* doesn't support remote wakeup */
-
-#define hw_optimize(g) do {} while (0)
 #endif
 
 /*-------------------------------------------------------------------------*/
 
-#ifndef EP0_MAXPACKET
+#ifndef EP_OUT_NUM
 #	error Configure some USB peripheral controller driver!
 #endif
 
@@ -241,10 +211,10 @@
  */
 
 #ifndef	SELFPOWER
-/* default: say we rely on bus power */
-#define SELFPOWER	0
+/* default: say we're self-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
 /* else:
- * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
+ * - SELFPOWER value must be zero
  * - MAX_USB_POWER may be nonzero.
  */
 #endif
@@ -362,14 +332,13 @@
 #define	CONFIG_SOURCE_SINK	3
 #define	CONFIG_LOOPBACK		2
 
-static const struct usb_device_descriptor
+static struct usb_device_descriptor
 device_desc = {
 	.bLength =		sizeof device_desc,
 	.bDescriptorType =	USB_DT_DEVICE,
 
 	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
 	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
-	.bMaxPacketSize0 =	EP0_MAXPACKET,
 
 	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
 	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
@@ -481,7 +450,7 @@
 	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
 };
 
-static const struct usb_qualifier_descriptor
+static struct usb_qualifier_descriptor
 dev_qualifier = {
 	.bLength =		sizeof dev_qualifier,
 	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
@@ -489,9 +458,6 @@
 	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
 	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
 
-	/* assumes ep0 uses the same value for both speeds ... */
-	.bMaxPacketSize0 =	EP0_MAXPACKET,
-
 	.bNumConfigurations =	2,
 };
 
@@ -975,7 +941,7 @@
 	if (number == dev->config)
 		return 0;
 
-#ifdef CONFIG_USB_ZERO_SA1100
+#ifdef CONFIG_USB_GADGET_SA1100
 	if (dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
 		INFO (dev, "can't change configurations\n");
@@ -983,7 +949,6 @@
 	}
 #endif
 	zero_reset_config (dev);
-	hw_optimize (gadget);
 
 	switch (number) {
 	case CONFIG_SOURCE_SINK:
@@ -1052,7 +1017,7 @@
 
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != USB_DIR_IN)
-			break;
+			goto unknown;
 		switch (ctrl->wValue >> 8) {
 
 		case USB_DT_DEVICE:
@@ -1092,14 +1057,14 @@
 	/* currently two configs, two speeds */
 	case USB_REQ_SET_CONFIGURATION:
 		if (ctrl->bRequestType != 0)
-			break;
+			goto unknown;
 		spin_lock (&dev->lock);
 		value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
 		if (ctrl->bRequestType != USB_DIR_IN)
-			break;
+			goto unknown;
 		*(u8 *)req->buf = dev->config;
 		value = min (ctrl->wLength, (u16) 1);
 		break;
@@ -1110,7 +1075,7 @@
 	 */
 	case USB_REQ_SET_INTERFACE:
 		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
-			break;
+			goto unknown;
 		spin_lock (&dev->lock);
 		if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) {
 			u8		config = dev->config;
@@ -1130,7 +1095,7 @@
 		break;
 	case USB_REQ_GET_INTERFACE:
 		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
-			break;
+			goto unknown;
 		if (!dev->config)
 			break;
 		if (ctrl->wIndex != 0) {
@@ -1141,7 +1106,35 @@
 		value = min (ctrl->wLength, (u16) 1);
 		break;
 
+	/*
+	 * These are the same vendor-specific requests supported by
+	 * Intel's USB 2.0 compliance test devices.  We exceed that
+	 * device spec by allowing multiple-packet requests.
+	 */
+	case 0x5b:	/* control WRITE test -- fill the buffer */
+		if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
+			goto unknown;
+		if (ctrl->wValue || ctrl->wIndex)
+			break;
+		/* just read that many bytes into the buffer */
+		if (ctrl->wLength > USB_BUFSIZ)
+			break;
+		value = ctrl->wLength;
+		break;
+	case 0x5c:	/* control READ test -- return the buffer */
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
+			goto unknown;
+		if (ctrl->wValue || ctrl->wIndex)
+			break;
+		/* expect those bytes are still in the buffer; send back */
+		if (ctrl->wLength > USB_BUFSIZ
+				|| ctrl->wLength != req->length)
+			break;
+		value = ctrl->wLength;
+		break;
+
 	default:
+unknown:
 		VDEBUG (dev,
 			"unknown control req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
@@ -1223,6 +1216,12 @@
 
 	dev->req->complete = zero_setup_complete;
 
+	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+#ifdef HIGHSPEED
+	/* assume ep0 uses the same value for both speeds ... */
+	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+#endif
+
 	gadget->ep0->driver_data = dev;
 
 	INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
diff -urN linux-2.4.25-pre7/drivers/usb/hid-core.c linux-2.4.25-pre8/drivers/usb/hid-core.c
--- linux-2.4.25-pre7/drivers/usb/hid-core.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/hid-core.c	2004-01-29 10:58:21.000000000 -0800
@@ -1235,8 +1235,8 @@
  	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_OKI, USB_VENDOR_ID_OKI_MULITI, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
 	{ 0, 0 }
 };
 
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci-dbg.c linux-2.4.25-pre8/drivers/usb/host/ehci-dbg.c
--- linux-2.4.25-pre7/drivers/usb/host/ehci-dbg.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/ehci-dbg.c	2004-01-29 10:58:21.000000000 -0800
@@ -73,6 +73,7 @@
 
 		buf[0] = 0;
 		for (i = 0; i < HCS_N_PORTS (params); i++) {
+			// FIXME MIPS won't readb() ...
 			byte = readb (&ehci->caps->portroute[(i>>1)]);
 			sprintf(tmp, "%d ", 
 				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
@@ -125,7 +126,7 @@
 #ifdef	DEBUG
 
 static void __attribute__((__unused__))
-dbg_qtd (char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 {
 	ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
 		cpu_to_le32p (&qtd->hw_next),
@@ -141,7 +142,7 @@
 }
 
 static void __attribute__((__unused__))
-dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
 		qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
@@ -149,6 +150,36 @@
 	dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
 }
 
+static void __attribute__((__unused__))
+dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) 
+{
+	ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
+		label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
+	ehci_dbg (ehci,
+		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", 
+		le32_to_cpu(itd->hw_transaction[0]),
+		le32_to_cpu(itd->hw_transaction[1]),
+		le32_to_cpu(itd->hw_transaction[2]),
+		le32_to_cpu(itd->hw_transaction[3]),
+		le32_to_cpu(itd->hw_transaction[4]),
+		le32_to_cpu(itd->hw_transaction[5]),
+		le32_to_cpu(itd->hw_transaction[6]),
+		le32_to_cpu(itd->hw_transaction[7]));
+	ehci_dbg (ehci,
+		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n", 
+		le32_to_cpu(itd->hw_bufp[0]),
+		le32_to_cpu(itd->hw_bufp[1]),
+		le32_to_cpu(itd->hw_bufp[2]),
+		le32_to_cpu(itd->hw_bufp[3]),
+		le32_to_cpu(itd->hw_bufp[4]),
+		le32_to_cpu(itd->hw_bufp[5]),
+		le32_to_cpu(itd->hw_bufp[6]));
+	ehci_dbg (ehci, "  index: %d %d %d %d %d %d %d %d\n",
+		itd->index[0], itd->index[1], itd->index[2],
+		itd->index[3], itd->index[4], itd->index[5],
+		itd->index[6], itd->index[7]);
+}
+
 static int __attribute__((__unused__))
 dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
 {
@@ -571,7 +602,7 @@
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/* Capability Registers */
-	i = readw (&ehci->caps->hci_version);
+	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	temp = snprintf (next, size,
 		"%s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
 		pdev->dev.name,
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci-hcd.c linux-2.4.25-pre8/drivers/usb/host/ehci-hcd.c
--- linux-2.4.25-pre7/drivers/usb/host/ehci-hcd.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/ehci-hcd.c	2004-01-29 10:58:21.000000000 -0800
@@ -68,6 +68,9 @@
  *
  * HISTORY:
  *
+ * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
+ *	<sojkam@centrum.cz>, updates by DB).
+ *
  * 2002-11-29	Correct handling for hw async_next register.
  * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
  *	only scheduling is different, no arbitrary limitations.
@@ -91,14 +94,16 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2003-Jun-19/2.4"
+#define DRIVER_VERSION "2003-Dec-29/2.4"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
 static const char	hcd_name [] = "ehci_hcd";
 
 
-// #define EHCI_VERBOSE_DEBUG
+#undef EHCI_VERBOSE_DEBUG
+#undef EHCI_URB_TRACE
+
 // #define have_split_iso
 
 #ifdef DEBUG
@@ -333,8 +338,8 @@
 	spin_lock_init (&ehci->lock);
 
 	ehci->caps = (struct ehci_caps *) hcd->regs;
-	ehci->regs = (struct ehci_regs *) (hcd->regs +
-				readb (&ehci->caps->length));
+ 	ehci->regs = (struct ehci_regs *) (hcd->regs +
+ 				HC_LENGTH (readl (&ehci->caps->hc_capbase)));
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
@@ -486,7 +491,7 @@
 
         /* PCI Serial Bus Release Number is at 0x60 offset */
 	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
-	temp = readw (&ehci->caps->hci_version);
+	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	ehci_info (ehci,
 		"USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
 		((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
@@ -895,8 +900,16 @@
 			struct ehci_qh		*qh;
 			char			*why;
 
-			/* dev->ep never has ITDs or SITDs */
+			/* dev->ep is a QH unless info1.maxpacket of zero
+			 * marks an iso stream head.
+			 * FIXME do something smarter here with ISO
+			 */
 			qh = (struct ehci_qh *) dev->ep [i];
+			if (qh->hw_info1 == 0) {
+				ehci_err (ehci, "no iso cleanup!!\n");
+				continue;
+			}
+
 
 			/* detect/report non-recoverable errors */
 			if (in_interrupt ()) 
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci-mem.c linux-2.4.25-pre8/drivers/usb/host/ehci-mem.c
--- linux-2.4.25-pre7/drivers/usb/host/ehci-mem.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/host/ehci-mem.c	2004-01-29 10:58:21.000000000 -0800
@@ -28,7 +28,7 @@
  *	- driver buffers, read/written by HC ... single shot DMA mapped 
  *
  * There's also PCI "register" data, which is memory mapped.
- * No memory seen by this driver is pagable.
+ * No memory seen by this driver is pageable.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -130,6 +130,7 @@
 	}
 	if (qh->dummy)
 		ehci_qtd_free (ehci, qh->dummy);
+	// usb_put_dev (qh->dev);
 	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 }
 
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci-q.c linux-2.4.25-pre8/drivers/usb/host/ehci-q.c
--- linux-2.4.25-pre7/drivers/usb/host/ehci-q.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/ehci-q.c	2004-01-29 10:58:21.000000000 -0800
@@ -225,6 +225,16 @@
 	}
 	spin_unlock (&urb->lock);
 
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s status %d len %d/%d\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->status,
+		urb->actual_length, urb->transfer_buffer_length);
+#endif
+
 	/* complete() can reenter this HCD */
 	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb (&ehci->hcd, urb, regs);
@@ -673,6 +683,10 @@
 
 			qh->period = urb->interval;
 		}
+
+		/* support for tt scheduling */
+		// qh->dev = usb_get_dev (urb->dev);
+		qh->dev = urb->dev;
 	}
 
 	/* using TT? */
@@ -732,8 +746,6 @@
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	return qh;
 }
-#undef hb_mult
-#undef hb_packet
 
 /*-------------------------------------------------------------------------*/
 
@@ -929,10 +941,14 @@
 	if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
 		epnum |= 0x10;
 
-	ehci_vdbg (ehci, "submit_async urb %p len %d ep%d%s qtd %p [qh %p]\n",
-		urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		epnum & 0x0f, usb_pipein (urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length,
 		qtd, dev ? dev->ep [epnum] : (void *)~0);
+#endif
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci-sched.c linux-2.4.25-pre8/drivers/usb/host/ehci-sched.c
--- linux-2.4.25-pre7/drivers/usb/host/ehci-sched.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/ehci-sched.c	2004-01-29 10:58:21.000000000 -0800
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (c) 2001-2003 by David Brownell
+ * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
  * 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -27,10 +28,10 @@
  * Note that for interrupt transfers, the QH/QTD manipulation is shared
  * with the "asynchronous" transaction support (control/bulk transfers).
  * The only real difference is in how interrupt transfers are scheduled.
- * We get some funky API restrictions from the current URB model, which
- * works notably better for reading transfers than for writing.  (And
- * which accordingly needs to change before it'll work inside devices,
- * or with "USB On The Go" additions to USB 2.0 ...)
+ *
+ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's linked, and holds enough
+ * pre-calculated schedule data to make appending to the queue be quick.
  */
 
 static int ehci_get_frame (struct usb_hcd *hcd);
@@ -126,9 +127,7 @@
 			q = &q->fstn->fstn_next;
 			break;
 		case Q_TYPE_ITD:
-			/* NOTE the "one uframe per itd" policy */
-			if (q->itd->hw_transaction [uframe] != 0)
-				usecs += q->itd->usecs;
+			usecs += q->itd->usecs [uframe];
 			q = &q->itd->itd_next;
 			break;
 #ifdef have_split_iso
@@ -520,417 +519,649 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void
-itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
+static inline struct ehci_iso_stream *
+iso_stream_alloc (int mem_flags)
 {
-	struct ehci_itd *first_itd = urb->hcpriv;
+	struct ehci_iso_stream *stream;
 
-	while (!list_empty (&first_itd->itd_list)) {
-		struct ehci_itd	*itd;
-
-		itd = list_entry (
-			first_itd->itd_list.next,
-			struct ehci_itd, itd_list);
-		list_del (&itd->itd_list);
-		pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	stream = kmalloc(sizeof *stream, mem_flags);
+	if (likely (stream != 0)) {
+		memset (stream, 0, sizeof(*stream));
+		INIT_LIST_HEAD(&stream->itd_list);
+		INIT_LIST_HEAD(&stream->free_itd_list);
+		stream->next_uframe = -1;
+		stream->refcount = 1;
 	}
-	pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
-	urb->hcpriv = 0;
+	return stream;
 }
 
-static int
-itd_fill (
-	struct ehci_hcd	*ehci,
-	struct ehci_itd	*itd,
-	struct urb	*urb,
-	unsigned	index,		// urb->iso_frame_desc [index]
-	dma_addr_t	dma		// mapped transfer buffer
-) {
-	u64		temp;
-	u32		buf1;
-	unsigned	i, epnum, maxp, multi;
-	unsigned	length;
-	int		is_input;
-
-	itd->hw_next = EHCI_LIST_END;
-	itd->urb = urb;
-	itd->index = index;
-
-	/* tell itd about its transfer buffer, max 2 pages */
-	length = urb->iso_frame_desc [index].length;
-	dma += urb->iso_frame_desc [index].offset;
-	temp = dma & ~0x0fff;
-	for (i = 0; i < 2; i++) {
-		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
-		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
-		temp += 0x1000;
-	}
-	itd->buf_dma = dma;
+static inline void
+iso_stream_init (
+	struct ehci_iso_stream	*stream,
+	struct usb_device	*dev,
+	int			pipe,
+	unsigned		interval
+)
+{
+	u32			buf1;
+	unsigned		epnum, maxp, multi;
+	int			is_input;
+	long			bandwidth;
 
 	/*
 	 * this might be a "high bandwidth" highspeed endpoint,
-	 * as encoded in the ep descriptor's maxpacket field
+	 * as encoded in the ep descriptor's wMaxPacket field
 	 */
-	epnum = usb_pipeendpoint (urb->pipe);
-	is_input = usb_pipein (urb->pipe);
+	epnum = usb_pipeendpoint (pipe);
+	is_input = usb_pipein (pipe) ? USB_DIR_IN : 0;
 	if (is_input) {
-		maxp = urb->dev->epmaxpacketin [epnum];
+		maxp = dev->epmaxpacketin [epnum];
 		buf1 = (1 << 11);
 	} else {
-		maxp = urb->dev->epmaxpacketout [epnum];
+		maxp = dev->epmaxpacketout [epnum];
 		buf1 = 0;
 	}
-	buf1 |= (maxp & 0x03ff);
-	multi = 1;
-	multi += (maxp >> 11) & 0x03;
-	maxp &= 0x03ff;
+
+	multi = hb_mult(maxp);
+	maxp = max_packet(maxp);
+	buf1 |= maxp;
 	maxp *= multi;
 
-	/* transfer can't fit in any uframe? */ 
-	if (length < 0 || maxp < length) {
-		dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
-			length, maxp, urb, index,
-			urb->iso_frame_desc [index].length);
-		return -ENOSPC;
-	}
-	itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
-
-	/* "plus" info in low order bits of buffer pointers */
-	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
-	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
-	itd->hw_bufp [2] |= cpu_to_le32 (multi);
-
-	/* figure hw_transaction[] value (it's scheduled later) */
-	itd->transaction = EHCI_ISOC_ACTIVE;
-	itd->transaction |= dma & 0x0fff;		/* offset; buffer=0 */
-	if ((index + 1) == urb->number_of_packets)
-		itd->transaction |= EHCI_ITD_IOC; 	/* end-of-urb irq */
-	itd->transaction |= length << 16;
-	cpu_to_le32s (&itd->transaction);
+	stream->dev = (struct hcd_dev *)dev->hcpriv;
+
+	stream->bEndpointAddress = is_input | epnum;
+	stream->interval = interval;
+	stream->maxp = maxp;
+
+	stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
+	stream->buf1 = cpu_to_le32 (buf1);
+	stream->buf2 = cpu_to_le32 (multi);
+
+	/* usbfs wants to report the average usecs per frame tied up
+	 * when transfers on this endpoint are scheduled ...
+	 */
+	stream->usecs = HS_USECS_ISO (maxp);
+	bandwidth = stream->usecs * 8;
+	bandwidth /= 1 << (interval - 1);
+	stream->bandwidth = bandwidth;
+}
+
+static void
+iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
+{
+	stream->refcount--;
+
+	/* free whenever just a dev->ep reference remains.
+	 * not like a QH -- no persistent state (toggle, halt)
+	 */
+	if (stream->refcount == 1) {
+		int is_in;
+
+		// BUG_ON (!list_empty(&stream->itd_list));
+
+		while (!list_empty (&stream->free_itd_list)) {
+			struct ehci_itd	*itd;
+
+			itd = list_entry (stream->free_itd_list.next,
+				struct ehci_itd, itd_list);
+			list_del (&itd->itd_list);
+			pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+		}
+
+		is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
+		stream->bEndpointAddress &= 0x0f;
+		stream->dev->ep [is_in + stream->bEndpointAddress] = 0;
+
+		if (stream->rescheduled) {
+			ehci_info (ehci, "ep%d%s-iso rescheduled "
+				"%lu times in %lu seconds\n",
+				stream->bEndpointAddress, is_in ? "in" : "out",
+				stream->rescheduled,
+				((jiffies - stream->start)/HZ)
+				);
+		}
+
+		kfree(stream);
+	}
+}
+
+static inline struct ehci_iso_stream *
+iso_stream_get (struct ehci_iso_stream *stream)
+{
+	if (likely (stream != 0))
+		stream->refcount++;
+	return stream;
+}
+
+static struct ehci_iso_stream *
+iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
+{
+	unsigned		epnum;
+	struct hcd_dev		*dev;
+	struct ehci_iso_stream	*stream;
+	unsigned long		flags;
+
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein(urb->pipe))
+		epnum += 0x10;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	stream = dev->ep [epnum];
+
+	if (unlikely (stream == 0)) {
+		stream = iso_stream_alloc(GFP_ATOMIC);
+		if (likely (stream != 0)) {
+			/* dev->ep owns the initial refcount */
+			dev->ep[epnum] = stream;
+			iso_stream_init(stream, urb->dev, urb->pipe,
+					urb->interval);
+		}
+
+	/* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */
+	} else if (unlikely (stream->hw_info1 != 0)) {
+		ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n",
+			urb->dev->devpath, epnum & 0x0f,
+			(epnum & 0x10) ? "in" : "out");
+		stream = 0;
+	}
+
+	/* caller guarantees an eventual matching iso_stream_put */
+	stream = iso_stream_get (stream);
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return stream;
+}
+
+/*-------------------------------------------------------------------------*/
 
+static inline struct ehci_itd_sched *
+itd_sched_alloc (unsigned packets, int mem_flags)
+{
+	struct ehci_itd_sched	*itd_sched;
+	int			size = sizeof *itd_sched;
+
+	size += packets * sizeof (struct ehci_iso_uframe);
+	itd_sched = kmalloc (size, mem_flags);
+	if (likely (itd_sched != 0)) {
+		memset(itd_sched, 0, size);
+		INIT_LIST_HEAD (&itd_sched->itd_list);
+	}
+	return itd_sched;
+}
+
+static int
+itd_sched_init (
+	struct ehci_itd_sched	*itd_sched,
+	struct ehci_iso_stream	*stream,
+	struct urb		*urb
+)
+{
+	unsigned	i;
+	dma_addr_t	dma = urb->transfer_dma;
+
+	/* how many uframes are needed for these transfers */
+	itd_sched->span = urb->number_of_packets * stream->interval;
+
+	/* figure out per-uframe itd fields that we'll need later
+	 * when we fit new itds into the schedule.
+	 */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct ehci_iso_uframe	*uframe = &itd_sched->packet [i];
+		unsigned		length;
+		dma_addr_t		buf;
+		u32			trans;
+
+		length = urb->iso_frame_desc [i].length;
+		buf = dma + urb->iso_frame_desc [i].offset;
+
+		trans = EHCI_ISOC_ACTIVE;
+		trans |= buf & 0x0fff;
+		if (unlikely ((i + 1) == urb->number_of_packets))
+			trans |= EHCI_ITD_IOC;
+		trans |= length << 16;
+		uframe->transaction = cpu_to_le32 (trans);
+
+		/* might need to cross a buffer page within a td */
+		uframe->bufp = (buf & ~(u64)0x0fff);
+		buf += length;
+		if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
+			uframe->cross = 1;
+	}
 	return 0;
 }
 
+static void
+itd_sched_free (
+	struct ehci_iso_stream	*stream,
+	struct ehci_itd_sched	*itd_sched
+)
+{
+	list_splice (&itd_sched->itd_list, &stream->free_itd_list);
+	kfree (itd_sched);
+}
+
 static int
 itd_urb_transaction (
+	struct ehci_iso_stream	*stream,
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	int			mem_flags
-) {
-	int			frame_index;
-	struct ehci_itd		*first_itd, *itd;
+)
+{
+	struct ehci_itd		*itd;
 	int			status;
 	dma_addr_t		itd_dma;
+	int			i;
+	unsigned		num_itds;
+	struct ehci_itd_sched	*itd_sched;
+
+	itd_sched = itd_sched_alloc (urb->number_of_packets, mem_flags);
+	if (unlikely (itd_sched == 0))
+		return -ENOMEM;
+
+	status = itd_sched_init (itd_sched, stream, urb);
+	if (unlikely (status != 0))  {
+		itd_sched_free (stream, itd_sched);
+		return status;
+	}
+
+	if (urb->interval < 8)
+		num_itds = 1 + (itd_sched->span + 7) / 8;
+	else
+		num_itds = urb->number_of_packets;
 
 	/* allocate/init ITDs */
-	for (frame_index = 0, first_itd = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
-		if (!itd) {
-			status = -ENOMEM;
-			goto fail;
+	for (i = 0; i < num_itds; i++) {
+
+		/* free_itd_list.next might be cache-hot ... but maybe
+		 * the HC caches it too. avoid that issue for now.
+		 */
+
+		/* prefer previously-allocated itds */
+		if (likely (!list_empty(&stream->free_itd_list))) {
+			itd = list_entry (stream->free_itd_list.prev,
+					 struct ehci_itd, itd_list);
+			list_del (&itd->itd_list);
+			itd_dma = itd->itd_dma;
+		} else
+			itd = pci_pool_alloc (ehci->itd_pool, mem_flags,
+					&itd_dma);
+
+		if (unlikely (0 == itd)) {
+			itd_sched_free (stream, itd_sched);
+			return -ENOMEM;
 		}
 		memset (itd, 0, sizeof *itd);
 		itd->itd_dma = itd_dma;
-
-		status = itd_fill (ehci, itd, urb, frame_index,
-				urb->transfer_dma);
-		if (status != 0)
-			goto fail;
-
-		if (first_itd)
-			list_add_tail (&itd->itd_list,
-					&first_itd->itd_list);
-		else {
-			INIT_LIST_HEAD (&itd->itd_list);
-			urb->hcpriv = first_itd = itd;
-		}
+		list_add (&itd->itd_list, &itd_sched->itd_list);
 	}
+
+	/* temporarily store schedule info in hcpriv */
+	urb->hcpriv = itd_sched;
 	urb->error_count = 0;
 	return 0;
-
-fail:
-	if (urb->hcpriv)
-		itd_free_list (ehci, urb);
-	return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static inline void
-itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
-{
-	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
-	itd->itd_next = ehci->pshadow [frame];
-	itd->hw_next = ehci->periodic [frame];
-	ehci->pshadow [frame].itd = itd;
-	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
 }
 
 /*
- * return zero on success, else -errno
- * - start holds first uframe to start scheduling into
- * - max is the first uframe it's NOT (!) OK to start scheduling into
- * math to be done modulo "mod" (ehci->periodic_size << 3)
+ * This scheduler plans almost as far into the future as it has actual
+ * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
+ * "as small as possible" to be cache-friendlier.)  That limits the size
+ * transfers you can stream reliably; avoid more than 64 msec per urb.
+ * Also avoid queue depths of less than the system's worst irq latency.
  */
-static int get_iso_range (
+
+#define SCHEDULE_SLOP	10	/* frames */
+
+static int
+itd_stream_schedule (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
-	unsigned		*start,
-	unsigned		*max,
-	unsigned		mod
-) {
-	struct list_head	*lh;
-	struct hcd_dev		*dev = urb->dev->hcpriv;
-	int			last = -1;
-	unsigned		now, span, end;
-
-	span = urb->interval * urb->number_of_packets;
-
-	/* first see if we know when the next transfer SHOULD happen */
-	list_for_each (lh, &dev->urb_list) {
-		struct urb	*u;
-		struct ehci_itd	*itd;
-		unsigned	s;
+	struct ehci_iso_stream	*stream
+)
+{
+	u32			now, start, end, max;
+	int			status;
+	unsigned		mod = ehci->periodic_size << 3;
+	struct ehci_itd_sched	*itd_sched = urb->hcpriv;
 
-		u = list_entry (lh, struct urb, urb_list);
-		if (u == urb || u->pipe != urb->pipe)
-			continue;
-		if (u->interval != urb->interval) {	/* must not change! */ 
-			dbg ("urb %p interval %d ... != %p interval %d",
-				u, u->interval, urb, urb->interval);
-			return -EINVAL;
-		}
-		
-		/* URB for this endpoint... covers through when?  */
-		itd = urb->hcpriv;
-		s = itd->uframe + u->interval * u->number_of_packets;
-		if (last < 0)
-			last = s;
-		else {
-			/*
-			 * So far we can only queue two ISO URBs...
-			 *
-			 * FIXME do interval math, figure out whether
-			 * this URB is "before" or not ... also, handle
-			 * the case where the URB might have completed,
-			 * but hasn't yet been processed.
-			 */
-			dbg ("NYET: queue >2 URBs per ISO endpoint");
-			return -EDOM;
-		}
+	if (unlikely (itd_sched->span > (mod - 8 * SCHEDULE_SLOP))) {
+		ehci_dbg (ehci, "iso request %p too long\n", urb);
+		status = -EFBIG;
+		goto fail;
 	}
 
-	/* calculate the legal range [start,max) */
-	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_sched)
-		now += 8;				/* startup delay */
-	now %= mod;
-	end = now + mod;
-	if (last < 0) {
-		*start = now + ehci->i_thresh + /* paranoia */ 1;
-		*max = end - span;
-		if (*max < *start + 1)
-			*max = *start + 1;
-	} else {
-		*start = last % mod;
-		*max = (last + 1) % mod;
-	}
+	now = readl (&ehci->regs->frame_index) % mod;
 
-	/* explicit start frame? */
-	if (!(urb->transfer_flags & URB_ISO_ASAP)) {
-		unsigned	temp;
-
-		/* sanity check: must be in range */
-		urb->start_frame %= ehci->periodic_size;
-		temp = urb->start_frame << 3;
-		if (temp < *start)
-			temp += mod;
-		if (temp > *max)
-			return -EDOM;
-
-		/* use that explicit start frame */
-		*start = urb->start_frame << 3;
-		temp += 8;
-		if (temp < *max)
-			*max = temp;
+	/* when's the last uframe this urb could start? */
+	max = now + mod;
+	max -= itd_sched->span;
+	max -= 8 * SCHEDULE_SLOP;
+
+	/* typical case: reuse current schedule. stream is still active,
+	 * and no gaps from host falling behind (irq delays etc)
+	 */
+	if (likely (!list_empty (&stream->itd_list))) {
+
+		start = stream->next_uframe;
+		if (start < now)
+			start += mod;
+		if (likely (start < max))
+			goto ready;
+
+		/* two cases:
+		 * (a) we missed some uframes ... can reschedule
+		 * (b) trying to overcommit the schedule
+		 * FIXME (b) should be a hard failure
+		 */
 	}
 
-	// FIXME minimize wraparound to "now" ... insist max+span
-	// (and start+span) remains a few frames short of "end"
+	/* need to schedule; when's the next (u)frame we could start?
+	 * this is bigger than ehci->i_thresh allows; scheduling itself
+	 * isn't free, the slop should handle reasonably slow cpus.  it
+	 * can also help high bandwidth if the dma and irq loads don't
+	 * jump until after the queue is primed.
+	 */
+	start = SCHEDULE_SLOP * 8 + (now & ~0x07);
+	end = start;
 
-	*max %= ehci->periodic_size;
-	if ((*start + span) < end)
-		return 0;
-	return -EFBIG;
-}
+	ehci_vdbg (ehci, "%s schedule from %d (%d..%d), was %d\n",
+			__FUNCTION__, now, start, max,
+			stream->next_uframe);
 
-static int
-itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
-{
-	unsigned	start, max, i;
-	int		status;
-	unsigned	mod = ehci->periodic_size << 3;
+	/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
 
-	for (i = 0; i < urb->number_of_packets; i++) {
-		urb->iso_frame_desc [i].status = -EINPROGRESS;
-		urb->iso_frame_desc [i].actual_length = 0;
-	}
+	if (likely (max > (start + urb->interval)))
+		max = start + urb->interval;
 
-	if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
-		return status;
+	/* hack:  account for itds already scheduled to this endpoint */
+	if (unlikely (list_empty (&stream->itd_list)))
+		end = max;
 
+	/* within [start..max] find a uframe slot with enough bandwidth */
+	end %= mod;
 	do {
 		unsigned	uframe;
-		unsigned	usecs;
-		struct ehci_itd	*itd;
+		int		enough_space = 1;
 
 		/* check schedule: enough space? */
-		itd = urb->hcpriv;
 		uframe = start;
-		for (i = 0, uframe = start;
-				i < urb->number_of_packets;
-				i++, uframe += urb->interval) {
+		do {
 			uframe %= mod;
 
 			/* can't commit more than 80% periodic == 100 usec */
 			if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
-					> (100 - itd->usecs)) {
-				itd = 0;
+					> (100 - stream->usecs)) {
+				enough_space = 0;
 				break;
 			}
-			itd = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		}
-		if (!itd)
-			continue;
-		
-		/* that's where we'll schedule this! */
-		itd = urb->hcpriv;
-		urb->start_frame = start >> 3;
-		vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
-			urb, urb->number_of_packets, urb->interval,
-			urb->start_frame, start & 0x7);
-		for (i = 0, uframe = start, usecs = 0;
-				i < urb->number_of_packets;
-				i++, uframe += urb->interval) {
-			uframe %= mod;
-
-			itd->uframe = uframe;
-			itd->hw_transaction [uframe & 0x07] = itd->transaction;
-			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
-				itd);
-			wmb ();
-			usecs += itd->usecs;
-
-			itd = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		}
 
-		/* update bandwidth utilization records (for usbfs)
-		 *
-		 * FIXME This claims each URB queued to an endpoint, as if
-		 * transfers were concurrent, not sequential.  So bandwidth
-		 * typically gets double-billed ... comes from tying it to
-		 * URBs rather than endpoints in the schedule.  Luckily we
-		 * don't use this usbfs data for serious decision making.
-		 */
-		usecs /= urb->number_of_packets;
-		usecs /= urb->interval;
-		usecs >>= 3;
-		if (usecs < 1)
-			usecs = 1;
-		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
-
-		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_sched++) {
-			if ((status =  enable_periodic (ehci)) != 0) {
-				// FIXME deschedule right away
-				err ("itd_schedule, enable = %d", status);
+			/* we know urb->interval is 2^N uframes */
+			uframe += urb->interval;
+		} while (uframe != end);
+
+		/* (re)schedule it here if there's enough bandwidth */
+		if (enough_space) {
+			start %= mod;
+			if (unlikely (!list_empty (&stream->itd_list))) {
+				/* host fell behind ... maybe irq latencies
+				 * delayed this request queue for too long.
+				 */
+				stream->rescheduled++;
+				pr_debug ("ehci %s devpath %d "
+					"iso%d%s %d.%d skip %d.%d\n",
+					ehci->pdev->slot_name,
+					urb->dev->devpath,
+					stream->bEndpointAddress & 0x0f,
+					(stream->bEndpointAddress & USB_DIR_IN)
+						? "in" : "out",
+					stream->next_uframe >> 3,
+					stream->next_uframe & 0x7,
+					start >> 3, start & 0x7);
 			}
+			stream->next_uframe = start;
+			goto ready;
 		}
 
-		return 0;
-
-	} while ((start = ++start % mod) != max);
+	} while (++start < max);
 
 	/* no room in the schedule */
-	dbg ("urb %p, CAN'T SCHEDULE", urb);
-	return -ENOSPC;
+	ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n",
+		list_empty (&stream->itd_list) ? "" : "re",
+		urb, now, end, max);
+	status = -ENOSPC;
+
+fail:
+	itd_sched_free (stream, itd_sched);
+	urb->hcpriv = 0;
+	return status;
+
+ready:
+	urb->start_frame = stream->next_uframe;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
+static inline void
+itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
+{
+	int i;
+
+	itd->hw_next = EHCI_LIST_END;
+	itd->hw_bufp [0] = stream->buf0;
+	itd->hw_bufp [1] = stream->buf1;
+	itd->hw_bufp [2] = stream->buf2;
+
+	for (i = 0; i < 8; i++)
+		itd->index[i] = -1;
+
+	/* All other fields are filled when scheduling */
+}
+
+static inline void
+itd_patch (
+	struct ehci_itd		*itd,
+	struct ehci_itd_sched	*itd_sched,
+	unsigned		index,
+	u16			uframe,
+	int			first
+)
+{
+	struct ehci_iso_uframe	*uf = &itd_sched->packet [index];
+	unsigned		pg = itd->pg;
+
+	// BUG_ON (pg == 6 && uf->cross);
+
+	uframe &= 0x07;
+	itd->index [uframe] = index;
+
+	itd->hw_transaction [uframe] = uf->transaction;
+	itd->hw_transaction [uframe] |= cpu_to_le32 (pg << 12);
+	itd->hw_bufp [pg] |= cpu_to_le32 (uf->bufp & ~(u32)0);
+	itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
+
+	/* iso_frame_desc[].offset must be strictly increasing */
+	if (unlikely (!first && uf->cross)) {
+		u64	bufp = uf->bufp + 4096;
+		itd->pg = ++pg;
+		itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
+		itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(bufp >> 32));
+	}
+}
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
+	itd->itd_next = ehci->pshadow [frame];
+	itd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].itd = itd;
+	itd->frame = frame;
+	wmb ();
+	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
+
+/* fit urb's itds into the selected schedule slot; activate as needed */
+static int
+itd_link_urb (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		mod,
+	struct ehci_iso_stream	*stream
+)
+{
+	int			packet, first = 1;
+	unsigned		next_uframe, uframe, frame;
+	struct ehci_itd_sched	*itd_sched = urb->hcpriv;
+	struct ehci_itd		*itd;
+
+	next_uframe = stream->next_uframe % mod;
+
+	if (unlikely (list_empty(&stream->itd_list))) {
+		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+				+= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
+			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+			urb->interval,
+			next_uframe >> 3, next_uframe & 0x7);
+		stream->start = jiffies;
+	}
+	hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++;
+
+	/* fill iTDs uframe by uframe */
+	for (packet = 0, itd = 0; packet < urb->number_of_packets; ) {
+		if (itd == 0) {
+			/* ASSERT:  we have all necessary itds */
+			// BUG_ON (list_empty (&itd_sched->itd_list));
+
+			/* ASSERT:  no itds for this endpoint in this uframe */
+
+			itd = list_entry (itd_sched->itd_list.next,
+					struct ehci_itd, itd_list);
+			list_move_tail (&itd->itd_list, &stream->itd_list);
+			itd->stream = iso_stream_get (stream);
+			itd->urb = usb_get_urb (urb);
+			first = 1;
+			itd_init (stream, itd);
+		}
+
+		uframe = next_uframe & 0x07;
+		frame = next_uframe >> 3;
+
+		itd->usecs [uframe] = stream->usecs;
+		itd_patch (itd, itd_sched, packet, uframe, first);
+		first = 0;
+
+		next_uframe += stream->interval;
+		next_uframe %= mod;
+		packet++;
+
+		/* link completed itds into the schedule */
+		if (((next_uframe >> 3) != frame)
+				|| packet == urb->number_of_packets) {
+			itd_link (ehci, frame % ehci->periodic_size, itd);
+			itd = 0;
+		}
+	}
+	stream->next_uframe = next_uframe;
+
+	/* don't need that schedule data any more */
+	itd_sched_free (stream, itd_sched);
+	urb->hcpriv = 0;
+
+	if (unlikely (!ehci->periodic_sched++))
+		return enable_periodic (ehci);
+	return 0;
+}
+
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
 static unsigned
 itd_complete (
 	struct ehci_hcd	*ehci,
 	struct ehci_itd	*itd,
-	unsigned	uframe,
 	struct pt_regs	*regs
 ) {
 	struct urb				*urb = itd->urb;
 	struct usb_iso_packet_descriptor	*desc;
 	u32					t;
+	unsigned				uframe;
+	int					urb_index = -1;
+	struct ehci_iso_stream			*stream = itd->stream;
+	struct usb_device			*dev;
+
+	/* for each uframe with a packet */
+	for (uframe = 0; uframe < 8; uframe++) {
+		if (likely (itd->index[uframe] == -1))
+			continue;
+		urb_index = itd->index[uframe];
+		desc = &urb->iso_frame_desc [urb_index];
 
-	/* update status for this uframe's transfers */
-	desc = &urb->iso_frame_desc [itd->index];
+		t = le32_to_cpup (&itd->hw_transaction [uframe]);
+		itd->hw_transaction [uframe] = 0;
 
-	t = itd->hw_transaction [uframe];
-	itd->hw_transaction [uframe] = 0;
-	if (t & EHCI_ISOC_ACTIVE)
-		desc->status = -EXDEV;
-	else if (t & ISO_ERRS) {
-		urb->error_count++;
-		if (t & EHCI_ISOC_BUF_ERR)
-			desc->status = usb_pipein (urb->pipe)
-				? -ENOSR  /* couldn't read */
-				: -ECOMM; /* couldn't write */
-		else if (t & EHCI_ISOC_BABBLE)
-			desc->status = -EOVERFLOW;
-		else /* (t & EHCI_ISOC_XACTERR) */
-			desc->status = -EPROTO;
-
-		/* HC need not update length with this error */
-		if (!(t & EHCI_ISOC_BABBLE))
-			desc->actual_length += EHCI_ITD_LENGTH (t);
-	} else {
-		desc->status = 0;
-		desc->actual_length += EHCI_ITD_LENGTH (t);
+		/* report transfer status */
+		if (unlikely (t & ISO_ERRS)) {
+			urb->error_count++;
+			if (t & EHCI_ISOC_BUF_ERR)
+				desc->status = usb_pipein (urb->pipe)
+					? -ENOSR  /* hc couldn't read */
+					: -ECOMM; /* hc couldn't write */
+			else if (t & EHCI_ISOC_BABBLE)
+				desc->status = -EOVERFLOW;
+			else /* (t & EHCI_ISOC_XACTERR) */
+				desc->status = -EPROTO;
+
+			/* HC need not update length with this error */
+			if (!(t & EHCI_ISOC_BABBLE))
+				desc->actual_length = EHCI_ITD_LENGTH (t);
+		} else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
+			desc->status = 0;
+			desc->actual_length = EHCI_ITD_LENGTH (t);
+		}
 	}
 
-	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
-		itd, urb, itd->index + 1, urb->number_of_packets,
-		t, desc->status, desc->actual_length);
+	usb_put_urb (urb);
+	itd->urb = 0;
+	itd->stream = 0;
+	list_move (&itd->itd_list, &stream->free_itd_list);
+	iso_stream_put (ehci, stream);
 
 	/* handle completion now? */
-	if ((itd->index + 1) != urb->number_of_packets)
+	if (likely ((urb_index + 1) != urb->number_of_packets))
 		return 0;
 
-	/*
-	 * Always give the urb back to the driver ... expect it to submit
-	 * a new urb (or resubmit this), and to have another already queued
-	 * when un-interrupted transfers are needed.
-	 *
-	 * NOTE that for now we don't accelerate ISO unlinks; they just
-	 * happen according to the current schedule.  Means a delay of
-	 * up to about a second (max).
+	/* ASSERT: it's really the last itd for this urb
+	list_for_each_entry (itd, &stream->itd_list, itd_list)
+		BUG_ON (itd->urb == urb);
 	 */
-	itd_free_list (ehci, urb);
-	if (urb->status == -EINPROGRESS)
-		urb->status = 0;
-
-	/* complete() can reenter this HCD */
-	spin_unlock (&ehci->lock);
-	usb_hcd_giveback_urb (&ehci->hcd, urb, regs);
-	spin_lock (&ehci->lock);
+
+	/* give urb back to the driver ... can be out-of-order */
+	//dev = usb_get_dev (urb->dev);
+	dev = urb->dev;
+	ehci_urb_done (ehci, urb, regs);
+	urb = 0;
 
 	/* defer stopping schedule; completion can submit */
 	ehci->periodic_sched--;
-	if (!ehci->periodic_sched)
+	if (unlikely (!ehci->periodic_sched))
 		(void) disable_periodic (ehci);
+	hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--;
+
+	if (unlikely (list_empty (&stream->itd_list))) {
+		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
+				-= stream->bandwidth;
+		ehci_vdbg (ehci,
+			"deschedule devp %s ep%d%s-iso\n",
+			dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+	}
+	iso_stream_put (ehci, stream);
+	//usb_put_dev (dev);
 
 	return 1;
 }
@@ -939,23 +1170,50 @@
 
 static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 {
-	int		status;
-	unsigned long	flags;
+	int			status = -EINVAL;
+	unsigned long		flags;
+	struct ehci_iso_stream	*stream;
 
-	dbg ("itd_submit urb %p", urb);
+	/* Get iso_stream head */
+	stream = iso_stream_find (ehci, urb);
+	if (unlikely (stream == 0)) {
+		ehci_dbg (ehci, "can't get iso stream\n");
+		return -ENOMEM;
+	}
+	if (unlikely (urb->interval != stream->interval)) {
+		ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+			stream->interval, urb->interval);
+		goto done;
+	}
+
+#ifdef EHCI_URB_TRACE
+	ehci_dbg (ehci,
+		"%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n",
+		__FUNCTION__, urb->dev->devpath, urb,
+		usb_pipeendpoint (urb->pipe),
+		usb_pipein (urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length,
+		urb->number_of_packets, urb->interval,
+		stream);
+#endif
 
 	/* allocate ITDs w/o locking anything */
-	status = itd_urb_transaction (ehci, urb, mem_flags);
-	if (status < 0)
-		return status;
+	status = itd_urb_transaction (stream, ehci, urb, mem_flags);
+	if (unlikely (status < 0)) {
+		ehci_dbg (ehci, "can't init itds\n");
+		goto done;
+	}
 
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
-	status = itd_schedule (ehci, urb);
+	status = itd_stream_schedule (ehci, urb, stream);
+ 	if (likely (status == 0))
+		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (status < 0)
-		itd_free_list (ehci, urb);
 
+done:
+	if (unlikely (status < 0))
+		iso_stream_put (ehci, stream);
 	return status;
 }
 
@@ -986,24 +1244,23 @@
 	 * When running, scan from last scan point up to "now"
 	 * else clean up by scanning everything that's left.
 	 * Touches as few pages as possible:  cache-friendly.
-	 * Don't scan ISO entries more than once, though.
 	 */
-	frame = ehci->next_uframe >> 3;
+	now_uframe = ehci->next_uframe;
 	if (HCD_IS_RUNNING (ehci->hcd.state))
-		now_uframe = readl (&ehci->regs->frame_index);
+		clock = readl (&ehci->regs->frame_index) % mod;
 	else
-		now_uframe = (frame << 3) - 1;
-	now_uframe %= mod;
-	clock = now_uframe >> 3;
+		clock = now_uframe + mod - 1;
 
 	for (;;) {
 		union ehci_shadow	q, *q_p;
 		u32			type, *hw_p;
 		unsigned		uframes;
 
+		frame = now_uframe >> 3;
 restart:
 		/* scan schedule to _before_ current frame index */
-		if (frame == clock)
+		if ((frame == (clock >> 3))
+				&& HCD_IS_RUNNING (ehci->hcd.state))
 			uframes = now_uframe & 0x07;
 		else
 			uframes = 8;
@@ -1043,34 +1300,31 @@
 			case Q_TYPE_ITD:
 				last = (q.itd->hw_next == EHCI_LIST_END);
 
-				/* Unlink each (S)ITD we see, since the ISO
-				 * URB model forces constant rescheduling.
-				 * That complicates sharing uframes in ITDs,
-				 * and means we need to skip uframes the HC
-				 * hasn't yet processed.
-				 */
-				for (uf = 0; uf < uframes; uf++) {
-					if (q.itd->hw_transaction [uf] != 0) {
-						temp = q;
-						*q_p = q.itd->itd_next;
-						*hw_p = q.itd->hw_next;
-						type = Q_NEXT_TYPE (*hw_p);
-
-						/* might free q.itd ... */
-						count += itd_complete (ehci,
-							temp.itd, uf, regs);
-						break;
-					}
-				}
-				/* we might skip this ITD's uframe ... */
-				if (uf == uframes) {
+				/* skip itds for later in the frame */
+				rmb ();
+				for (uf = uframes; uf < 8; uf++) {
+					if (0 == (q.itd->hw_transaction [uf]
+							& ISO_ACTIVE))
+						continue;
 					q_p = &q.itd->itd_next;
 					hw_p = &q.itd->hw_next;
 					type = Q_NEXT_TYPE (q.itd->hw_next);
+					q = *q_p;
+					break;
 				}
+				if (uf != 8)
+					break;
 
-				q = *q_p;
-				break;
+				/* this one's ready ... HC won't cache the
+				 * pointer for much longer, if at all.
+				 */
+				*q_p = q.itd->itd_next;
+				*hw_p = q.itd->hw_next;
+				wmb();
+
+				/* always rescan here; simpler */
+				count += itd_complete (ehci, q.itd, regs);
+				goto restart;
 #ifdef have_split_iso
 			case Q_TYPE_SITD:
 				last = (q.sitd->hw_next == EHCI_LIST_END);
@@ -1104,7 +1358,7 @@
 
 		// FIXME:  likewise assumes HC doesn't halt mid-scan
 
-		if (frame == clock) {
+		if (now_uframe == clock) {
 			unsigned	now;
 
 			if (!HCD_IS_RUNNING (ehci->hcd.state))
@@ -1115,9 +1369,13 @@
 				break;
 
 			/* rescan the rest of this frame, then ... */
-			now_uframe = now;
-			clock = now_uframe >> 3;
-		} else
-			frame = (frame + 1) % ehci->periodic_size;
+			clock = now;
+		} else {
+			/* FIXME sometimes we can scan the next frame
+			 * right away, not always inching up on it ...
+			 */
+			now_uframe++;
+			now_uframe %= mod;
+		}
 	} 
 }
diff -urN linux-2.4.25-pre7/drivers/usb/host/ehci.h linux-2.4.25-pre8/drivers/usb/host/ehci.h
--- linux-2.4.25-pre7/drivers/usb/host/ehci.h	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/ehci.h	2004-01-29 10:58:21.000000000 -0800
@@ -153,9 +153,12 @@
 
 /* Section 2.2 Host Controller Capability Registers */
 struct ehci_caps {
-	u8		length;		/* CAPLENGTH - size of this struct */
-	u8		reserved;       /* offset 0x1 */
-	u16		hci_version;    /* HCIVERSION - offset 0x2 */
+	/* these fields are specified as 8 and 16 bit registers,
+	 * but some hosts can't perform 8 or 16 bit PCI accesses.
+	 */
+	u32	hc_capbase;
+#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
+#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
 	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
 #define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
 #define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
@@ -378,11 +381,68 @@
 	unsigned short		period;		/* polling interval */
 	unsigned short		start;		/* where polling starts */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
-
+	struct usb_device	*dev;		/* access to TT */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
 
+/* description of one iso highspeed transaction (up to 3 KB data) */
+struct ehci_iso_uframe {
+	/* These will be copied to iTD when scheduling */
+	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
+	u32			transaction;	/* itd->hw_transaction[i] |= */
+	u8			cross;		/* buf crosses pages */
+};
+
+/* temporary schedule data for highspeed packets from iso urbs
+ * each packet is one uframe's usb transactions, in some itd,
+ * beginning at stream->next_uframe
+ */
+struct ehci_itd_sched {
+	struct list_head	itd_list;
+	unsigned		span;
+	struct ehci_iso_uframe	packet [0];
+};
+
+/*
+ * ehci_iso_stream - groups all (s)itds for this endpoint.
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+struct ehci_iso_stream {
+	/* first two fields match QH, but info1 == 0 */
+	u32			hw_next;
+	u32			hw_info1;
+
+	u32			refcount;
+	u8			bEndpointAddress;
+	struct list_head	itd_list;	/* queued itds */
+	struct list_head	free_itd_list;	/* list of unused itds */
+	struct hcd_dev		*dev;
+
+	/* output of (re)scheduling */
+	unsigned long		start;		/* jiffies */
+	unsigned long		rescheduled;
+	int			next_uframe;
+
+	/* the rest is derived from the endpoint descriptor,
+	 * trusting urb->interval == (1 << (epdesc->bInterval - 1)),
+	 * including the extra info for hw_bufp[0..2]
+	 */
+	u8			interval;
+	u8			usecs;		
+	u16			maxp;
+	unsigned		bandwidth;
+
+	/* This is used to initialize iTD's hw_bufp fields */
+	u32			buf0;		
+	u32			buf1;		
+	u32			buf2;
+
+	/* ... sITD won't use buf[012], and needs TT access ... */
+};
+
+/*-------------------------------------------------------------------------*/
+
 /*
  * EHCI Specification 0.95 Section 3.3
  * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
@@ -397,9 +457,11 @@
 #define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
 #define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
 #define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
-#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
 #define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
 
+#define ISO_ACTIVE	__constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+
 	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
 	u32			hw_bufp_hi [7];	/* Appendix B */
 
@@ -408,14 +470,14 @@
 	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
 
 	struct urb		*urb;
-	struct list_head	itd_list;	/* list of urb frames' itds */
-	dma_addr_t		buf_dma;	/* frame's buffer address */
+	struct ehci_iso_stream	*stream;	/* endpoint's queue */
+	struct list_head	itd_list;	/* list of stream's itds */
 
-	/* for now, only one hw_transaction per itd */
-	u32			transaction;
-	u16			index;		/* in urb->iso_frame_desc */
-	u16			uframe;		/* in periodic schedule */
-	u16			usecs;
+	/* any/all hw_transactions here may be used by that urb */
+	unsigned		frame;		/* where scheduled */
+	unsigned		pg;
+	unsigned		index[8];	/* in urb->iso_frame_desc */
+	u8			usecs[8];
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -urN linux-2.4.25-pre7/drivers/usb/host/sl811.c linux-2.4.25-pre8/drivers/usb/host/sl811.c
--- linux-2.4.25-pre7/drivers/usb/host/sl811.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/host/sl811.c	2004-01-29 10:58:21.000000000 -0800
@@ -652,7 +652,7 @@
 {
 	struct sl811_urb_priv *urbp;
 	
-	urbp = kmalloc(sizeof(*urbp), GFP_KERNEL);
+	urbp = kmalloc(sizeof(*urbp), GFP_ATOMIC);
 	if (!urbp)
 		return NULL;
 	
@@ -763,7 +763,7 @@
 	struct sl811_urb_priv *urbp = urb->hcpriv;
 	struct sl811_td *td;
 	
-	td = kmalloc(sizeof (*td), GFP_KERNEL);
+	td = kmalloc(sizeof (*td), GFP_ATOMIC);
 	if (!td)
 		return NULL;
 	
diff -urN linux-2.4.25-pre7/drivers/usb/host/usb-ohci.c linux-2.4.25-pre8/drivers/usb/host/usb-ohci.c
--- linux-2.4.25-pre7/drivers/usb/host/usb-ohci.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/host/usb-ohci.c	2004-01-29 10:58:21.000000000 -0800
@@ -628,7 +628,7 @@
 
 	/* allocate the private part of the URB */
 	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
-							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+							in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
 	if (!urb_priv) {
 		usb_dec_dev_use (urb->dev);	
 		return -ENOMEM;
diff -urN linux-2.4.25-pre7/drivers/usb/host/usb-ohci.h linux-2.4.25-pre8/drivers/usb/host/usb-ohci.h
--- linux-2.4.25-pre7/drivers/usb/host/usb-ohci.h	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/host/usb-ohci.h	2004-01-29 10:58:21.000000000 -0800
@@ -439,7 +439,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define ALLOC_FLAGS (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
+#define ALLOC_FLAGS (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_NOIO)
 
 #ifdef DEBUG
 #	define OHCI_MEM_FLAGS	SLAB_POISON
diff -urN linux-2.4.25-pre7/drivers/usb/host/usb-uhci.c linux-2.4.25-pre8/drivers/usb/host/usb-uhci.c
--- linux-2.4.25-pre7/drivers/usb/host/usb-uhci.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/host/usb-uhci.c	2004-01-29 10:58:21.000000000 -0800
@@ -88,8 +88,8 @@
 	static kmem_cache_t *urb_priv_kmem;
 #endif
 
-#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
+#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_NOIO)
+#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_NOIO)
 
 /* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
  * Reclamation: feature that puts loop on descriptor loop when
diff -urN linux-2.4.25-pre7/drivers/usb/inode.c linux-2.4.25-pre8/drivers/usb/inode.c
--- linux-2.4.25-pre7/drivers/usb/inode.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/inode.c	2004-01-29 10:58:21.000000000 -0800
@@ -158,9 +158,7 @@
 	inode->i_uid = inode->i_gid = 0;
 	inode->i_size = 0;
 	list_del(&inode->u.usbdev_i.slist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
 	list_del(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
 	iput(inode);
 }
 
@@ -512,8 +510,6 @@
 	inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
 	inode->i_mode = S_IFREG;
 	inode->i_gid = inode->i_uid = 0;
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
 	inode->u.usbdev_i.p.dev = NULL;
 	inode->u.usbdev_i.p.bus = NULL;
 	switch (ITYPE(inode->i_ino)) {
diff -urN linux-2.4.25-pre7/drivers/usb/serial/ir-usb.c linux-2.4.25-pre8/drivers/usb/serial/ir-usb.c
--- linux-2.4.25-pre7/drivers/usb/serial/ir-usb.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/serial/ir-usb.c	2004-01-29 10:58:21.000000000 -0800
@@ -568,7 +568,9 @@
 			case B115200:  ir_baud = SPEED_115200;  break;
 			case B576000:  ir_baud = SPEED_576000;  break;
 			case B1152000: ir_baud = SPEED_1152000; break;
+#ifdef B4000000
 			case B4000000: ir_baud = SPEED_4000000; break;
+#endif
 		}
 
 		if (xbof == -1) {
diff -urN linux-2.4.25-pre7/drivers/usb/serial/visor.c linux-2.4.25-pre8/drivers/usb/serial/visor.c
--- linux-2.4.25-pre7/drivers/usb/serial/visor.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/serial/visor.c	2004-01-29 10:58:21.000000000 -0800
@@ -212,6 +212,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
@@ -243,6 +244,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
diff -urN linux-2.4.25-pre7/drivers/usb/serial/visor.h linux-2.4.25-pre8/drivers/usb/serial/visor.h
--- linux-2.4.25-pre7/drivers/usb/serial/visor.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/serial/visor.h	2004-01-29 10:58:21.000000000 -0800
@@ -42,6 +42,7 @@
 #define SONY_CLIE_NX60_ID		0x00DA
 #define SONY_CLIE_NZ90V_ID		0x00E9
 #define SONY_CLIE_UX50_ID		0x0144
+#define SONY_CLIE_TJ25_ID		0x0169
 
 #define SAMSUNG_VENDOR_ID		0x04E8
 #define SAMSUNG_SCH_I330_ID		0x8001
diff -urN linux-2.4.25-pre7/drivers/usb/storage/transport.c linux-2.4.25-pre8/drivers/usb/storage/transport.c
--- linux-2.4.25-pre7/drivers/usb/storage/transport.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.25-pre8/drivers/usb/storage/transport.c	2004-01-29 10:58:21.000000000 -0800
@@ -1140,7 +1140,7 @@
 	US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
 		  le32_to_cpu(bcb->Signature), bcb->Tag,
 		  (bcb->Lun >> 4), (bcb->Lun & 0x0F), 
-		  bcb->DataTransferLength, bcb->Flags, bcb->Length);
+		  le32_to_cpu(bcb->DataTransferLength), bcb->Flags, bcb->Length);
 	result = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, 
 				   &partial);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
diff -urN linux-2.4.25-pre7/drivers/usb/storage/unusual_devs.h linux-2.4.25-pre8/drivers/usb/storage/unusual_devs.h
--- linux-2.4.25-pre7/drivers/usb/storage/unusual_devs.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/storage/unusual_devs.h	2004-01-29 10:58:21.000000000 -0800
@@ -45,13 +45,6 @@
  *
  */
 
-/* Patch submitted by Martin Berentsen <berentsen at sent5 dot uni-duisburg dot de> */
-#define US_FL_START_STOP  0x00000004   /* ignore START_STOP commands     */
-UNUSUAL_DEV(  0x0686, 0x4014, 0x0001, 0x0001, 
-		"Minolta",
-		"Dimage S414",
-		US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), 
-
 UNUSUAL_DEV(  0x03ee, 0x0000, 0x0000, 0x0245, 
 		"Mitsumi",
 		"CD-R/RW Drive",
@@ -296,7 +289,7 @@
 UNUSUAL_DEV(  0x054c, 0x006d, 0x0000, 0x9999,
 		"Sony",
 		"PEG Mass Storage",
-		US_SC_8070, US_PR_CBI, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 		
 UNUSUAL_DEV(  0x057b, 0x0000, 0x0000, 0x0299, 
@@ -377,7 +370,7 @@
 UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff, 
 		"", 
 		"USB TO IDE",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_SCSI, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ), 
 
 /* Reported by Peter Marks <peter.marks@turner.com>
@@ -489,11 +482,6 @@
 		"Freecom",
 		"USB-IDE",
 		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
-
-UNUSUAL_DEV(  0x07ab, 0xfc84, 0x0000, 0x9999,
-		"Freecom",
-		"FX-5/FX-50",
-		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
 #endif
 
 UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133, 
@@ -639,11 +627,19 @@
 		"3MegaCam",
 		US_SC_DEVICE, US_PR_BULK, NULL,
 		US_FL_MODE_XLATE ),
+
+/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
+UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
+		"Trumpion",
+		"MP3 player",
+		US_SC_RBC, US_PR_BULK, NULL,
+		US_FL_MODE_XLATE),
+
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
 		"Feiya",
 		"5-in-1 Card Reader",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
 UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x0001,
@@ -671,6 +667,13 @@
                 US_SC_DEVICE, US_PR_DEVICE, NULL,
                 US_FL_FIX_INQUIRY ),
 
+/* This entry from <matthias@ma-c.de> in the Debian mailing list */
+UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff,
+		"Pentax",
+		"Optio 330GS",
+		US_SC_8070, US_PR_CB, NULL,
+		US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ),
+
 /* Submitted by Per Winkvist <per.winkvist@uk.com> */
 UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
                 "Pentax",
@@ -703,6 +706,17 @@
 		"JD 5200 z3",
 		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
 
+/* Reported by Lubomir Blaha <tritol@trilogic.cz>
+ * I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
+ * works for me. Can anybody correct these values? (I able to test corrected
+ * version.)
+ */
+UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff,
+		"Netac",
+		"USB-CF-Card",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
 UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
 		"USB",
@@ -738,3 +752,12 @@
 		US_SC_SCSI, US_PR_SDDR55, NULL,
 		US_FL_SINGLE_LUN),
 #endif
+
+/* Patch for Kyocera Finecam L3
+ * Submitted by Michael Krauth <michael.krauth@web.de>
+ */
+UNUSUAL_DEV(  0x0482, 0x0105, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam L3",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY),
diff -urN linux-2.4.25-pre7/drivers/usb/storage/usb.c linux-2.4.25-pre8/drivers/usb/storage/usb.c
--- linux-2.4.25-pre7/drivers/usb/storage/usb.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/storage/usb.c	2004-01-29 10:58:21.000000000 -0800
@@ -728,6 +728,7 @@
 
 		/* allocate an IRQ callback if one is needed */
 		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) {
+			up(&(ss->dev_semaphore));
 			usb_dec_dev_use(dev);
 			return NULL;
 		}
@@ -735,6 +736,7 @@
 		/* allocate the URB we're going to use */
 		ss->current_urb = usb_alloc_urb(0);
 		if (!ss->current_urb) {
+			up(&(ss->dev_semaphore));
 			usb_dec_dev_use(dev);
 			return NULL;
 		}
diff -urN linux-2.4.25-pre7/drivers/usb/usb.c linux-2.4.25-pre8/drivers/usb/usb.c
--- linux-2.4.25-pre7/drivers/usb/usb.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.25-pre8/drivers/usb/usb.c	2004-01-29 10:58:21.000000000 -0800
@@ -1198,7 +1198,7 @@
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
 			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
-	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
 	int ret;
 	
 	if (!dr)
diff -urN linux-2.4.25-pre7/drivers/video/it8181fb.c linux-2.4.25-pre8/drivers/video/it8181fb.c
--- linux-2.4.25-pre7/drivers/video/it8181fb.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/drivers/video/it8181fb.c	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,1350 @@
+/*  IT8181 console frame buffer driver---it8181fb.c
+ *
+ *  Copyright (C) 2001 Integrated Technology Express, Inc.
+ *  Copyright (C) 2001 MontaVista Software Inc.
+ *  Copyright (C) 2002,2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *
+ *  Initial work by rich.liu@ite.com.tw
+ *
+ *  Rewritten by MontaVista Software, Inc.
+ *         	stevel@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * Changes:
+ * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
+ *	- Added support of NEC VR4111 and VR4121.
+ *	- rewrote it8181fb_set_par()
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#include "vga.h"
+
+static const struct {
+	int f_pix_l; // kHz
+	int f_pix_h; // kHz
+	int m, n, p;
+} std_pll_freq[] = {
+	{24923, 25427, 1, 14, 3}, // 25.175 MHz +- 1%
+	{31185, 31815, 3, 53, 3}, // 31.5 MHz +- 1%
+	{39600, 40400, 5, 56, 2}, // 40 MHz +- 1%
+	{49005, 49995, 6, 83, 2}, // 49.5 MHz +- 1%
+	{49500, 50500, 1, 14, 2}, // 50 MHz +- 1%
+	{64350, 65650, 9, 82, 1}, // 65 MHz +- 1%
+	{74250, 75750, 2, 21, 1}, // 75 MHz +- 1%
+	{0, 0, 0, 0, 0}
+};
+
+// FIXME: this is just a guess
+#define PLL_MAX_M		18
+
+#define IT8181_GUI_SIZE		0x8000L		/* 32kB */
+#define IT8181_MMIO_SIZE	0x10000L	/* 64kB */
+#define IT8181_FB_SIZE		0x400000L	/* 4MB  */
+#define IT8181_CFG_SIZE		0x50UL
+
+#define PICOS2KHZ(a)		(1000000000UL/(a))
+#define KHZ2PICOS(a)		(1000000000UL/(a))
+
+#define CLOCK_REF		14318 // KHz
+
+#define IT8181_STANDBY		0x44	/* Standby register */
+#define IT8181_PLL1		0x48	/* PLL1 register */
+#define IT8181_PLL2		0x4c	/* PLL2 register */
+
+#define IT8181_PLL1_RST		0x00004000	/* PLL1 reset */
+#define IT8181_PLL2_RST		0x00008000
+
+#define IT8181_MODULE_NAME	"IT8181"
+#define PFX IT8181_MODULE_NAME
+
+#undef IT8181_DEBUG
+
+#ifdef IT8181_DEBUG
+#define dbg(format, arg...) \
+    printk(__FUNCTION__ ": " format "\n" , ## arg)
+  //printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+#define emerg(format, arg...) printk(KERN_EMERG PFX ": " format "\n" , ## arg)
+
+#define CMAPSIZE		16
+#define arraysize(x)		(sizeof(x)/sizeof(*(x)))
+
+/*
+ * These are fb_var_screeninfo's for 640x480, 800x600, and
+ * 1024x768. The bpp field is filled in later.
+ */
+static const struct fb_var_screeninfo it8181_var_table[] = {
+	{	// 640x480@75, 31.5MHz dotclock
+		640, 480, 640, 480, 0, 0, -1, 0,
+		{0}, {0}, {0}, {0},
+		0, FB_ACTIVATE_NOW, -1, -1, 0,
+		31747, 120, 16, 16, 1, 64, 3,
+		0, FB_VMODE_NONINTERLACED },
+	{	// 800x600@72, 50.00MHz dotclock
+		800, 600, 800, 600, 0, 0, -1, 0,
+		{0}, {0}, {0}, {0},
+		0, FB_ACTIVATE_NOW, -1, -1, 0,
+		20000, 64, 56, 23, 37, 120, 6,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED },
+	{	// 1024x768@70, 75.00MHz dotclock
+		1024, 768, 1024, 768, 0, 0, -1, 0,
+		{0}, {0}, {0}, {0},
+		0, FB_ACTIVATE_NOW, -1, -1, 0,
+		13334, 144, 24, 29, 3, 136, 6,
+		0, FB_VMODE_NONINTERLACED }
+};
+
+enum {
+	RES_640x480 = 0,
+	RES_800x600,
+	RES_1024x768
+};
+
+/*
+ * The default resolution and color depth to use if
+ * none was specified on command line.
+ */
+#define DEFAULT_RES		RES_800x600
+#define DEFAULT_BPP		16
+#define DEFAULT_MEMORY_BASE	0
+#define DEFAULT_CONFIG_OFFSET	0
+
+static const char default_mode[] = "800x600-70";
+static char __initdata fontname[40] = { 0 };
+static const char *mode_option __initdata = NULL;
+static int default_bpp __initdata = DEFAULT_BPP;
+static int default_res __initdata = DEFAULT_RES;
+static int default_memory_base __initdata = DEFAULT_MEMORY_BASE;
+static int default_config_offset __initdata = DEFAULT_CONFIG_OFFSET;
+
+struct it8181fb_par {
+        struct fb_var_screeninfo var;
+
+        int HorizRes;          /* The x resolution in pixel */
+        int HorizTotal;
+        int HorizDispEnd;
+        int HorizBlankStart;
+        int HorizBlankEnd;
+        int HorizSyncStart;
+        int HorizSyncEnd;
+
+        int VertRes;           /* the physical y resolution in scanlines */
+        int VertTotal;
+        int VertDispEnd;
+        int VertSyncStart;
+        int VertSyncEnd;
+        int VertBlankStart;
+        int VertBlankEnd;
+	
+	int pll1_N, pll1_M, pll1_P; // PLL1 settings for pixel clock
+	int pll2_N, pll2_M, pll2_P; // PLL2 settings for memory clock
+	int pclk;                // pixel clock from above PLL settings, KHz
+	
+	int line_length;  // in bytes
+	int cmap_len;     // color-map length
+};
+
+struct it8181fb_info {
+        struct fb_info_gen gen;
+	struct it8181fb_par current_par;
+	struct pci_dev *pdev;
+        struct display disp;
+        unsigned int itConfigAddrVirt;
+        unsigned int itMmioAddrVirt;
+        unsigned int itFbAddrVirt;
+        unsigned int itGuiCtrlVirt;
+        unsigned int itMmioAddrPhys;
+        unsigned int itFbAddrPhys;
+        unsigned int itGuiCtrlPhys;
+	int blank_mode;
+	
+        struct it8181fb_info *next;
+};
+
+static struct it8181fb_info *fb_it8181;
+static u32 itMmioAddr;
+static int it8181fb_lcd;
+static int it8181fb_memory_type;
+
+static char it8181fb_name[16] = IT8181_MODULE_NAME;
+
+static union {
+#ifdef FBCON_HAS_CFB16
+	u16 cfb16[CMAPSIZE];
+#endif
+#ifdef FBCON_HAS_CFB24
+	u32 cfb24[CMAPSIZE];
+#endif
+#ifdef FBCON_HAS_CFB32
+	u32 cfb32[CMAPSIZE];
+#endif
+} fbcon_cmap;
+
+/* Interface used by the world */
+int it8181fb_init(void);
+int it8181fb_setup(char *options, int *ints);
+static int it8181fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info);
+
+/* Hardware Specific Routines */
+static void it8181fb_detect (void);
+static int it8181fb_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
+				struct fb_info_gen *info);
+static int it8181fb_decode_var (const struct fb_var_screeninfo *var, void *par,
+				struct fb_info_gen *info);
+static int it8181fb_encode_var (struct fb_var_screeninfo *var, const void *par,
+				struct fb_info_gen *info);
+static void it8181fb_get_par (void *par, struct fb_info_gen *info);
+static void it8181fb_set_par (const void *par, struct fb_info_gen *info);
+static int it8181fb_getcolreg (unsigned regno, unsigned *red, unsigned *green,
+			       unsigned *blue, unsigned *transp,
+			       struct fb_info *info);
+static int it8181fb_setcolreg (unsigned regno, unsigned red, unsigned green,
+                            unsigned blue, unsigned transp,
+			       struct fb_info *info);
+static int it8181fb_pan_display (const struct fb_var_screeninfo *var,
+				 struct fb_info_gen *info);
+static int it8181fb_blank (int blank_mode, struct fb_info_gen *info);
+static void it8181fb_set_disp (const void *par, struct display *disp,
+			       struct fb_info_gen *info);
+
+/* Internal routines */
+static void set_color_bitfields(struct fb_var_screeninfo *var);
+static int it8181fb_calc_pixclock(struct it8181fb_par* par);
+static void it8181SetPLL(const struct it8181fb_par* par,
+			 const struct it8181fb_info* info);
+
+/* function table of the above functions */
+static struct fb_ops it8181fb_ops = {
+        owner:          THIS_MODULE,
+        fb_get_fix:     fbgen_get_fix,
+        fb_get_var:     fbgen_get_var,
+        fb_set_var:     fbgen_set_var,
+        fb_get_cmap:    fbgen_get_cmap,
+        fb_set_cmap:    fbgen_set_cmap,
+        fb_pan_display: fbgen_pan_display,
+        fb_ioctl:       it8181fb_ioctl,
+};
+
+/* function table of the above functions */
+static struct fbgen_hwswitch it8181fb_hwswitch =
+{
+        it8181fb_detect,
+        it8181fb_encode_fix,
+        it8181fb_decode_var,
+        it8181fb_encode_var,
+        it8181fb_get_par,
+        it8181fb_set_par,
+        it8181fb_getcolreg,
+        it8181fb_setcolreg,
+        it8181fb_pan_display,
+        it8181fb_blank,
+        it8181fb_set_disp
+};
+
+static int itReadConfigDword(const struct it8181fb_info *info, int where, u32 *val)
+{
+	int result = 0;
+
+#ifdef CONFIG_PCI
+	if (info->pdev)
+		result =  pci_read_config_dword(info->pdev, where, val);
+	else
+#endif
+		*val = readl(info->itConfigAddrVirt + where);
+
+	return result;
+}
+
+static int itWriteConfigDword(const struct it8181fb_info *info, int where, u32 val)
+{
+	int result = 0;
+
+#ifdef CONFIG_PCI
+	if (info->pdev)
+		result =  pci_write_config_dword(info->pdev, where, val);
+	else
+#endif
+		writel(val, info->itConfigAddrVirt+ where);
+
+	return result;
+}
+
+static inline int itReadRegExtB(unsigned char addr)
+{	
+	writeb(addr,itMmioAddr+0x3ce);
+	return readb(itMmioAddr+0x3cf);
+}
+
+static inline void itWriteRegExtB(unsigned char addr, unsigned char value)
+{
+	int tmp;
+	writeb(addr,itMmioAddr+0x3ce);
+	writeb(value,itMmioAddr+0x3cf);
+	tmp = itReadRegExtB(addr);
+}
+
+static inline void itExtBLock(void)
+{
+	itWriteRegExtB(0x0b,0x35);
+	if (itReadRegExtB(0x0b) & 1)
+		dbg("ExtB still unlocked!");
+}
+
+static inline void itExtBUnlock(void)
+{
+	itWriteRegExtB(0x0b,0xca);
+	if (!(itReadRegExtB(0x0b) & 1))
+		dbg("ExtB still locked!");
+}
+
+static inline int itReadRegExtA(unsigned char addr)
+{	
+	writeb(addr,itMmioAddr+0x3d6);
+	return readb(itMmioAddr+0x3d7);
+}
+
+static inline void itWriteRegExtA(unsigned char addr,unsigned char value)
+{
+	int tmp;
+	writeb(addr,itMmioAddr+0x3d6);
+	writeb(value,itMmioAddr+0x3d7);
+	tmp = itReadRegExtA(addr);
+}
+
+static inline void itExtALock(void)
+{
+	itWriteRegExtA(0x0b,0xce);
+}
+
+static inline void itExtAUnlock(void)
+{
+	itWriteRegExtA(0x0b,0xec);
+}
+
+static inline int itReadRegCrtc(unsigned char addr)
+{
+	writeb(addr,itMmioAddr+VGA_CRT_IC);
+	return readb(itMmioAddr+VGA_CRT_DC);
+}
+
+static inline void itWriteRegCrtc(unsigned char addr,unsigned char value)
+{
+	int tmp;
+	writeb(addr,itMmioAddr+VGA_CRT_IC);
+	writeb(value,itMmioAddr+VGA_CRT_DC);
+	tmp = itReadRegCrtc(addr);
+}
+
+static inline uint8_t itReadRegMisc(void)
+{
+	return readb(itMmioAddr+VGA_MIS_R);
+}
+
+static inline void itWriteRegMisc(unsigned char value)
+{
+	writeb(value, itMmioAddr+VGA_MIS_W);		
+}
+
+static inline int itReadRegSEQ(unsigned char addr)
+{
+	writeb(addr, itMmioAddr+VGA_SEQ_I);
+	return readb(itMmioAddr+VGA_SEQ_D);
+}
+
+static inline void itWriteRegSEQ(unsigned char addr,unsigned char value)
+{
+	writeb(addr, itMmioAddr+VGA_SEQ_I);
+	writeb(value, itMmioAddr+VGA_SEQ_D);
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	case 1:
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 16:	/* RGB 565 */
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 24:	/* RGB 888 */
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:	/* RGBA 8888 */
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 16;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+}
+
+
+static void it8181fb_detect (void)
+{
+	dbg("");
+}
+
+static int it8181fb_encode_fix(struct fb_fix_screeninfo *fix,
+				const void* _par,
+				struct fb_info_gen* _info)
+{
+        struct it8181fb_par *par = (struct it8181fb_par *) _par;
+        struct it8181fb_info *info = (struct it8181fb_info *) _info;
+	struct fb_var_screeninfo* var = &par->var;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, it8181fb_name);
+
+	fix->smem_start = info->itFbAddrPhys;
+	fix->smem_len = IT8181_FB_SIZE;
+	fix->mmio_start = info->itMmioAddrPhys;
+	fix->mmio_len = IT8181_MMIO_SIZE;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+        fix->visual = (var->bits_per_pixel <= 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->line_length = par->line_length;
+
+	return 0;
+}
+
+static int  it8181fb_decode_var(const struct fb_var_screeninfo *var,
+				void *_par,
+				struct fb_info_gen *_info)
+{
+        struct it8181fb_par *par = (struct it8181fb_par *) _par;
+	int xres, rm, hsync, lm;
+	int yres, bm, vsync, um;
+	
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		dbg("double-scan modes not supported");
+		return -EINVAL;
+	}
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		dbg("interlaced modes not supported");
+		return -EINVAL;
+	}
+
+	if (!((var->xres == 640 && var->yres == 480) ||
+	      (var->xres == 800 && var->yres == 600) ||
+	      (var->xres == 1024 && var->yres == 768))) {
+		dbg("resolution not supported: %dx%d",
+		    var->xres, var->yres);
+		return -EINVAL;
+	}
+
+        memset (par, 0, sizeof (struct it8181fb_par));
+        par->var = *var;
+
+	switch (var->bits_per_pixel) {
+	case 2 ... 8:
+		par->var.bits_per_pixel = 8;
+		break;
+	case 9 ... 16:
+		par->var.bits_per_pixel = 16;
+		break;
+	case 17 ... 24:
+		par->var.bits_per_pixel = 24;
+		break;
+	case 25 ... 32:
+		par->var.bits_per_pixel = 32;
+		break;
+	default:
+		dbg("color depth %d bpp not supported", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	par->var.width = par->var.height = -1;
+	/* no virtual display for now (no panning/scrolling) */
+	par->var.xoffset = par->var.yoffset = 0;
+	par->var.xres_virtual = par->var.xres;
+	par->var.yres_virtual = par->var.yres;
+	/* no accels */
+	par->var.accel_flags = 0;
+	
+	set_color_bitfields(&par->var);
+	par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16;
+
+	/*
+	 *  check memory limit
+	 */
+	par->line_length =
+		par->var.xres_virtual * (par->var.bits_per_pixel>>3);
+	if (par->line_length * par->var.yres_virtual > IT8181_FB_SIZE) {
+		dbg("not enough video memory for virtual res %dx%dx%d!",
+		    par->var.xres_virtual, par->var.yres_virtual,
+		    par->var.bits_per_pixel);
+		return -ENOMEM;
+	}
+	
+	if (it8181fb_calc_pixclock(par)) {
+		return -EINVAL;
+	}
+	
+	xres = var->xres;
+	rm = var->right_margin;
+	hsync = var->hsync_len;
+	lm = var->left_margin;
+
+	yres = var->yres;
+	bm = var->lower_margin;
+	vsync = var->vsync_len;
+	um = var->upper_margin;
+
+	par->HorizRes = xres;
+	par->HorizTotal = (xres + rm + hsync + lm) / 8 - 5;
+	par->HorizDispEnd = xres / 8 - 1;
+	par->HorizBlankStart = xres / 8;
+	par->HorizBlankEnd = par->HorizTotal + 5; // does not count with "-5"
+	par->HorizSyncStart = (xres + rm) / 8 + 1;
+	par->HorizSyncEnd = (xres + rm + hsync) / 8 + 1;
+
+	par->VertRes = yres;
+	par->VertTotal = yres + bm + vsync + um - 2;
+	par->VertDispEnd = yres - 1;
+	par->VertBlankStart = yres;
+	par->VertBlankEnd = par->VertTotal;
+	par->VertSyncStart = yres + bm - 1;
+	par->VertSyncEnd = yres + bm + vsync - 1;
+
+	return 0;
+}
+
+static int  it8181fb_encode_var(struct fb_var_screeninfo *var,
+				const void *par,
+				struct fb_info_gen *info)
+{
+	*var = ((struct it8181fb_par *)par)->var;
+	return 0;
+}
+
+static void it8181fb_set_disp(const void *_par, struct display *disp,
+			      struct fb_info_gen *_info)
+{
+        struct it8181fb_par *par = (struct it8181fb_par *) _par;
+        struct it8181fb_info *info = (struct it8181fb_info *) _info;
+
+	disp->screen_base = (char *)info->itFbAddrVirt;
+
+	switch (par->var.bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		disp->dispsw = &fbcon_mfb;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
+		disp->dispsw = &fbcon_cfb2;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB4
+	case 4:
+		disp->dispsw = &fbcon_cfb4;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		disp->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = fbcon_cmap.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		disp->dispsw = &fbcon_cfb24;
+		disp->dispsw_data = fbcon_cmap.cfb24;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		disp->dispsw = &fbcon_cfb32;
+		disp->dispsw_data = fbcon_cmap.cfb32;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+		disp->dispsw_data = NULL;
+		break;
+	}
+}
+
+static int it8181fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info)
+{
+	/* nothing to do yet */
+	return -EINVAL;
+}
+
+static inline void it8181fb_panel_poweron(void)
+{
+	if (it8181fb_lcd != 0) {
+		itExtAUnlock();
+		itWriteRegExtA(0x9b, 0x01);
+		itExtALock();
+
+		mdelay(120);
+	}
+}
+
+static inline void it8181fb_panel_poweroff(void)
+{
+	if (it8181fb_lcd != 0) {
+		itExtAUnlock();
+		itWriteRegExtA(0x9b, 0x00);
+		itExtALock();
+
+		mdelay(120);
+	}
+}
+
+/*
+ *  Blank the display.
+ *
+ * 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off
+ */
+static int it8181fb_blank(int mode, struct fb_info_gen *_info)
+{
+	struct it8181fb_info *p = (struct it8181fb_info *)_info;
+
+        if (p->blank_mode == mode)
+                return 0;
+
+	itExtBUnlock();
+
+	mdelay(25);
+
+	switch (mode) {
+	case 0:
+		// turn display sync's back on
+		itWriteRegExtB(0x3c, 0x00);
+		itWriteRegSEQ(VGA_SEQ_CLOCK_MODE, 0); // unblank
+
+		it8181fb_panel_poweron();
+		break;
+	case 1:
+		// turn display sync's back on
+		itWriteRegExtB(0x3c, 0x00);
+                itWriteRegSEQ(VGA_SEQ_CLOCK_MODE, 0x20); // blank
+
+		it8181fb_panel_poweroff();
+		break;
+	case 2:
+                itWriteRegSEQ(VGA_SEQ_CLOCK_MODE, 0x20); // blank
+		itWriteRegExtB(0x3c, 0x08); // disable vsync
+
+		it8181fb_panel_poweroff();
+		break;
+	case 3:
+                itWriteRegSEQ(VGA_SEQ_CLOCK_MODE, 0x20); // blank
+		itWriteRegExtB(0x3c, 0x02); // disable hsync
+
+		it8181fb_panel_poweroff();
+		break;
+	case 4:
+                itWriteRegSEQ(VGA_SEQ_CLOCK_MODE, 0x20); // blank
+		itWriteRegExtB(0x3c, 0x0a); // disable sync
+
+		it8181fb_panel_poweroff();
+		break;
+	}
+
+	itExtBLock();
+
+	p->blank_mode = mode;
+
+	return 0;
+}
+
+static int it8181fb_calc_pixclock(struct it8181fb_par* par)
+{
+	int i;
+	int f_pix, f_actual;
+
+	/*
+	 * If the desired pixel clock is one of the standard
+	 * VESA frequencies, pull the {N,M,P} values from the
+	 * std_pll_freq[] table, otherwise we have to calculate
+	 * the {N,M,P} values.
+	 */
+
+	f_pix = PICOS2KHZ(par->var.pixclock);
+
+	for (i=0; std_pll_freq[i].f_pix_l; i++) {
+		if (f_pix >= std_pll_freq[i].f_pix_l &&
+		    f_pix <= std_pll_freq[i].f_pix_h) {
+			par->pll1_N = std_pll_freq[i].n;
+			par->pll1_M = std_pll_freq[i].m;
+			par->pll1_P = std_pll_freq[i].p;
+			break;
+		}
+	}
+
+	if (!std_pll_freq[i].f_pix_l) {
+		int r, N, M, P;
+		// Pixel clock is not one of the standard VESA frequencies.
+		if (f_pix < 2*CLOCK_REF)      P = 3;
+		else if (f_pix < 4*CLOCK_REF) P = 2;
+		else if (f_pix < 6*CLOCK_REF) P = 1;
+		else                          P = 0;
+		
+		r = ((1<<10) * f_pix * (1<<P)) / CLOCK_REF;
+		
+		if (r > 255*(1<<10) || r < (1<<10)/PLL_MAX_M) {
+			dbg("desired pixclock out of range");
+			return -EINVAL;
+		}
+		
+		if (r == (1<<10)) {
+			// r = 1.0
+			N = M = PLL_MAX_M;
+		} else if (r > (1<<10)) {
+			// r > 1.0
+			for (N=255; N>1; N--) {
+				// round-up
+				M = ((N*(1<<11) + (1<<10)) / r) / 2;
+				if (M <= PLL_MAX_M)
+					break;
+			}
+		} else {
+			// r < 1.0
+			M = PLL_MAX_M;
+			N = (PLL_MAX_M * r + (1<<9)) / (1<<10); // round-up
+		}
+		
+		par->pll1_N = N;
+		par->pll1_M = M;
+		par->pll1_P = P;
+	}
+	
+
+	f_actual = (par->pll1_N * CLOCK_REF) / (par->pll1_M * (1<<par->pll1_P));
+	
+	dbg("N=%d, M=%d, P=%d", par->pll1_N, par->pll1_M, par->pll1_P);
+	dbg("desired=%d KHz, actual=%d KHz, error=%d%%",
+	    f_pix, f_actual, (100*abs(f_actual - f_pix)) / f_pix);
+
+	par->var.pixclock = KHZ2PICOS(f_actual);
+	return 0;
+}
+
+static void it8181SetPLL(const struct it8181fb_par* par,
+			 const struct it8181fb_info* info)
+{
+	itWriteConfigDword(info, IT8181_STANDBY, 0x0000c000);
+
+	// program PLL1
+	itWriteConfigDword(info, IT8181_PLL1,
+	                   (par->pll1_P << 16) |
+	                   (((-par->pll1_N) & 0xff) << 8) |
+	                   (((-par->pll1_M) & 0x3f)));
+
+	// PLL2 = 49.5 MHz
+	itWriteConfigDword(info, IT8181_PLL2, 0x0002AD3A);
+
+	itWriteConfigDword(info, IT8181_STANDBY, 0x00000110);
+	mdelay(25); // wait 25 msec
+}
+
+/* get current video mode */
+static void it8181fb_get_par (void *_par, struct fb_info_gen *_info)
+{
+        struct it8181fb_par *par = (struct it8181fb_par *) _par;
+        struct it8181fb_info *info = (struct it8181fb_info *) _info;
+
+        *par = info->current_par;
+}
+
+/*
+  setmod for IT8181 chip
+*/
+static void it8181fb_set_par(const void *_par, struct fb_info_gen *_info)
+{
+        struct it8181fb_par *par = (struct it8181fb_par *) _par;
+        struct it8181fb_info *info = (struct it8181fb_info *) _info;
+
+	dbg("%dx%dx%d", par->var.xres, par->var.yres, par->var.bits_per_pixel);
+	dbg("%d %d %d %d %d %d %d",
+	    par->var.pixclock,
+	    par->var.left_margin,
+	    par->var.right_margin,
+	    par->var.upper_margin,
+	    par->var.lower_margin,
+	    par->var.hsync_len,
+	    par->var.vsync_len);
+	    
+	/* disable cursor */
+	writeb(0x00, info->itGuiCtrlVirt + 0x100);
+
+	itExtBUnlock();
+	itExtAUnlock();
+
+	mdelay(25);
+
+	// disable display sync
+	itWriteRegExtB(0x3c, 0x0a);
+
+	// Set RAM to 1M*16bit Symmetric DRAM	
+	itWriteRegExtB(0x2f,0x80);
+
+	// enable GUI engine registers
+	itWriteRegExtB(0x2b,0x10);
+
+	// set pixel clock
+	it8181SetPLL(par, info);
+
+	// Step2
+	if (par->var.xres == 640 && par->var.yres == 480 &&
+	    (par->var.bits_per_pixel == 8 || par->var.bits_per_pixel == 16)) {
+		itWriteRegMisc(0xc3);
+
+		itWriteRegCrtc(VGA_CRTC_H_TOTAL, 0x5f);
+		itWriteRegCrtc(VGA_CRTC_H_DISP, 0x4f);
+		itWriteRegCrtc(VGA_CRTC_H_BLANK_START, 0x40);
+		itWriteRegCrtc(VGA_CRTC_H_BLANK_END, 0x80);
+		itWriteRegCrtc(VGA_CRTC_H_SYNC_START, 0x52);
+		itWriteRegCrtc(VGA_CRTC_H_SYNC_END, 0x81);
+		itWriteRegCrtc(VGA_CRTC_V_TOTAL, 0x0b);
+		itWriteRegCrtc(VGA_CRTC_OVERFLOW, 0x3e);
+		itWriteRegCrtc(VGA_CRTC_PRESET_ROW, 0x00);
+		itWriteRegCrtc(VGA_CRTC_MAX_SCAN, 0x40);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_START, 0x00);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_END, 0x00);
+		itWriteRegCrtc(VGA_CRTC_START_HI, 0x00);
+		itWriteRegCrtc(VGA_CRTC_START_LO, 0x00);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_HI, 0x01);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_LO, 0x49);
+		itWriteRegCrtc(VGA_CRTC_V_SYNC_START, 0xea);
+		itWriteRegCrtc(VGA_CRTC_V_SYNC_END, 0x8c);
+		itWriteRegCrtc(VGA_CRTC_V_DISP_END, 0xdf);
+		itWriteRegCrtc(VGA_CRTC_OFFSET, 0x50);
+		itWriteRegCrtc(VGA_CRTC_UNDERLINE, 0x00);
+		itWriteRegCrtc(VGA_CRTC_V_BLANK_START, 0xe7);
+		itWriteRegCrtc(VGA_CRTC_V_BLANK_END, 0x04);
+		itWriteRegCrtc(VGA_CRTC_MODE, 0xe3);
+		itWriteRegCrtc(VGA_CRTC_LINE_COMPARE, 0xff);
+	} else if (par->var.xres == 800 && par->var.yres == 600 &&
+	           (par->var.bits_per_pixel == 8 || par->var.bits_per_pixel == 16)) {
+		itWriteRegMisc(0x03);
+
+		itWriteRegCrtc(VGA_CRTC_H_TOTAL, 0x07);
+		itWriteRegCrtc(VGA_CRTC_H_DISP, 0x63);
+		itWriteRegCrtc(VGA_CRTC_H_BLANK_START, 0x64);
+		itWriteRegCrtc(VGA_CRTC_H_BLANK_END, 0x81);
+		itWriteRegCrtc(VGA_CRTC_H_SYNC_START, 0x6c);
+		itWriteRegCrtc(VGA_CRTC_H_SYNC_END, 0x18);
+		itWriteRegCrtc(VGA_CRTC_V_TOTAL, 0x72);
+		itWriteRegCrtc(VGA_CRTC_OVERFLOW, 0x0f);
+		itWriteRegCrtc(VGA_CRTC_PRESET_ROW, 0x00);
+		itWriteRegCrtc(VGA_CRTC_MAX_SCAN, 0x60);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_START, 0x00);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_END, 0x00);
+		itWriteRegCrtc(VGA_CRTC_START_HI, 0x00);
+		itWriteRegCrtc(VGA_CRTC_START_LO, 0x00);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_HI, 0x00);
+		itWriteRegCrtc(VGA_CRTC_CURSOR_LO, 0xaa);
+		itWriteRegCrtc(VGA_CRTC_V_SYNC_START, 0x59);
+		itWriteRegCrtc(VGA_CRTC_V_SYNC_END, 0xad);
+		itWriteRegCrtc(VGA_CRTC_V_DISP_END, 0x57);
+		itWriteRegCrtc(VGA_CRTC_OFFSET, 0x64);
+		itWriteRegCrtc(VGA_CRTC_UNDERLINE, 0x00);
+		itWriteRegCrtc(VGA_CRTC_V_BLANK_START, 0x59);
+		itWriteRegCrtc(VGA_CRTC_V_BLANK_END, 0x00);
+		itWriteRegCrtc(VGA_CRTC_MODE, 0xe3);
+		itWriteRegCrtc(VGA_CRTC_LINE_COMPARE, 0xff);
+	}
+
+
+	if (par->var.bits_per_pixel == 8) {
+		if (par->var.xres == 640 && par->var.yres == 480)
+			itWriteRegCrtc(VGA_CRTC_OFFSET, 0x28);
+		else if (par->var.xres == 800 && par->var.yres == 600)
+			itWriteRegCrtc(VGA_CRTC_OFFSET, 0x32);
+	}
+
+	itWriteRegSEQ(VGA_SEQ_RESET, 0x03);
+	itWriteRegExtB(0x06, 0x01);
+	itWriteRegExtB(0x20, 0x01);
+
+	if (par->var.xres == 640 && par->var.yres == 480) {
+		if (par->var.bits_per_pixel == 8)
+			itWriteRegExtB(0x38, 0x01);
+		else if (par->var.bits_per_pixel == 16)
+			itWriteRegExtB(0x38, 0x03);
+		itWriteRegExtB(0x39, 0x40);
+	} else if (par->var.xres == 800 && par->var.yres == 600) {
+		if (par->var.bits_per_pixel == 8)
+			itWriteRegExtB(0x38, 0x21);
+		else if (par->var.bits_per_pixel == 16)
+			itWriteRegExtB(0x38, 0x23);
+		itWriteRegExtB(0x39, 0x44);
+	}
+
+	writeb(0xff, info->itMmioAddrVirt+VGA_PEL_MSK);
+
+	// Step3
+	if (it8181fb_lcd) {
+		if (par->var.xres == 640 && par->var.yres == 480 &&
+		    (par->var.bits_per_pixel == 8 ||
+		     par->var.bits_per_pixel == 16)) {
+			dbg("LCD 640x480-8/16 selected");
+			itWriteRegExtA(0x80, 0x4e);
+			itWriteRegExtA(0x81, 0x00);
+			itWriteRegExtA(0x82, 0x13);
+			itWriteRegExtA(0x83, 0x00);
+			itWriteRegExtA(0x84, 0x10);
+			itWriteRegExtA(0x85, 0xdf);
+			itWriteRegExtA(0x86, 0x00);
+			itWriteRegExtA(0x87, 0x28);
+			itWriteRegExtA(0x88, 0x00);
+			itWriteRegExtA(0x89, 0x00);
+			itWriteRegExtA(0x8a, 0x81);
+			itWriteRegExtA(0x8b, 0x4e);
+			itWriteRegExtA(0x8c, 0x00);
+			itWriteRegExtA(0x8d, 0x2b);
+			itWriteRegExtA(0x8e, 0x00);
+			itWriteRegExtA(0x8f, 0x00);
+			itWriteRegExtA(0x90, 0x01);
+			itWriteRegExtA(0x91, 0x00);
+			itWriteRegExtA(0x92, 0x00);
+			itWriteRegExtA(0x93, 0x10);
+
+			itWriteRegExtA(0xa0, 0x23);
+
+			itWriteRegExtA(0xb0, 0x04);
+			itWriteRegExtA(0xb1, 0x04);
+			itWriteRegExtA(0xb2, 0x40);
+			itWriteRegExtA(0xb3, 0x40);
+			itWriteRegExtA(0xb4, 0x08);
+			itWriteRegExtA(0xb5, 0x08);
+			itWriteRegExtA(0xb6, 0x80);
+			itWriteRegExtA(0xb7, 0x80);
+			itWriteRegExtA(0xb8, 0x2a);
+			itWriteRegExtA(0xb9, 0x3b);
+			itWriteRegExtA(0xba, 0x6e);
+			itWriteRegExtA(0xbb, 0x7f);
+			itWriteRegExtA(0xbc, 0x80);
+			itWriteRegExtA(0xbd, 0x19);
+			itWriteRegExtA(0xbe, 0xc4);
+			itWriteRegExtA(0xbf, 0xd5);
+		} else if (par->var.xres == 800 && par->var.yres == 600 &&
+		           (par->var.bits_per_pixel == 8 ||
+			    par->var.bits_per_pixel == 16)) {
+			dbg("LCD 800x600-8/16 selected");
+			itWriteRegExtA(0x80, 0x62);
+			itWriteRegExtA(0x81, 0x00);
+			itWriteRegExtA(0x82, 0x1f);
+			itWriteRegExtA(0x83, 0x00);
+			itWriteRegExtA(0x84, 0x10);
+			itWriteRegExtA(0x85, 0x57);
+			itWriteRegExtA(0x86, 0x18);
+			itWriteRegExtA(0x87, 0x48);
+			itWriteRegExtA(0x88, 0x00);
+			itWriteRegExtA(0x89, 0x00);
+			itWriteRegExtA(0x8a, 0xf9);
+			itWriteRegExtA(0x8b, 0xc7);
+			itWriteRegExtA(0x8c, 0x00);
+			itWriteRegExtA(0x8d, 0x1a);
+			itWriteRegExtA(0x8e, 0x00);
+			itWriteRegExtA(0x8f, 0x00);
+			itWriteRegExtA(0x90, 0x41);
+			itWriteRegExtA(0x91, 0x00);
+			itWriteRegExtA(0x92, 0x00);
+			itWriteRegExtA(0x93, 0x10);
+
+			itWriteRegExtA(0xa0, 0x23);
+
+			itWriteRegExtA(0xb0, 0x00);
+			itWriteRegExtA(0xb1, 0x00);
+			itWriteRegExtA(0xb2, 0x00);
+			itWriteRegExtA(0xb3, 0x00);
+			itWriteRegExtA(0xb4, 0x00);
+			itWriteRegExtA(0xb5, 0x00);
+			itWriteRegExtA(0xb6, 0x00);
+			itWriteRegExtA(0xb7, 0x00);
+			itWriteRegExtA(0xb8, 0x50);
+			itWriteRegExtA(0xb9, 0x7b);
+			itWriteRegExtA(0xba, 0x8c);
+			itWriteRegExtA(0xbb, 0x2e);
+			itWriteRegExtA(0xbc, 0x14);
+			itWriteRegExtA(0xbd, 0xa6);
+			itWriteRegExtA(0xbe, 0xd9);
+			itWriteRegExtA(0xbf, 0xf3);
+		}
+
+		if (it8181fb_memory_type == 0) {
+			itWriteRegExtA(0xa8, 0x30);
+			itWriteRegExtA(0xa9, 0x3c);
+		} else {
+			itWriteRegExtA(0xa8, 0xc0);
+			itWriteRegExtA(0xa9, 0xe0);
+		}
+
+		itWriteRegExtA(0xa1, 0x01);
+		itWriteRegExtA(0xa2, 0x00);
+
+		itWriteRegExtA(0x9a, 0x22);
+		itWriteRegExtA(0x9b, 0x01);
+	}
+
+	// turn display sync's back on
+	itWriteRegExtB(0x3c, 0x00);
+
+	itExtBLock();
+	itExtALock();
+
+	mdelay(25);
+
+	/* this par is now current par */
+	info->current_par = *par;
+}
+
+/*
+ * Set/Get the color of a palette entry in 8bpp mode 
+ */
+static inline void
+do_setpalentry(unsigned regno, u8 r, u8 g, u8 b)
+{
+	writeb((u8)regno, itMmioAddr+VGA_PEL_IW);
+	writeb(r, itMmioAddr+VGA_PEL_D);
+	writeb(g, itMmioAddr+VGA_PEL_D);
+	writeb(b, itMmioAddr+VGA_PEL_D);	
+}
+
+static inline void
+do_getpalentry(unsigned regno, u8* r, u8* g, u8* b)
+{
+	writeb((u8)regno, itMmioAddr+VGA_PEL_IW);
+	*r = readb(itMmioAddr+VGA_PEL_D);
+	*g = readb(itMmioAddr+VGA_PEL_D);
+	*b = readb(itMmioAddr+VGA_PEL_D);	
+}
+
+static int it8181fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			      unsigned *blue, unsigned *transp,
+			      struct fb_info *_info)
+{
+	u8 r,g,b;
+
+        if (regno > 255)
+                return 1;
+
+	do_getpalentry(regno, &r, &g, &b);
+	
+        *red    = (unsigned)r << 10;
+        *green  = (unsigned)g << 10;
+        *blue   = (unsigned)b << 10;
+        *transp = 0;
+
+        return 0;
+}
+
+static int it8181fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *_info)
+{
+	struct it8181fb_info *p = (struct it8181fb_info *) _info;
+	struct it8181fb_par* par = &p->current_par;
+	
+	if (regno > 255)
+		return -EINVAL;
+
+	do_setpalentry(regno, (u8)(red>>10),
+		       (u8)(green>>10), (u8)(blue>>10));
+
+	switch (par->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		if(regno < CMAPSIZE)
+			fbcon_cmap.cfb16[regno] =
+				((red & 0xf800) >> 0) |
+				((green & 0xf800) >> 5) |
+				((blue & 0xf800) >> 11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		if (regno < CMAPSIZE)
+			fbcon_cmap.cfb24[regno] =
+				((red & 0xff00) << 8) |
+				((green & 0xff00)) |
+				((blue & 0xff00) >> 8);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		if(regno < CMAPSIZE)
+			fbcon_cmap.cfb32[regno] =
+				((red & 0xff00) >> 8) |
+				((green & 0xff00)) |
+				((blue & 0xff00) << 8);
+		break;
+#endif
+	default: 
+		break;
+	}
+
+	return 0;
+}
+
+static int it8181fb_pan_display (const struct fb_var_screeninfo *var,
+				 struct fb_info_gen *info)
+{
+	/* not implemented */
+	return 0;
+}
+
+/*
+ *  Initialisation
+ */
+int it8181fb_init(void)
+{
+	struct fb_var_screeninfo var;
+	struct it8181fb_info *p = NULL;
+
+	fb_it8181 = p =
+		(struct it8181fb_info *) kmalloc(sizeof(*p), GFP_ATOMIC);
+	if(p==NULL)
+		return -ENOMEM;
+	memset(p, 0, sizeof(*p));
+
+#ifdef CONFIG_PCI
+	p->pdev = (struct pci_dev *) pci_find_device(PCI_VENDOR_ID_ITE,
+						     PCI_DEVICE_ID_ITE_IT8181,
+						     NULL);
+#endif
+	if(!p->pdev) {
+		u32 id = 0;
+		if (default_config_offset)
+			p->itConfigAddrVirt = (u32) ioremap(default_memory_base +
+			                                    default_config_offset,
+			                                    IT8181_CFG_SIZE);
+		if (p->itConfigAddrVirt)
+			itReadConfigDword(p, PCI_VENDOR_ID, &id);
+		if (!(id == (PCI_VENDOR_ID_ITE | (PCI_DEVICE_ID_ITE_IT8181 << 16))))
+			return -ENODEV;
+	}
+	
+	itReadConfigDword(p, PCI_BASE_ADDRESS_0, &(p->itFbAddrPhys));
+	itReadConfigDword(p, PCI_BASE_ADDRESS_1, &(p->itGuiCtrlPhys));
+	itReadConfigDword(p, PCI_BASE_ADDRESS_2, &(p->itMmioAddrPhys));
+
+	p->itFbAddrVirt = (u32) ioremap(p->itFbAddrPhys + default_memory_base,
+	                                IT8181_FB_SIZE);
+	p->itGuiCtrlVirt = (u32) ioremap(p->itGuiCtrlPhys + default_memory_base,
+	                                 IT8181_GUI_SIZE);
+	p->itMmioAddrVirt = itMmioAddr = (u32) ioremap(p->itMmioAddrPhys +
+	                                               default_memory_base,
+	                                               IT8181_MMIO_SIZE);
+
+	info("Mmio at 0x%08x, Framebuffer at 0x%08x", itMmioAddr, p->itFbAddrVirt);
+
+        /* set up a few more things, register framebuffer driver etc */
+        p->gen.parsize = sizeof (struct it8181fb_par);
+        p->gen.fbhw = &it8181fb_hwswitch;
+
+	strcpy(p->gen.info.modename, "ITE "); 
+	strcat(p->gen.info.modename, it8181fb_name);
+	p->gen.info.changevar = NULL;
+	p->gen.info.node = -1;
+
+	p->gen.info.fbops = &it8181fb_ops;
+	p->gen.info.disp = &p->disp;
+	p->gen.info.switch_con = &fbgen_switch;
+	p->gen.info.updatevar = &fbgen_update_var;
+	p->gen.info.blank = &fbgen_blank;
+	p->gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	if(!mode_option || !fb_find_mode(&var, &p->gen.info,
+					 mode_option, NULL, 0, NULL, 16)) {
+		var = it8181_var_table[default_res];
+		var.bits_per_pixel = default_bpp;
+	}
+	
+        if (fbgen_do_set_var(&var, 1, &p->gen)) {
+                /*
+                 * Can't use the mode from the mode db or the default
+                 * mode - give up
+                 */
+                err("boot video mode failed");
+                goto ret_enxio;
+        }
+
+        p->disp.var = var;
+        fbgen_set_disp(-1, &p->gen);
+        fbgen_install_cmap(0, &p->gen);
+
+	if (register_framebuffer(&p->gen.info) < 0) {
+		goto ret_enxio;
+	}
+
+	return 0;
+
+ ret_enxio:
+	kfree(p);
+	iounmap((void *)itMmioAddr);
+	iounmap((void *)p->itGuiCtrlVirt);
+	iounmap((void *)p->itFbAddrVirt);
+	return -ENXIO;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	return it8181fb_init();
+}
+
+void cleanup_module(void)
+{
+	unregister_framebuffer(&(fb_it8181->gen.info));
+	iounmap((void*)itMmioAddr);
+	iounmap((void*)fb_it8181->itFbAddrVirt);
+	kfree(fb_it8181);
+}
+
+#else
+
+int it8181fb_setup(char *options, int *ints)
+{
+	char *this_opt;
+	int xres, cpu = 0, mod;
+	
+	if (!options || !*options)
+		return 1;
+
+	for (this_opt = strtok(options, ","); this_opt;
+	     this_opt = strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "font:", 5)) {
+			strcpy(fontname, this_opt+5);
+		} else if (!strncmp(this_opt, "bpp:", 4)) {
+			default_bpp = simple_strtoul(this_opt+4, NULL, 0);
+		} else if (!strncmp(this_opt, "xres:", 5)) {
+			xres = simple_strtoul(this_opt+5, NULL, 0);
+			if (xres == 640)
+				default_res = RES_640x480;
+			else if (xres == 800)
+				default_res = RES_800x600;
+			else if (xres == 1024)
+				default_res = RES_1024x768;
+		} else if (!strncmp(this_opt, "cpu:", 4)) {
+			if (!strncmp(this_opt+4, "vr4111", 6)) {
+				cpu = 1;
+				default_memory_base = 0xa000000;
+			} else if (!strncmp(this_opt + 4, "sh7750", 6)) {
+				cpu = 2;
+			}
+		} else if (!strncmp(this_opt, "mod:", 4)) {
+			mod = simple_strtoul(this_opt+4, NULL, 0);
+			if (cpu == 1) {
+				/* NEC VR4111 or VR4121 */
+				if (mod == 1)
+					default_memory_base += 0x800000;
+				default_config_offset = 0x800000 - 0x400;
+			} else if (cpu == 2) {
+				/* Hitachi SH7750 */
+				if (mod == 0)
+					default_config_offset = 0x2000000 - 0x400;
+				else if (mod == 1)
+					default_config_offset = 0x3000000 - 0x400;
+			}
+		}else if (!strncmp(this_opt, "lcd:", 4)) {
+			it8181fb_lcd = simple_strtoul(this_opt+4, NULL, 0);
+		}else if (!strncmp(this_opt, "mtype:", 6)) {
+			it8181fb_memory_type = simple_strtoul(this_opt+6, NULL, 0);
+		} else {
+			mode_option = this_opt;
+		}
+	}
+
+	return 0;
+}
+
+#endif /* MODULE */
diff -urN linux-2.4.25-pre7/fs/Config.in linux-2.4.25-pre8/fs/Config.in
--- linux-2.4.25-pre7/fs/Config.in	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/fs/Config.in	2004-01-29 10:58:21.000000000 -0800
@@ -145,6 +145,7 @@
       if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then
          string '    Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437"
       fi
+      bool '  Enable Unix Extensions' CONFIG_SMB_UNIX
    fi
    if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
       tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
diff -urN linux-2.4.25-pre7/fs/smbfs/ChangeLog linux-2.4.25-pre8/fs/smbfs/ChangeLog
--- linux-2.4.25-pre7/fs/smbfs/ChangeLog	2002-02-25 11:38:09.000000000 -0800
+++ linux-2.4.25-pre8/fs/smbfs/ChangeLog	2004-01-29 10:58:21.000000000 -0800
@@ -1,5 +1,13 @@
 ChangeLog for smbfs.
 
+2004-01-24 Urban Widmark <urban@teststation.com>
+
+	* file.c, inode.c, proc.c: Large File Support
+
+2004-01-24 John Newbigin <jn@it.swin.edu.au>
+
+	* *.c: Implementation of CIFS Extensions for UNIX systems
+
 2001-12-31 René Scharfe <l.s.r@web.de>
 
 	* inode.c: added smb_show_options to show mount options in /proc/mounts
diff -urN linux-2.4.25-pre7/fs/smbfs/Makefile linux-2.4.25-pre8/fs/smbfs/Makefile
--- linux-2.4.25-pre7/fs/smbfs/Makefile	2001-10-02 17:03:34.000000000 -0700
+++ linux-2.4.25-pre8/fs/smbfs/Makefile	2004-01-29 10:58:21.000000000 -0800
@@ -9,7 +9,7 @@
 
 O_TARGET := smbfs.o
 
-obj-y   := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o
+obj-y   := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o symlink.o
 obj-m   := $(O_TARGET)
 
 # If you want debugging output, you may add these flags to the EXTRA_CFLAGS
@@ -29,7 +29,7 @@
 #
 
 # getopt.c not included. It is intentionally separate
-SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c
+SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c symlink.c
 
 proto:
 	-rm -f proto.h
diff -urN linux-2.4.25-pre7/fs/smbfs/dir.c linux-2.4.25-pre8/fs/smbfs/dir.c
--- linux-2.4.25-pre7/fs/smbfs/dir.c	2001-10-02 17:03:34.000000000 -0700
+++ linux-2.4.25-pre8/fs/smbfs/dir.c	2004-01-29 10:58:21.000000000 -0800
@@ -30,6 +30,8 @@
 static int smb_unlink(struct inode *, struct dentry *);
 static int smb_rename(struct inode *, struct dentry *,
 		      struct inode *, struct dentry *);
+static int smb_make_node(struct inode *,struct dentry *, int, int);
+static int smb_link(struct dentry *, struct inode *, struct dentry *);
 
 struct file_operations smb_dir_operations =
 {
@@ -51,6 +53,21 @@
 	setattr:	smb_notify_change,
 };
 
+struct inode_operations smb_dir_inode_operations_unix =
+{
+	create:		smb_create,
+	lookup:		smb_lookup,
+	unlink:		smb_unlink,
+	mkdir:		smb_mkdir,
+	rmdir:		smb_rmdir,
+	rename:		smb_rename,
+	revalidate:	smb_revalidate_inode,
+	setattr:	smb_notify_change,
+	symlink:	smb_symlink,
+	mknod:		smb_make_node,
+	link:		smb_link,
+};
+
 /*
  * Read a directory, using filldir to fill the dirent memory.
  * smb_proc_readdir does the actual reading from the smb server.
@@ -188,7 +205,7 @@
 	ctl.filled = 0;
 	ctl.valid  = 1;
 read_really:
-	result = smb_proc_readdir(filp, dirent, filldir, &ctl);
+	result = server->ops->readdir(filp, dirent, filldir, &ctl);
 	if (ctl.idx == -1)
 		goto invalid_cache;	/* retry */
 	ctl.head.end = ctl.fpos - 1;
@@ -477,14 +494,22 @@
 static int
 smb_create(struct inode *dir, struct dentry *dentry, int mode)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	__u16 fileid;
 	int error;
+	struct iattr attr;
 
 	VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
 
 	smb_invalid_dir_cache(dir);
 	error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
 	if (!error) {
+		if (server->opt.capabilities & SMB_CAP_UNIX) {
+			/* Set attributes for new file */
+			attr.ia_valid = ATTR_MODE;
+			attr.ia_mode = mode;
+			error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
+		}
 		error = smb_instantiate(dentry, fileid, 1);
 	} else {
 		PARANOIA("%s/%s failed, error=%d\n",
@@ -497,11 +522,19 @@
 static int
 smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	int error;
+	struct iattr attr;
 
 	smb_invalid_dir_cache(dir);
 	error = smb_proc_mkdir(dentry);
 	if (!error) {
+		if (server->opt.capabilities & SMB_CAP_UNIX) {
+			/* Set attributes for new directory */
+			attr.ia_valid = ATTR_MODE;
+			attr.ia_mode = mode;
+			error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
+		}
 		error = smb_instantiate(dentry, 0, 0);
 	}
 	return error;
@@ -583,3 +616,46 @@
 out:
 	return error;
 }
+
+/*
+ * FIXME: samba servers won't let you create device nodes unless uid/gid
+ * matches the connection credentials (and we don't know which those are ...)
+ */
+static int
+smb_make_node(struct inode *dir, struct dentry *dentry, int mode, int dev)
+{
+	int error;
+	struct iattr attr;
+
+	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
+	attr.ia_mode = mode;
+	attr.ia_uid = current->euid;
+	attr.ia_gid = current->egid;
+
+	smb_invalid_dir_cache(dir);
+	error = smb_proc_setattr_unix(dentry, &attr, MAJOR(dev), MINOR(dev));
+	if (!error) {
+		error = smb_instantiate(dentry, 0, 0);
+	}
+	return error;
+}
+
+/*
+ * dentry = existing file
+ * new_dentry = new file
+ */
+static int
+smb_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry)
+{
+	int error;
+
+	DEBUG1("smb_link old=%s/%s new=%s/%s\n",
+	       DENTRY_PATH(dentry), DENTRY_PATH(new_dentry));
+	smb_invalid_dir_cache(dir);
+	error = smb_proc_link(server_from_dentry(dentry), dentry, new_dentry);
+	if (!error) {
+		smb_renew_times(dentry);
+		error = smb_instantiate(new_dentry, 0, 0);
+	}
+	return error;
+}
diff -urN linux-2.4.25-pre7/fs/smbfs/file.c linux-2.4.25-pre8/fs/smbfs/file.c
--- linux-2.4.25-pre7/fs/smbfs/file.c	2002-02-25 11:38:09.000000000 -0800
+++ linux-2.4.25-pre8/fs/smbfs/file.c	2004-01-29 10:58:21.000000000 -0800
@@ -55,8 +55,9 @@
 smb_readpage_sync(struct dentry *dentry, struct page *page)
 {
 	char *buffer = kmap(page);
-	unsigned long offset = page->index << PAGE_CACHE_SHIFT;
-	int rsize = smb_get_rsize(server_from_dentry(dentry));
+	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	unsigned int rsize = smb_get_rsize(server);
 	int count = PAGE_SIZE;
 	int result;
 
@@ -74,7 +75,7 @@
 		if (count < rsize)
 			rsize = count;
 
-		result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
+		result = server->ops->read(dentry->d_inode,offset,rsize,buffer);
 		if (result < 0)
 			goto io_error;
 
@@ -118,21 +119,23 @@
  */
 static int
 smb_writepage_sync(struct inode *inode, struct page *page,
-		   unsigned long offset, unsigned int count)
+		   unsigned long pageoffset, unsigned int count)
 {
-	char *buffer = kmap(page) + offset;
-	int wsize = smb_get_wsize(server_from_inode(inode));
+	loff_t offset;
+	char *buffer = kmap(page) + pageoffset;
+	struct smb_sb_info *server = server_from_inode(inode);
+	unsigned int wsize = smb_get_wsize(server);
 	int result, written = 0;
 
-	offset += page->index << PAGE_CACHE_SHIFT;
-	VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
+	offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
+	VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
 		inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
 
 	do {
 		if (count < wsize)
 			wsize = count;
 
-		result = smb_proc_write(inode, offset, wsize, buffer);
+		result = server->ops->write(inode, offset, wsize, buffer);
 		if (result < 0) {
 			PARANOIA("failed write, wsize=%d, result=%d\n",
 				 wsize, result);
diff -urN linux-2.4.25-pre7/fs/smbfs/inode.c linux-2.4.25-pre8/fs/smbfs/inode.c
--- linux-2.4.25-pre7/fs/smbfs/inode.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.25-pre8/fs/smbfs/inode.c	2004-01-29 10:58:21.000000000 -0800
@@ -79,8 +79,16 @@
 		result->i_fop = &smb_file_operations;
 		result->i_data.a_ops = &smb_file_aops;
 	} else if (S_ISDIR(result->i_mode)) {
-		result->i_op = &smb_dir_inode_operations;
+		struct smb_sb_info *server = &(sb->u.smbfs_sb);
+		if (server->opt.capabilities & SMB_CAP_UNIX)
+			result->i_op = &smb_dir_inode_operations_unix;
+		else
+			result->i_op = &smb_dir_inode_operations;
 		result->i_fop = &smb_dir_operations;
+	} else if(S_ISLNK(result->i_mode)) {
+		result->i_op = &smb_link_inode_operations;
+	} else {
+		init_special_inode(result, result->i_mode, fattr->f_rdev);
 	}
 	insert_inode_hash(result);
 	return result;
@@ -187,7 +195,14 @@
 		/*
 		 * Check whether the type part of the mode changed,
 		 * and don't update the attributes if it did.
+		 *
+		 * And don't dick with the root inode
 		 */
+		if (inode->i_ino == 2)
+			return error;
+		if (S_ISLNK(inode->i_mode))
+			return error;	/* VFS will deal with it */
+
 		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
 			smb_set_inode_attr(inode, &fattr);
 		} else {
@@ -424,6 +439,7 @@
 	struct inode *root_inode;
 	struct smb_fattr root;
 	int ver;
+	void *mem;
 
 	if (!raw_data)
 		goto out_no_data;
@@ -435,6 +451,7 @@
 
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
+	sb->s_maxbytes = MAX_NON_LFS;
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_op = &smb_sops;
 
@@ -462,10 +479,13 @@
 
 	/* Allocate the mount data structure */
 	/* FIXME: merge this with the other malloc and get a whole page? */
-	mnt = smb_kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
-	if (!mnt)
+	mem = smb_kmalloc(sizeof(struct smb_ops) +
+			  sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
+	if (!mem)
 		goto out_no_mount;
-	server->mnt = mnt;
+	server->mnt = mnt = mem;
+	server->ops = mem + sizeof(struct smb_mount_data_kernel);
+	smb_install_null_ops(server->ops);
 
 	memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
 	strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
@@ -479,7 +499,6 @@
 		mnt->version = oldmnt->version;
 
 		/* FIXME: is this enough to convert uid/gid's ? */
-		mnt->mounted_uid = oldmnt->mounted_uid;
 		mnt->uid = oldmnt->uid;
 		mnt->gid = oldmnt->gid;
 
@@ -490,10 +509,9 @@
 	} else {
 		if (parse_options(mnt, raw_data))
 			goto out_bad_option;
-
-		mnt->mounted_uid = current->uid;
 	}
 	smb_setcodepage(server, &mnt->codepage);
+	mnt->mounted_uid = current->uid;
 
 	/*
 	 * Display the enabled options
@@ -587,8 +605,7 @@
 		error = smb_open(dentry, O_WRONLY);
 		if (error)
 			goto out;
-		error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
-					 attr->ia_size);
+		error = server->ops->truncate(inode, attr->ia_size);
 		if (error)
 			goto out;
 		error = vmtruncate(inode, attr->ia_size);
@@ -597,6 +614,16 @@
 		refresh = 1;
 	}
 
+	if (server->opt.capabilities & SMB_CAP_UNIX) {
+		/* For now we don't want to set the size with setattr_unix */
+		attr->ia_valid &= ~ATTR_SIZE;
+		/* FIXME: only call if we actually want to set something? */
+		error = smb_proc_setattr_unix(dentry, attr, 0, 0);
+		if (!error)
+			refresh = 1;
+		goto out;
+	}
+
 	/*
 	 * Initialize the fattr and check for changed fields.
 	 * Note: CTIME under SMB is creation time rather than
diff -urN linux-2.4.25-pre7/fs/smbfs/proc.c linux-2.4.25-pre8/fs/smbfs/proc.c
--- linux-2.4.25-pre7/fs/smbfs/proc.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.25-pre8/fs/smbfs/proc.c	2004-01-29 10:58:21.000000000 -0800
@@ -45,16 +45,32 @@
 #define SMB_ST_BLKSIZE	(PAGE_SIZE)
 #define SMB_ST_BLKSHIFT	(PAGE_SHIFT)
 
+static struct smb_ops smb_ops_core;
+static struct smb_ops smb_ops_os2;
+static struct smb_ops smb_ops_win95;
+static struct smb_ops smb_ops_winNT;
+static struct smb_ops smb_ops_unix;
+
+static void
+smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+static void
+smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+static int
+smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
+		      struct smb_fattr *fattr);
+static int
+smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dir,
+		    struct smb_fattr *fattr);
 static int
 smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
 		     struct smb_fattr *);
 static int
 smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
                       __u16 attr);
+static void
+install_ops(struct smb_ops *dst, struct smb_ops *src);
 static int
-smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
-		    struct smb_fattr *fattr);
-
+smb_proc_query_cifsunix(struct smb_sb_info *server);
 
 
 static void
@@ -95,8 +111,8 @@
 }
 
 /* no conversion, just a wrapper for memcpy. */
-static int convert_memcpy(char *output, int olen,
-			  const char *input, int ilen,
+static int convert_memcpy(unsigned char *output, int olen,
+			  const unsigned char *input, int ilen,
 			  struct nls_table *nls_from,
 			  struct nls_table *nls_to)
 {
@@ -123,8 +139,8 @@
 }
 
 /* convert from one "codepage" to another (possibly being utf8). */
-static int convert_cp(char *output, int olen,
-		      const char *input, int ilen,
+static int convert_cp(unsigned char *output, int olen,
+		      const unsigned char *input, int ilen,
 		      struct nls_table *nls_from,
 		      struct nls_table *nls_to)
 {
@@ -203,9 +219,9 @@
 
 out:
 	if (server->local_nls != NULL && server->remote_nls != NULL)
-		server->convert = convert_cp;
+		server->ops->convert = convert_cp;
 	else
-		server->convert = convert_memcpy;
+		server->ops->convert = convert_memcpy;
 
 	smb_unlock_server(server);
 	return n;
@@ -268,7 +284,7 @@
 		if (maxlen < 3)
 			return -ENAMETOOLONG;
 
-		len = server->convert(path, maxlen-2, 
+		len = server->ops->convert(path, maxlen-2, 
 				      entry->d_name.name, entry->d_name.len,
 				      server->local_nls, server->remote_nls);
 		if (len < 0)
@@ -290,7 +306,7 @@
 		if (maxlen < 3)
 			return -ENAMETOOLONG;
 		*path++ = '\\';
-		len = server->convert(path, maxlen-2, 
+		len = server->ops->convert(path, maxlen-2, 
 				      name->name, name->len,
 				      server->local_nls, server->remote_nls);
 		if (len < 0)
@@ -426,15 +442,45 @@
 	return (time_t)t;
 }
 
-#if 0
-/* Convert the Unix UTC into NT time */
 static u64
-smb_unixutc2ntutc(struct smb_sb_info *server, time_t t)
+smb_unixutc2ntutc(time_t t)
 {
 	/* Note: timezone conversion is probably wrong. */
-	return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET;
+	return ((u64)t) * 10000000 + NTFS_TIME_OFFSET;
+}
+
+#define MAX_FILE_MODE   6
+static mode_t file_mode[] = {
+	S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFIFO, S_IFSOCK
+};
+
+static int smb_filetype_to_mode(u32 filetype)
+{
+	if (filetype > MAX_FILE_MODE) {
+		PARANOIA("Filetype out of range: %d\n", filetype);
+		return S_IFREG;
+	}
+	return file_mode[filetype];
+}
+
+static u32 smb_filetype_from_mode(int mode)
+{
+	if (mode & S_IFREG)
+		return UNIX_TYPE_FILE;
+	if (mode & S_IFDIR)
+		return UNIX_TYPE_DIR;
+	if (mode & S_IFLNK)
+		return UNIX_TYPE_SYMLINK;
+	if (mode & S_IFCHR)
+		return UNIX_TYPE_CHARDEV;
+	if (mode & S_IFBLK)
+		return UNIX_TYPE_BLKDEV;
+	if (mode & S_IFIFO)
+		return UNIX_TYPE_FIFO;
+	if (mode & S_IFSOCK)
+		return UNIX_TYPE_SOCKET;
+	return UNIX_TYPE_UNKNOWN;
 }
-#endif
 
 
 /*****************************************************************************/
@@ -518,7 +564,8 @@
 int
 smb_get_rsize(struct smb_sb_info *server)
 {
-	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+	/* readX has 12 parameters, read has 5 */
+	int overhead = SMB_HEADER_LEN + 12 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
 	VERBOSE("packet=%d, xmit=%d, size=%d\n",
@@ -533,7 +580,8 @@
 int
 smb_get_wsize(struct smb_sb_info *server)
 {
-	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+	/* writeX has 14 parameters, write has 5 */
+	int overhead = SMB_HEADER_LEN + 14 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
 	VERBOSE("packet=%d, xmit=%d, size=%d\n",
@@ -832,13 +880,54 @@
 
 	/* now that we have an established connection we can detect the server
 	   type and enable bug workarounds */
-	if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
-	    (server->opt.max_xmit < 0x1000) &&
-	    !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
+	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
+		install_ops(server->ops, &smb_ops_core);
+	else if (server->opt.protocol == SMB_PROTOCOL_LANMAN2)
+		install_ops(server->ops, &smb_ops_os2);
+	else if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
+		 (server->opt.max_xmit < 0x1000) &&
+		 !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
+		/* FIXME: can we kill the WIN95 flag now? */
 		server->mnt->flags |= SMB_MOUNT_WIN95;
-		VERBOSE("smb_newconn: detected WIN95 server\n");
+		VERBOSE("detected WIN95 server\n");
+		install_ops(server->ops, &smb_ops_win95);
+	} else {
+		/*
+		 * Samba has max_xmit 65535
+		 * NT4spX has max_xmit 4536 (or something like that)
+		 * win2k has ...
+		 */
+		VERBOSE("detected NT1 (Samba, NT4/5) server\n");
+		install_ops(server->ops, &smb_ops_winNT);
 	}
 
+	/* FIXME: the win9x code wants to modify these ... (seek/trunc bug) */
+	if (server->mnt->flags & SMB_MOUNT_OLDATTR) {
+		server->ops->getattr = smb_proc_getattr_core;
+	} else if (server->mnt->flags & SMB_MOUNT_DIRATTR) {
+		server->ops->getattr = smb_proc_getattr_ff;
+	}
+
+	/* Decode server capabilities */
+	if (server->opt.capabilities & SMB_CAP_LARGE_FILES) {
+		/* Should be ok to set this now, as no one can access the
+		   mount until the connection has been established. */
+		SB_of(server)->s_maxbytes = ~0ULL >> 1;
+		VERBOSE("LFS enabled\n");
+	}
+#ifdef CONFIG_SMB_UNIX
+	if (server->opt.capabilities & SMB_CAP_UNIX) {
+		struct inode *inode;
+		VERBOSE("Using UNIX CIFS extensions\n");
+		install_ops(server->ops, &smb_ops_unix);
+		inode = SB_of(server)->s_root->d_inode;
+		if (inode)
+			inode->i_op = &smb_dir_inode_operations_unix;
+	}
+#else
+	server->opt.capabilities &= ~SMB_CAP_UNIX;
+#endif
+
 	VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
 		server->opt.capabilities);
@@ -862,6 +951,9 @@
 		}
 	}
 
+	if (server->opt.capabilities & SMB_CAP_UNIX)
+		smb_proc_query_cifsunix(server);
+
 out:
 	smb_unlock_server(server);
 	smb_wakeup(server);
@@ -1118,7 +1210,8 @@
 		 * If the file is open with write permissions,
 		 * update the time stamps to sync mtime and atime.
 		 */
-		if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
+		if ((server->opt.capabilities & SMB_CAP_UNIX) == 0 &&
+		    (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
 		    !(ino->u.smbfs_i.access == SMB_O_RDONLY))
 		{
 			struct smb_fattr fattr;
@@ -1172,8 +1265,8 @@
 /* In smb_proc_read and smb_proc_write we do not retry, because the
    file-id would not be valid after a reconnection. */
 
-int
-smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
+static int
+smb_proc_read(struct inode *inode, loff_t offset, int count, char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
 	__u16 returned_count, data_len;
@@ -1221,15 +1314,15 @@
 	return result;
 }
 
-int
-smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
+static int
+smb_proc_write(struct inode *inode, loff_t offset, int count, const char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
 	int result;
 	__u8 *p;
 	__u16 fileid = inode->u.smbfs_i.fileid;
 
-	VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
 		inode->i_ino, inode->u.smbfs_i.fileid, count, offset,
 		server->packet_size);
 
@@ -1252,6 +1345,94 @@
 	return result;
 }
 
+/*
+ * In smb_proc_readX and smb_proc_writeX we do not retry, because the
+ * file-id would not be valid after a reconnection.
+ */
+static int
+smb_proc_readX(struct inode *inode, loff_t offset, int count, char *data)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	u16 data_len, data_off;
+	unsigned char *buf;
+	int result;
+
+	smb_lock_server(server);
+	smb_setup_header(server, SMBreadX, 12, 0);
+	buf = server->packet;
+	WSET(buf, smb_vwv0, 0x00ff);
+	WSET(buf, smb_vwv1, 0);
+	WSET(buf, smb_vwv2, inode->u.smbfs_i.fileid);
+	DSET(buf, smb_vwv3, (u32)offset);               /* low 32 bits */
+	WSET(buf, smb_vwv5, count);
+	WSET(buf, smb_vwv6, 0);
+	DSET(buf, smb_vwv7, 0);
+	WSET(buf, smb_vwv9, 0);
+	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */
+	WSET(buf, smb_vwv11, 0);
+
+	result = smb_request_ok(server, SMBreadX, 12, -1);
+	if (result < 0)
+		goto out;
+	data_len = WVAL(server->packet, smb_vwv5);
+	data_off = WVAL(server->packet, smb_vwv6);
+	buf = smb_base(server->packet) + data_off;
+
+	/* we can NOT simply trust the info given by the server ... */
+	if (data_len > server->packet_size - (buf - server->packet)) {
+		printk(KERN_ERR "smb_proc_read: invalid data length!! "
+		       "%d > %d - (%p - %p)\n",
+		       data_len, server->packet_size, buf, server->packet);
+		result = -EIO;
+		goto out;
+	}
+
+	memcpy(data, buf, data_len);
+	result = data_len;
+
+out:
+	smb_unlock_server(server);
+	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
+		inode->i_ino, inode->u.smbfs_i.fileid, count, result);
+	return result;
+}
+
+static int
+smb_proc_writeX(struct inode *inode, loff_t offset, int count, const char *data)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int result;
+	u8 *p;
+
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
+		inode->i_ino, inode->u.smbfs_i.fileid, count, offset,
+		server->packet_size);
+
+	smb_lock_server(server);
+	p = smb_setup_header(server, SMBwriteX, 14, count + 2);
+	WSET(server->packet, smb_vwv0, 0x00ff);
+	WSET(server->packet, smb_vwv1, 0);
+	WSET(server->packet, smb_vwv2, inode->u.smbfs_i.fileid);
+	DSET(server->packet, smb_vwv3, (u32)offset);    /* low 32 bits */
+	DSET(server->packet, smb_vwv5, 0);
+	WSET(server->packet, smb_vwv7, 0);              /* write mode */
+	WSET(server->packet, smb_vwv8, 0);
+	WSET(server->packet, smb_vwv9, 0);
+	WSET(server->packet, smb_vwv10, count);         /* data length */
+	WSET(server->packet, smb_vwv11, p + 2 - smb_base(server->packet));
+	DSET(server->packet, smb_vwv12, (u32)(offset >> 32));
+	*p++ = 0;    /* FIXME: pad to short or long ... change +2 above also */
+	*p++ = 0;
+	memcpy(p, data, count);
+
+	result = smb_request_ok(server, SMBwriteX, 6, 0);
+	if (result >= 0)
+		result = WVAL(server->packet, smb_vwv2);
+
+	smb_unlock_server(server);
+	return result;
+}
+
 int
 smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
 {
@@ -1371,7 +1552,9 @@
 	struct smb_fattr fattr;
 
 	/* first get current attribute */
-	result = smb_proc_do_getattr(server, dentry, &fattr);
+	smb_init_dirent(server, &fattr);
+	result = server->ops->getattr(server, dentry, &fattr);
+	smb_finish_dirent(server, &fattr);
 	if (result < 0)
 		return result;
 
@@ -1446,38 +1629,72 @@
 	return smb_request_ok(server, SMBflush, 0, 0);
 }
 
-int
-smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
+static int
+smb_proc_trunc32(struct inode *inode, loff_t length)
 {
-	char *p;
+	/*
+	 * Writing 0bytes is old-SMB magic for truncating files.
+	 * MAX_NON_LFS should prevent this from being called with a too
+	 * large offset.
+	 */
+	return smb_proc_write(inode, length, 0, NULL);
+}
+
+static int
+smb_proc_trunc64(struct inode *inode, loff_t length)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int command;
 	int result;
+	char *param = server->temp_buf;
+	char data[8];
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
 
 	smb_lock_server(server);
-
-retry:
-	p = smb_setup_header(server, SMBwrite, 5, 3);
-	WSET(server->packet, smb_vwv0, fid);
-	WSET(server->packet, smb_vwv1, 0);
-	DSET(server->packet, smb_vwv2, length);
-	WSET(server->packet, smb_vwv4, 0);
-	*p++ = 1;
-	WSET(p, 0, 0);
-
-	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
+	command = TRANSACT2_SETFILEINFO;
+ 
+	/* FIXME: must we also set allocation size? winNT seems to do that */
+ retry:
+	WSET(param, 0, inode->u.smbfs_i.fileid);
+	WSET(param, 2, SMB_SET_FILE_END_OF_FILE_INFO);
+	WSET(param, 4, 0);
+	LSET(data, 0, length);
+	result = smb_trans2_request(server, command,
+				    8, data, 6, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
 	}
+	result = 0;
+	if (server->rcls != 0)
+		result = smb_errno(server);
 
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
+static int
+smb_proc_trunc95(struct inode *inode, loff_t length)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int result = smb_proc_trunc32(inode, length);
+ 
 	/*
 	 * win9x doesn't appear to update the size immediately.
 	 * It will return the old file size after the truncate,
-	 * confusing smbfs.
-	 * NT and Samba return the new value immediately.
+	 * confusing smbfs. So we force an update.
+	 *
+	 * FIXME: is this still necessary?
 	 */
-	if (server->mnt->flags & SMB_MOUNT_WIN95)
-		smb_proc_flush(server, fid);
-out:
+	smb_lock_server(server);
+	smb_proc_flush(server, inode->u.smbfs_i.fileid);
 	smb_unlock_server(server);
 	return result;
 }
@@ -1491,14 +1708,17 @@
 	fattr->f_uid = server->mnt->uid;
 	fattr->f_gid = server->mnt->gid;
 	fattr->f_blksize = SMB_ST_BLKSIZE;
+	fattr->f_unix = 0;
 }
 
 static void
 smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
+	if (fattr->f_unix)
+		return;
+
 	fattr->f_mode = server->mnt->file_mode;
-	if (fattr->attr & aDIR)
-	{
+	if (fattr->attr & aDIR) {
 		fattr->f_mode = server->mnt->dir_mode;
 		fattr->f_size = SMB_ST_BLKSIZE;
 	}
@@ -1578,7 +1798,7 @@
 #endif
 
 	qname->len = 0;
-	len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+	len = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
 			    qname->name, len,
 			    server->remote_nls, server->local_nls);
 	if (len > 0) {
@@ -1723,6 +1943,43 @@
 	return result;
 }
 
+void smb_decode_unix_basic(struct smb_fattr *fattr, char *p)
+{
+	/* FIXME: verify nls support. all is sent as utf8? */
+
+	fattr->f_unix = 1;
+	fattr->f_mode = 0;
+
+	/* FIXME: use the uniqueID from the remote instead? */
+	/* 0 L file size in bytes */
+	/* 8 L file size on disk in bytes (block count) */
+	/* 40 L uid */
+	/* 48 L gid */
+	/* 56 W file type */
+	/* 60 L devmajor */
+	/* 68 L devminor */
+	/* 76 L unique ID (inode) */
+	/* 84 L permissions */
+	/* 92 L link count */
+
+	fattr->f_size = LVAL(p, 0);
+	fattr->f_blocks = LVAL(p, 8);
+	fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16));
+	fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24));
+	fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32));
+	fattr->f_uid = LVAL(p, 40); 
+	fattr->f_gid = LVAL(p, 48); 
+	fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56));
+
+	if (S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) {
+		__u64 major = LVAL(p, 60);
+		__u64 minor = LVAL(p, 68);
+
+		fattr->f_rdev = MKDEV(major & 0xffffffff, minor & 0xffffffff);
+	}
+	fattr->f_mode |= LVAL(p, 84);
+}
+
 /*
  * Interpret a long filename structure using the specified info level:
  *   level 1 for anything below NT1 protocol
@@ -1786,13 +2043,25 @@
 		fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));
 		fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));
 		/* change time (32) */
-		fattr->f_size = DVAL(p, 40);
+		fattr->f_size = LVAL(p, 40);
 		/* alloc size (48) */
 		fattr->attr = DVAL(p, 56);
 
 		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
 			p, len, len, qname->name);
 		break;
+	case SMB_FIND_FILE_UNIX:
+		result = p + WVAL(p, 0);
+		qname->name = p + 108;
+
+		len = strlen(qname->name);
+		/* FIXME: should we check the length?? */
+
+		p += 8;
+		smb_decode_unix_basic(fattr, p);
+		VERBOSE("info SMB_FIND_FILE_UNIX at %p, len=%d, name=%.*s\n",
+			p, len, len, qname->name);
+		break;
 	default:
 		PARANOIA("Unknown info level %d\n", level);
 		result = p + WVAL(p, 0);
@@ -1817,7 +2086,7 @@
 #endif
 
 	qname->len = 0;
-	n = server->convert(server->name_buf, SMB_MAXNAMELEN,
+	n = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
 			    qname->name, len,
 			    server->remote_nls, server->local_nls);
 	if (n > 0) {
@@ -1879,7 +2148,9 @@
 	/*
 	 * use info level 1 for older servers that don't do 260
 	 */
-	if (server->opt.protocol < SMB_PROTOCOL_NT1)
+	if (server->opt.capabilities & SMB_CAP_UNIX)
+		info_level = SMB_FIND_FILE_UNIX;
+	else if (server->opt.protocol < SMB_PROTOCOL_NT1)
 		info_level = 1;
 
 	smb_lock_server(server);
@@ -1987,11 +2258,15 @@
 		 *
 		 * OS/2 needs this and talks infolevel 1
 		 * NetApps want lastname with infolevel 260
+		 * win2k want lastname with infolevel 260, and points to
+		 *       the record not to the name.
+		 * Samba+CifsUnixExt doesn't need lastname.
 		 *
-		 * Both are happy if we return the data they point to. So we do.
+		 * All are happy if we return the data they point to. So we do.
 		 */
 		mask_len = 0;
-		if (ff_lastname > 0 && ff_lastname < resp_data_len) {
+		if (info_level != SMB_FIND_FILE_UNIX &&
+		    ff_lastname > 0 && ff_lastname < resp_data_len) {
 			lastname = resp_data + ff_lastname;
 
 			switch (info_level) {
@@ -2066,18 +2341,6 @@
 	return result;
 }
 
-int
-smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
-		 struct smb_cache_control *ctl)
-{
-	struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
-
-	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
-		return smb_proc_readdir_long(filp, dirent, filldir, ctl);
-	else
-		return smb_proc_readdir_short(filp, dirent, filldir, ctl);
-}
-
 /*
  * This version uses the trans2 TRANSACT2_FINDFIRST message 
  * to get the attribute data.
@@ -2204,12 +2467,71 @@
 
 /*
  * Note: called with the server locked.
+ */
+static int
+smb_proc_getattr_trans2_all(struct smb_sb_info *server, struct dentry *dir,
+			    struct smb_fattr *attr)
+{
+	char *p, *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+
+      retry:
+	WSET(param, 0, SMB_QUERY_FILE_ALL_INFO);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	if (server->rcls != 0) {
+		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
+			&param[6], result, server->rcls, server->err);
+		result = smb_errno(server);
+		goto out;
+	}
+
+	result = -ENOENT;
+	if (resp_data_len < 56) {
+		PARANOIA("not enough data for %s, len=%d\n",
+			 &param[6], resp_data_len);
+		goto out;
+	}
+
+	attr->f_ctime = smb_ntutc2unixutc(LVAL(resp_data, 0));
+	attr->f_atime = smb_ntutc2unixutc(LVAL(resp_data, 8));
+	attr->f_mtime = smb_ntutc2unixutc(LVAL(resp_data, 16));
+	/* change (24) */
+	attr->attr = WVAL(resp_data, 32);
+	/* pad? (34) */
+	/* allocated size (40) */
+	attr->f_size = LVAL(resp_data, 48);
+	result = 0;
+
+out:
+	return result;
+}
+
+/*
+ * Note: called with the server locked.
  *
  * Bugs Noted:
  * (1) Win 95 swaps the date and time fields in the standard info level.
  */
 static int
-smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
+smb_proc_getattr_trans2_std(struct smb_sb_info *server, struct dentry *dir,
 			struct smb_fattr *attr)
 {
 	char *p, *param = server->temp_buf;
@@ -2222,7 +2544,7 @@
 	int result;
 
       retry:
-	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	WSET(param, 0, SMB_INFO_STANDARD);
 	DSET(param, 2, 0);
 	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
@@ -2246,6 +2568,7 @@
 		result = smb_errno(server);
 		goto out;
 	}
+
 	result = -ENOENT;
 	if (resp_data_len < 22)
 	{
@@ -2285,51 +2608,86 @@
 	return result;
 }
 
-/*
- * Note: called with the server locked
- */
 static int
-smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
-		    struct smb_fattr *fattr)
+smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir,
+		    struct smb_fattr *attr)
 {
-	int result;
 	struct inode *inode = dir->d_inode;
+	int result;
 
-	smb_init_dirent(server, fattr);
-
-	/*
-	 * Select whether to use core or trans2 getattr.
-	 * Win 95 appears to break with the trans2 getattr.
- 	 */
-	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 ||
-	    (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) {
-		result = smb_proc_getattr_core(server, dir, fattr);
-	} else {
-		if (server->mnt->flags & SMB_MOUNT_DIRATTR)
-			result = smb_proc_getattr_ff(server, dir, fattr);
-		else
-			result = smb_proc_getattr_trans2(server, dir, fattr);
-	}
+	result = smb_proc_getattr_trans2_std(server, dir, attr);
+	if (result < 0)
+		goto out;
 
 	/*
-	 * None of the getattr versions here can make win9x return the right
-	 * filesize if there are changes made to an open file.
-	 * A seek-to-end does return the right size, but we only need to do
-	 * that on files we have written.
+	 * None of the other getattr versions here can make win9x
+	 * return the right filesize if there are changes made to an
+	 * open file.  A seek-to-end does return the right size, but
+	 * we only need to do that on files we have written.
 	 */
-	if (server->mnt->flags & SMB_MOUNT_WIN95 &&
-	    inode &&
-	    inode->u.smbfs_i.flags & SMB_F_LOCALWRITE &&
+	if (inode && inode->u.smbfs_i.flags & SMB_F_LOCALWRITE &&
 	    smb_is_open(inode))
 	{
 		__u16 fileid = inode->u.smbfs_i.fileid;
-		fattr->f_size = smb_proc_seek(server, fileid, 2, 0);
+		attr->f_size = smb_proc_seek(server, fileid, 2, 0);
 	}
 
-	smb_finish_dirent(server, fattr);
+out:
 	return result;
 }
 
+/*
+ * Note: called with the server locked.
+ */
+static int
+smb_proc_getattr_unix(struct smb_sb_info *server, struct dentry *dir,
+		      struct smb_fattr *attr)
+{
+	char *p, *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+
+      retry:
+	WSET(param, 0, SMB_QUERY_FILE_UNIX_BASIC);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	if (server->rcls != 0) {
+		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
+			&param[6], result, server->rcls, server->err);
+		result = smb_errno(server);
+		goto out;
+	}
+
+	smb_decode_unix_basic(attr, resp_data);
+	result = 0;
+
+out:
+	return result;
+}
+
+static int
+smb_proc_getattr_null(struct smb_sb_info *server, struct dentry *dir,
+		      struct smb_fattr *attr)
+{
+	return -EIO;
+}
+
 int
 smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr)
 {
@@ -2337,7 +2695,9 @@
 	int result;
 
 	smb_lock_server(server);
-	result = smb_proc_do_getattr(server, dir, fattr);
+	smb_init_dirent(server, fattr);
+	result = server->ops->getattr(server, dir, fattr);
+	smb_finish_dirent(server, fattr);
 	smb_unlock_server(server);
 	return result;
 }
@@ -2515,6 +2875,126 @@
 }
 
 /*
+ * ATTR_MODE      0x001
+ * ATTR_UID       0x002
+ * ATTR_GID       0x004
+ * ATTR_SIZE      0x008
+ * ATTR_ATIME     0x010
+ * ATTR_MTIME     0x020
+ * ATTR_CTIME     0x040
+ * ATTR_ATIME_SET 0x080
+ * ATTR_MTIME_SET 0x100
+ * ATTR_FORCE     0x200
+ * ATTR_ATTR_FLAG 0x400
+ *
+ * major/minor should only be set by mknod.
+ */
+int
+smb_proc_setattr_unix(struct dentry *dentry, struct iattr *attr,
+		      unsigned int major, unsigned int minor)
+{
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	u64 nttime;
+	char *p, *param;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+	char data[100];
+
+	smb_lock_server(server);
+	param = server->temp_buf;
+
+	DEBUG1("valid flags = 0x%04x\n", attr->ia_valid);
+
+retry:
+	WSET(param, 0, SMB_SET_FILE_UNIX_BASIC);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+
+	/* 0 L file size in bytes */
+	/* 8 L file size on disk in bytes (block count) */
+	/* 40 L uid */
+	/* 48 L gid */
+	/* 56 W file type enum */
+	/* 60 L devmajor */
+	/* 68 L devminor */
+	/* 76 L unique ID (inode) */
+	/* 84 L permissions */
+	/* 92 L link count */
+	LSET(data, 0, SMB_SIZE_NO_CHANGE);
+	LSET(data, 8, SMB_SIZE_NO_CHANGE);
+	LSET(data, 16, SMB_TIME_NO_CHANGE);
+	LSET(data, 24, SMB_TIME_NO_CHANGE);
+	LSET(data, 32, SMB_TIME_NO_CHANGE);
+	LSET(data, 40, SMB_UID_NO_CHANGE);
+	LSET(data, 48, SMB_GID_NO_CHANGE);
+	LSET(data, 56, smb_filetype_from_mode(attr->ia_mode));
+	LSET(data, 60, major);
+	LSET(data, 68, minor);
+	LSET(data, 76, 0);
+	LSET(data, 84, SMB_MODE_NO_CHANGE);
+	LSET(data, 92, 0);
+
+	if (attr->ia_valid & ATTR_SIZE) {
+		LSET(data, 0, attr->ia_size);
+		LSET(data, 8, 0); /* can't set anyway */
+	}
+
+	/*
+	 * FIXME: check the conversion function it the correct one
+	 *
+	 * we can't set ctime but we might as well pass this to the server
+	 * and let it ignore it.
+	 */
+	if (attr->ia_valid & ATTR_CTIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_ctime);
+		LSET(data, 16, nttime);
+	}
+	if (attr->ia_valid & ATTR_ATIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_atime);
+		LSET(data, 24, nttime);
+	}
+	if (attr->ia_valid & ATTR_MTIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_mtime);
+		LSET(data, 32, nttime);
+	}
+
+	if (attr->ia_valid & ATTR_UID) {
+		LSET(data, 40, attr->ia_uid);
+	}
+	if (attr->ia_valid & ATTR_GID) {
+		LSET(data, 48, attr->ia_gid); 
+	}
+
+	if (attr->ia_valid & ATTR_MODE) {
+		LSET(data, 84, attr->ia_mode);
+	}
+
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    sizeof(data), data, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0)
+	{
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	result = 0;
+	if (server->rcls != 0)
+		result = smb_errno(server);
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
+/*
  * Set the modify and access timestamps for a file.
  *
  * Incredibly enough, in all of SMB there is no message to allow
@@ -2600,3 +3080,275 @@
 	smb_unlock_server(server);
 	return result;
 }
+
+int
+smb_proc_read_link(struct smb_sb_info *server, struct dentry *dentry,
+		   char *buffer, int len)
+{
+	char *p, *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+
+	DEBUG1("readlink of %s/%s\n", DENTRY_PATH(dentry));
+
+	smb_lock_server(server);
+  retry:
+	WSET(param, 0, SMB_QUERY_FILE_UNIX_LINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+		&param[6], result, server->rcls, server->err);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	if (server->rcls != 0) {
+		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
+			&param[6], result, server->rcls, server->err);
+		result = smb_errno(server);
+		goto out;
+	}
+
+	/* copy data up to the \0 or buffer length */
+	result = len;
+	if (resp_data_len < len)
+		result = resp_data_len;
+	strncpy(buffer, resp_data, result);
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
+
+/*
+ * Create a symlink object called dentry which points to oldpath.
+ * Samba does not permit dangling links but returns a suitable error message.
+ */
+int
+smb_proc_symlink(struct smb_sb_info *server, struct dentry *dentry,
+		 const char *oldpath)
+{
+	char *p, *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+
+	smb_lock_server(server);
+  retry:
+	WSET(param, 0, SMB_SET_FILE_UNIX_LINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    strlen(oldpath) + 1,
+				    (char *)oldpath, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+		&param[6], result, server->rcls, server->err);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	if (server->rcls != 0) {
+		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
+			&param[6], result, server->rcls, server->err);
+		result = smb_errno(server);
+		goto out;
+	}
+
+	result = 0;
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
+/*
+ * Create a hard link object called new_dentry which points to dentry.
+ */
+int
+smb_proc_link(struct smb_sb_info *server, struct dentry *dentry,
+	      struct dentry *new_dentry)
+{
+	char *p, *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+	int newpathlen = 0;
+	char newpath[SMB_MAXPATHLEN+1];		/* FIXME: ugh! */
+
+	smb_lock_server(server);
+
+	newpathlen = smb_encode_path(server, newpath, SMB_MAXPATHLEN+1, dentry, NULL);
+
+	DEBUG1("newpathlen = %d newpath=\"%s\"\n", newpathlen, newpath);
+retry:
+	WSET(param, 0, SMB_SET_FILE_UNIX_HLINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, new_dentry, NULL);
+	if (result < 0)
+		goto out;
+	p = param + 6 + result;
+	DEBUG1("pathlen = %d oldpath=\"%s\"\n", result, param + 6);
+
+
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    newpathlen + 1,
+				    (char *)newpath, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+               &param[6], result, server->rcls, server->err);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+	if (server->rcls != 0) {
+		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
+			&param[6], result, server->rcls, server->err);
+		result = smb_errno(server);
+		goto out;
+	}
+
+	result = 0;
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
+
+/*
+ * We are called with the server locked
+ */
+static int
+smb_proc_query_cifsunix(struct smb_sb_info *server)
+{
+	char *param = server->temp_buf;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+	int result;
+	int major, minor;
+	u64 caps;
+
+  retry:
+	WSET(param, 0, SMB_QUERY_CIFS_UNIX_INFO);
+	result = smb_trans2_request(server, TRANSACT2_QFSINFO,
+				    0, NULL, 2, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0) {
+		if (smb_retry(server))
+			goto retry;
+		goto out;
+	}
+
+	if (resp_data_len < 12) {
+		PARANOIA("Not enough data\n");
+		goto out;
+	}
+
+	major = WVAL(resp_data, 0);
+	minor = WVAL(resp_data, 2);
+	VERBOSE("Server implements CIFS Extensions for UNIX systems v%d.%d\n",
+		major, minor);
+	/* FIXME: verify that we are ok with this major/minor? */
+
+	caps = LVAL(resp_data, 4);
+	DEBUG1("Server capabilities 0x%016llx\n", caps);
+
+out:
+	return result;
+}
+
+
+static void
+install_ops(struct smb_ops *dst, struct smb_ops *src)
+{
+	memcpy(dst, src, sizeof(void *) * SMB_OPS_NUM_STATIC);
+}
+
+/* < LANMAN2 */
+static struct smb_ops smb_ops_core =
+{
+	.read           = smb_proc_read,
+	.write          = smb_proc_write,
+	.readdir        = smb_proc_readdir_short,
+	.getattr        = smb_proc_getattr_core,
+	.truncate       = smb_proc_trunc32,
+};
+
+/* LANMAN2, OS/2, others? */
+static struct smb_ops smb_ops_os2 =
+{
+	.read           = smb_proc_read,
+	.write          = smb_proc_write,
+	.readdir        = smb_proc_readdir_long,
+	.getattr        = smb_proc_getattr_trans2_std,
+	.truncate       = smb_proc_trunc32,
+};
+
+/* Win95, and possibly some NetApp versions too */
+static struct smb_ops smb_ops_win95 =
+{
+	.read           = smb_proc_read,    /* does not support 12word readX */
+	.write          = smb_proc_write,
+	.readdir        = smb_proc_readdir_long,
+	.getattr        = smb_proc_getattr_95,
+	.truncate       = smb_proc_trunc95,
+};
+
+/* Samba, NT4 and NT5 */
+static struct smb_ops smb_ops_winNT =
+{
+	.read           = smb_proc_readX,
+	.write          = smb_proc_writeX,
+	.readdir        = smb_proc_readdir_long,
+	.getattr        = smb_proc_getattr_trans2_all,
+	.truncate       = smb_proc_trunc64,
+};
+
+/* Samba w/ unix extensions. Others? */
+static struct smb_ops smb_ops_unix =
+{
+	.read           = smb_proc_readX,
+	.write          = smb_proc_writeX,
+	.readdir        = smb_proc_readdir_long,
+	.getattr        = smb_proc_getattr_unix,
+	.truncate       = smb_proc_trunc64,
+};
+
+/* Place holder until real ops are in place */
+static struct smb_ops smb_ops_null =
+{
+	.getattr        = smb_proc_getattr_null,
+};
+
+void smb_install_null_ops(struct smb_ops *ops)
+{
+	install_ops(ops, &smb_ops_null);
+}
diff -urN linux-2.4.25-pre7/fs/smbfs/proto.h linux-2.4.25-pre8/fs/smbfs/proto.h
--- linux-2.4.25-pre7/fs/smbfs/proto.h	2001-10-02 17:03:34.000000000 -0700
+++ linux-2.4.25-pre8/fs/smbfs/proto.h	2004-01-29 10:58:21.000000000 -0800
@@ -1,5 +1,5 @@
 /*
- *  Autogenerated with cproto on:  Tue Oct 2 20:40:54 CEST 2001
+ *  Autogenerated with cproto on:  Sat Jan 24 14:28:52 CET 2004
  */
 
 /* proc.c */
@@ -14,24 +14,27 @@
 extern int smb_open(struct dentry *dentry, int wish);
 extern int smb_close(struct inode *ino);
 extern int smb_close_fileid(struct dentry *dentry, __u16 fileid);
-extern int smb_proc_read(struct inode *inode, off_t offset, int count, char *data);
-extern int smb_proc_write(struct inode *inode, off_t offset, int count, const char *data);
 extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid);
 extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
 extern int smb_proc_mkdir(struct dentry *dentry);
 extern int smb_proc_rmdir(struct dentry *dentry);
 extern int smb_proc_unlink(struct dentry *dentry);
 extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid);
-extern int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length);
 extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
-extern int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl);
+extern void smb_decode_unix_basic(struct smb_fattr *fattr, char *p);
 extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
 extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
+extern int smb_proc_setattr_unix(struct dentry *dentry, struct iattr *attr, unsigned int major, unsigned int minor);
 extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
 extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr);
+extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *dentry, char *buffer, int len);
+extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *dentry, const char *oldpath);
+extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
+extern void smb_install_null_ops(struct smb_ops *ops);
 /* dir.c */
 extern struct file_operations smb_dir_operations;
 extern struct inode_operations smb_dir_inode_operations;
+extern struct inode_operations smb_dir_inode_operations_unix;
 extern void smb_new_dentry(struct dentry *dentry);
 extern void smb_renew_times(struct dentry *dentry);
 /* cache.c */
@@ -61,3 +64,8 @@
 extern struct inode_operations smb_file_inode_operations;
 /* ioctl.c */
 extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+/* symlink.c */
+extern int smb_read_link(struct dentry *dentry, char *buffer, int len);
+extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname);
+extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd);
+extern struct inode_operations smb_link_inode_operations;
diff -urN linux-2.4.25-pre7/fs/smbfs/symlink.c linux-2.4.25-pre8/fs/smbfs/symlink.c
--- linux-2.4.25-pre7/fs/smbfs/symlink.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/fs/smbfs/symlink.c	2004-01-29 10:58:21.000000000 -0800
@@ -0,0 +1,90 @@
+/*
+ *  symlink.c
+ *
+ *  Copyright (C) 2002 by John Newbigin
+ *
+ *  Please add a note about your changes to smbfs in the ChangeLog file.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/net.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/smbno.h>
+#include <linux/smb_fs.h>
+
+#include "smb_debug.h"
+#include "proto.h"
+
+int smb_read_link(struct dentry *dentry, char *buffer, int len)
+{
+	char *link;
+	int result;
+	DEBUG1("read link buffer len = %d\n", len);
+
+	result = -ENOMEM;
+	link = kmalloc(SMB_MAXNAMELEN + 1, GFP_KERNEL);
+	if (!link)
+		goto out;
+
+	result = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
+				    SMB_MAXNAMELEN);
+	if (result < 0)
+		goto out_free;
+	result = vfs_readlink(dentry, buffer, len, link);
+
+out_free:
+	kfree(link);
+out:
+	return result;
+}
+
+int smb_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+{
+	DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
+
+	smb_invalid_dir_cache(dir);
+	return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
+}
+
+int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *link;
+	int result;
+
+	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
+
+	result = -ENOMEM;
+	link = kmalloc(SMB_MAXNAMELEN + 1, GFP_KERNEL);
+	if (!link)
+		goto out;
+
+	result = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
+				    SMB_MAXNAMELEN);
+	if (result < 0 || result >= SMB_MAXNAMELEN)
+		goto out_free;
+	link[result] = 0;
+
+	result = vfs_follow_link(nd, link);
+
+out_free:
+	kfree(link);
+out:
+	return result;
+}
+
+struct inode_operations smb_link_inode_operations =
+{
+	.readlink	= smb_read_link,
+	.follow_link	= smb_follow_link,
+};
diff -urN linux-2.4.25-pre7/fs/xfs/xfs_log_recover.c linux-2.4.25-pre8/fs/xfs/xfs_log_recover.c
--- linux-2.4.25-pre7/fs/xfs/xfs_log_recover.c	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/fs/xfs/xfs_log_recover.c	2004-01-29 10:58:22.000000000 -0800
@@ -1553,7 +1553,7 @@
 		case XFS_LI_BUF:
 		case XFS_LI_6_1_BUF:
 		case XFS_LI_5_3_BUF:
-			if ((!flags & XFS_BLI_CANCEL)) {
+			if (!(flags & XFS_BLI_CANCEL)) {
 				xlog_recover_insert_item_frontq(&trans->r_itemq,
 								itemq);
 				break;
diff -urN linux-2.4.25-pre7/include/acpi/acconfig.h linux-2.4.25-pre8/include/acpi/acconfig.h
--- linux-2.4.25-pre7/include/acpi/acconfig.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acconfig.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20031203
+#define ACPI_CA_VERSION                 0x20040116
 
 /* Maximum objects in the various object caches */
 
diff -urN linux-2.4.25-pre7/include/acpi/acdebug.h linux-2.4.25-pre8/include/acpi/acdebug.h
--- linux-2.4.25-pre7/include/acpi/acdebug.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acdebug.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acdisasm.h linux-2.4.25-pre8/include/acpi/acdisasm.h
--- linux-2.4.25-pre7/include/acpi/acdisasm.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acdisasm.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acdispat.h linux-2.4.25-pre8/include/acpi/acdispat.h
--- linux-2.4.25-pre7/include/acpi/acdispat.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acdispat.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acevents.h linux-2.4.25-pre8/include/acpi/acevents.h
--- linux-2.4.25-pre7/include/acpi/acevents.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acevents.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acexcep.h linux-2.4.25-pre8/include/acpi/acexcep.h
--- linux-2.4.25-pre7/include/acpi/acexcep.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acexcep.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acglobal.h linux-2.4.25-pre8/include/acpi/acglobal.h
--- linux-2.4.25-pre7/include/acpi/acglobal.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acglobal.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/achware.h linux-2.4.25-pre8/include/acpi/achware.h
--- linux-2.4.25-pre7/include/acpi/achware.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/achware.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acinterp.h linux-2.4.25-pre8/include/acpi/acinterp.h
--- linux-2.4.25-pre7/include/acpi/acinterp.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acinterp.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/aclocal.h linux-2.4.25-pre8/include/acpi/aclocal.h
--- linux-2.4.25-pre7/include/acpi/aclocal.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/aclocal.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acmacros.h linux-2.4.25-pre8/include/acpi/acmacros.h
--- linux-2.4.25-pre7/include/acpi/acmacros.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acmacros.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acnamesp.h linux-2.4.25-pre8/include/acpi/acnamesp.h
--- linux-2.4.25-pre7/include/acpi/acnamesp.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acnamesp.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acobject.h linux-2.4.25-pre8/include/acpi/acobject.h
--- linux-2.4.25-pre7/include/acpi/acobject.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acobject.h	2004-01-29 10:58:22.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acoutput.h linux-2.4.25-pre8/include/acpi/acoutput.h
--- linux-2.4.25-pre7/include/acpi/acoutput.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acoutput.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acparser.h linux-2.4.25-pre8/include/acpi/acparser.h
--- linux-2.4.25-pre7/include/acpi/acparser.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acparser.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acpi.h linux-2.4.25-pre8/include/acpi/acpi.h
--- linux-2.4.25-pre7/include/acpi/acpi.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acpi.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acpiosxf.h linux-2.4.25-pre8/include/acpi/acpiosxf.h
--- linux-2.4.25-pre7/include/acpi/acpiosxf.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acpiosxf.h	2004-01-29 10:58:22.000000000 -0800
@@ -9,7 +9,7 @@
 
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acpixf.h linux-2.4.25-pre8/include/acpi/acpixf.h
--- linux-2.4.25-pre7/include/acpi/acpixf.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acpixf.h	2004-01-29 10:58:22.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acresrc.h linux-2.4.25-pre8/include/acpi/acresrc.h
--- linux-2.4.25-pre7/include/acpi/acresrc.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/acresrc.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acstruct.h linux-2.4.25-pre8/include/acpi/acstruct.h
--- linux-2.4.25-pre7/include/acpi/acstruct.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acstruct.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/actables.h linux-2.4.25-pre8/include/acpi/actables.h
--- linux-2.4.25-pre7/include/acpi/actables.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/actables.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/actbl.h linux-2.4.25-pre8/include/acpi/actbl.h
--- linux-2.4.25-pre7/include/acpi/actbl.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/actbl.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -165,6 +165,11 @@
 	u8                              type; \
 	u8                              length;
 
+struct apic_header
+{
+	APIC_HEADER_DEF
+};
+
 /* Values for MPS INTI flags */
 
 #define POLARITY_CONFORMS       0
@@ -236,7 +241,7 @@
 {
 	APIC_HEADER_DEF
 	u16                             reserved;               /* Reserved - must be zero */
-	u32                             address;                /* APIC physical address */
+	u64                             address;                /* APIC physical address */
 };
 
 struct madt_io_sapic
diff -urN linux-2.4.25-pre7/include/acpi/actbl1.h linux-2.4.25-pre8/include/acpi/actbl1.h
--- linux-2.4.25-pre7/include/acpi/actbl1.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/actbl1.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/actbl2.h linux-2.4.25-pre8/include/acpi/actbl2.h
--- linux-2.4.25-pre7/include/acpi/actbl2.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/actbl2.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/actypes.h linux-2.4.25-pre8/include/acpi/actypes.h
--- linux-2.4.25-pre7/include/acpi/actypes.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/actypes.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/acutils.h linux-2.4.25-pre8/include/acpi/acutils.h
--- linux-2.4.25-pre7/include/acpi/acutils.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/acpi/acutils.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/amlcode.h linux-2.4.25-pre8/include/acpi/amlcode.h
--- linux-2.4.25-pre7/include/acpi/amlcode.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/amlcode.h	2004-01-29 10:58:22.000000000 -0800
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/amlresrc.h linux-2.4.25-pre8/include/acpi/amlresrc.h
--- linux-2.4.25-pre7/include/acpi/amlresrc.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/amlresrc.h	2004-01-29 10:58:22.000000000 -0800
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/platform/acenv.h linux-2.4.25-pre8/include/acpi/platform/acenv.h
--- linux-2.4.25-pre7/include/acpi/platform/acenv.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/platform/acenv.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/platform/acgcc.h linux-2.4.25-pre8/include/acpi/platform/acgcc.h
--- linux-2.4.25-pre7/include/acpi/platform/acgcc.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/platform/acgcc.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/acpi/platform/aclinux.h linux-2.4.25-pre8/include/acpi/platform/aclinux.h
--- linux-2.4.25-pre7/include/acpi/platform/aclinux.h	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.25-pre8/include/acpi/platform/aclinux.h	2004-01-29 10:58:22.000000000 -0800
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2003, R. Byron Moore
+ * Copyright (C) 2000 - 2004, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff -urN linux-2.4.25-pre7/include/asm-alpha/elf.h linux-2.4.25-pre8/include/asm-alpha/elf.h
--- linux-2.4.25-pre7/include/asm-alpha/elf.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/asm-alpha/elf.h	2004-01-29 10:58:22.000000000 -0800
@@ -66,27 +66,19 @@
    instruction set this CPU supports.  This is trivial on Alpha, 
    but not so on other machines. */
 
-#define ELF_HWCAP							\
-({									\
-	/* Sadly, most folks don't yet have assemblers that know about	\
-	   amask.  This is "amask v0, v0" */				\
-	register long _v0 __asm("$0") = -1;				\
-	__asm(".long 0x47e00c20" : "=r"(_v0) : "0"(_v0));		\
-	~_v0;								\
-})
+#define ELF_HWCAP  (~amask(-1))
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.  
-
-   This might do with checking bwx simultaneously...  */
+   intent than poking at uname or /proc/cpuinfo.  */
 
 #define ELF_PLATFORM				\
 ({						\
-	/* Or "implver v0" ... */		\
-	register long _v0 __asm("$0");		\
-	__asm(".long 0x47e03d80" : "=r"(_v0));	\
-	_v0 == 0 ? "ev4" : "ev5";		\
+	enum implver_enum i_ = implver();	\
+	( i_ == IMPLVER_EV4 ? "ev4"		\
+	: i_ == IMPLVER_EV5			\
+	  ? (amask(AMASK_BWX) ? "ev5" : "ev56")	\
+	: amask (AMASK_CIX) ? "ev6" : "ev67");	\
 })
 
 #ifdef __KERNEL__
diff -urN linux-2.4.25-pre7/include/asm-alpha/system.h linux-2.4.25-pre8/include/asm-alpha/system.h
--- linux-2.4.25-pre7/include/asm-alpha/system.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.25-pre8/include/asm-alpha/system.h	2004-01-29 10:58:22.000000000 -0800
@@ -201,6 +201,7 @@
 enum amask_enum {
 	AMASK_BWX = (1UL << 0),
 	AMASK_FIX = (1UL << 1),
+	AMASK_CIX = (1UL << 2),
 	AMASK_MAX = (1UL << 8),
 	AMASK_PRECISE_TRAP = (1UL << 9),
 };
diff -urN linux-2.4.25-pre7/include/asm-i386/timex.h linux-2.4.25-pre8/include/asm-i386/timex.h
--- linux-2.4.25-pre7/include/asm-i386/timex.h	2004-01-29 10:58:18.000000000 -0800
+++ linux-2.4.25-pre8/include/asm-i386/timex.h	2002-11-28 15:53:15.000000000 -0800
@@ -40,10 +40,14 @@
 
 static inline cycles_t get_cycles (void)
 {
-	unsigned long long ret = 0;
-	if(cpu_has_tsc)
-		rdtscll(ret);
+#ifndef CONFIG_X86_TSC
+	return 0;
+#else
+	unsigned long long ret;
+
+	rdtscll(ret);
 	return ret;
+#endif
 }
 
 extern unsigned long cpu_khz;
diff -urN linux-2.4.25-pre7/include/asm-x86_64/desc.h linux-2.4.25-pre8/include/asm-x86_64/desc.h
--- linux-2.4.25-pre7/include/asm-x86_64/desc.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/asm-x86_64/desc.h	2004-01-29 10:58:22.000000000 -0800
@@ -121,6 +121,7 @@
 	dst->base1 = PTR_MIDDLE(ptr) & 0xFF; 
 	dst->type = type;
 	dst->p = 1; 
+	dst->g = 1;
 	dst->limit1 = (size >> 16) & 0xF;
 	dst->base2 = (PTR_MIDDLE(ptr) >> 8) & 0xFF; 
 	dst->base3 = PTR_HIGH(ptr); 
diff -urN linux-2.4.25-pre7/include/asm-x86_64/uaccess.h linux-2.4.25-pre8/include/asm-x86_64/uaccess.h
--- linux-2.4.25-pre7/include/asm-x86_64/uaccess.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/asm-x86_64/uaccess.h	2004-01-29 10:58:22.000000000 -0800
@@ -297,6 +297,46 @@
 	}
 }	
 
+static inline int __copy_in_user(void *dst, const void *src, unsigned size) 
+{ 
+       int ret = 0;
+       if (!__builtin_constant_p(size))
+		return copy_user_generic(dst,src,size);
+       switch (size) { 
+       case 1: { 
+	       u8 tmp;
+	       __get_user_asm(tmp,(u8 *)src,ret,"b","b","=q",1); 
+	       if (likely(!ret))
+		       __put_user_asm(tmp,(u8 *)dst,ret,"b","b","iq",1); 
+	       return ret;
+       }
+       case 2: { 
+	       u16 tmp;
+	       __get_user_asm(tmp,(u16 *)src,ret,"w","w","=r",2); 
+	       if (likely(!ret))
+		       __put_user_asm(tmp,(u16 *)dst,ret,"w","w","ir",2); 
+	       return ret;
+       }
+	       
+       case 4: { 
+	       u32 tmp;
+	       __get_user_asm(tmp,(u32 *)src,ret,"l","k","=r",4); 
+	       if (likely(!ret))
+		       __put_user_asm(tmp,(u32 *)dst,ret,"l","k","ir",4); 
+	       return ret;
+       }
+       case 8: { 
+	       u64 tmp;
+	       __get_user_asm(tmp,(u64 *)src,ret,"q","","=r",8); 
+	       if (likely(!ret))
+		       __put_user_asm(tmp,(u64 *)dst,ret,"q","","ir",8); 
+	       return ret;
+       }
+       default:
+	       return copy_user_generic(dst,src,size); 
+       }
+}	
+
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
 long strnlen_user(const char *str, long n);
diff -urN linux-2.4.25-pre7/include/asm-x86_64/unistd.h linux-2.4.25-pre8/include/asm-x86_64/unistd.h
--- linux-2.4.25-pre7/include/asm-x86_64/unistd.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/asm-x86_64/unistd.h	2004-01-29 10:58:22.000000000 -0800
@@ -590,11 +590,11 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
 { \
 long __res; \
-__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; movq %[a5],%%r9" __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; movq %[a5],%%r9 ; " __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5), \
-	  [a5] "g" ((long)(arg6),) : \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5)), \
+	  [a5] "g" ((long)(arg6)) : \
 	__syscall_clobber,"r8","r10","r9" ); \
 __syscall_return(type,__res); \
 }
diff -urN linux-2.4.25-pre7/include/linux/console.h linux-2.4.25-pre8/include/linux/console.h
--- linux-2.4.25-pre7/include/linux/console.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/console.h	2004-01-29 10:58:22.000000000 -0800
@@ -80,7 +80,7 @@
 	char	*options;			/* Options for the driver   */
 };
 #define MAX_CMDLINECONSOLES 8
-extern struct console_cmdline console_list[MAX_CMDLINECONSOLES];
+extern struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
 
 /*
  *	The interface for a console, or any other device that
diff -urN linux-2.4.25-pre7/include/linux/moduleparam.h linux-2.4.25-pre8/include/linux/moduleparam.h
--- linux-2.4.25-pre7/include/linux/moduleparam.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/moduleparam.h	2004-01-29 10:58:22.000000000 -0800
@@ -0,0 +1,25 @@
+#ifndef _LINUX_MODULE_PARAMS_H
+#define _LINUX_MODULE_PARAMS_H
+/* Macros for (very simple) module parameter compatibility with 2.6. */
+#include <linux/module.h>
+
+/* type is byte, short, ushort, int, uint, long, ulong, bool. (2.6
+   has more, but they are not supported).  perm is permissions when
+   it appears in sysfs: 0 means doens't appear, 0444 means read-only
+   by everyone, 0644 means changable dynamically by root, etc.  name
+   must be in scope (unlike MODULE_PARM).
+*/
+#define module_param(name, type, perm)					     \
+	static inline void *__check_existence_##name(void) { return &name; } \
+	MODULE_PARM(name, _MODULE_PARM_STRING_ ## type)
+
+#define _MODULE_PARM_STRING_byte "b"
+#define _MODULE_PARM_STRING_short "h"
+#define _MODULE_PARM_STRING_ushort "h"
+#define _MODULE_PARM_STRING_int "i"
+#define _MODULE_PARM_STRING_uint "i"
+#define _MODULE_PARM_STRING_long "l"
+#define _MODULE_PARM_STRING_ulong "l"
+#define _MODULE_PARM_STRING_bool "i"
+
+#endif /* _LINUX_MODULE_PARAM_TYPES_H */
diff -urN linux-2.4.25-pre7/include/linux/pci_ids.h linux-2.4.25-pre8/include/linux/pci_ids.h
--- linux-2.4.25-pre7/include/linux/pci_ids.h	2004-01-29 10:58:19.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/pci_ids.h	2004-01-29 10:58:22.000000000 -0800
@@ -1438,6 +1438,7 @@
 #define PCI_VENDOR_ID_ITE		0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G	0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
+#define PCI_DEVICE_ID_ITE_IT8181	0x8181
 #define PCI_DEVICE_ID_ITE_8872		0x8872
 
 #define PCI_DEVICE_ID_ITE_IT8330G_0    0xe886
diff -urN linux-2.4.25-pre7/include/linux/smb.h linux-2.4.25-pre8/include/linux/smb.h
--- linux-2.4.25-pre7/include/linux/smb.h	2001-11-22 11:46:18.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/smb.h	2004-01-29 10:58:22.000000000 -0800
@@ -85,12 +85,13 @@
 	uid_t		f_uid;
 	gid_t		f_gid;
 	kdev_t		f_rdev;
-	off_t		f_size;
+	loff_t		f_size;
 	time_t		f_atime;
 	time_t		f_mtime;
 	time_t		f_ctime;
 	unsigned long	f_blksize;
 	unsigned long	f_blocks;
+	int		f_unix;
 };
 
 enum smb_conn_state {
diff -urN linux-2.4.25-pre7/include/linux/smb_fs.h linux-2.4.25-pre8/include/linux/smb_fs.h
--- linux-2.4.25-pre7/include/linux/smb_fs.h	2001-10-02 17:03:34.000000000 -0700
+++ linux-2.4.25-pre8/include/linux/smb_fs.h	2004-01-29 10:58:22.000000000 -0800
@@ -100,18 +100,20 @@
 
 
 /* NT1 protocol capability bits */
-#define SMB_CAP_RAW_MODE         0x0001
-#define SMB_CAP_MPX_MODE         0x0002
-#define SMB_CAP_UNICODE          0x0004
-#define SMB_CAP_LARGE_FILES      0x0008
-#define SMB_CAP_NT_SMBS          0x0010
-#define SMB_CAP_RPC_REMOTE_APIS  0x0020
-#define SMB_CAP_STATUS32         0x0040
-#define SMB_CAP_LEVEL_II_OPLOCKS 0x0080
-#define SMB_CAP_LOCK_AND_READ    0x0100
-#define SMB_CAP_NT_FIND          0x0200
-#define SMB_CAP_DFS              0x1000
-#define SMB_CAP_LARGE_READX      0x4000
+#define SMB_CAP_RAW_MODE         0x00000001
+#define SMB_CAP_MPX_MODE         0x00000002
+#define SMB_CAP_UNICODE          0x00000004
+#define SMB_CAP_LARGE_FILES      0x00000008
+#define SMB_CAP_NT_SMBS          0x00000010
+#define SMB_CAP_RPC_REMOTE_APIS  0x00000020
+#define SMB_CAP_STATUS32         0x00000040
+#define SMB_CAP_LEVEL_II_OPLOCKS 0x00000080
+#define SMB_CAP_LOCK_AND_READ    0x00000100
+#define SMB_CAP_NT_FIND          0x00000200
+#define SMB_CAP_DFS              0x00001000
+#define SMB_CAP_LARGE_READX      0x00004000
+#define SMB_CAP_LARGE_WRITEX     0x00008000
+#define SMB_CAP_UNIX             0x00800000     /* unofficial ... */
 
 
 /*
@@ -160,6 +162,29 @@
 	return (i->u.smbfs_i.open == server_from_inode(i)->generation);
 }
 
+#define SMB_OPS_NUM_STATIC      5
+struct smb_ops {
+	int (*read)(struct inode *inode, loff_t offset, int count,
+		    char *data);
+	int (*write)(struct inode *inode, loff_t offset, int count, const
+		     char *data);
+	int (*readdir)(struct file *filp, void *dirent, filldir_t filldir,
+		       struct smb_cache_control *ctl);
+
+	int (*getattr)(struct smb_sb_info *server, struct dentry *dir,
+		       struct smb_fattr *fattr);
+	/* int (*setattr)(...); */      /* setattr is really icky! */
+
+	int (*truncate)(struct inode *inode, loff_t length);
+
+
+	/* --- --- --- end of "static" entries --- --- --- */
+
+	int (*convert)(unsigned char *output, int olen,
+		       const unsigned char *input, int ilen,
+		       struct nls_table *nls_from,
+		       struct nls_table *nls_to);
+};
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.4.25-pre7/include/linux/smb_fs_sb.h linux-2.4.25-pre8/include/linux/smb_fs_sb.h
--- linux-2.4.25-pre7/include/linux/smb_fs_sb.h	2001-11-22 11:46:18.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/smb_fs_sb.h	2004-01-29 10:58:22.000000000 -0800
@@ -54,8 +54,7 @@
 	   to put it on the stack. This points to temp_buf space. */
 	char *name_buf;
 
-	int (*convert)(char *, int, const char *, int,
-		       struct nls_table *, struct nls_table *);
+	struct smb_ops *ops;
 };
 
 
diff -urN linux-2.4.25-pre7/include/linux/smb_mount.h linux-2.4.25-pre8/include/linux/smb_mount.h
--- linux-2.4.25-pre7/include/linux/smb_mount.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/smb_mount.h	2004-01-29 10:58:22.000000000 -0800
@@ -42,7 +42,7 @@
 struct smb_mount_data_kernel {
 	int version;
 
-	__kernel_uid_t mounted_uid;	/* Who may umount() this filesystem? */
+	uid_t mounted_uid;	/* Who may umount() this filesystem? */
 	__kernel_uid_t uid;
 	__kernel_gid_t gid;
 	__kernel_mode_t file_mode;
diff -urN linux-2.4.25-pre7/include/linux/smbno.h linux-2.4.25-pre8/include/linux/smbno.h
--- linux-2.4.25-pre7/include/linux/smbno.h	2001-10-07 16:47:43.000000000 -0700
+++ linux-2.4.25-pre8/include/linux/smbno.h	2004-01-29 10:58:22.000000000 -0800
@@ -281,4 +281,64 @@
 #define TRANSACT2_FINDNOTIFYNEXT  12
 #define TRANSACT2_MKDIR           13
 
+/* Information Levels -  Shared? */
+#define SMB_INFO_STANDARD		1
+#define SMB_INFO_QUERY_EA_SIZE		2
+#define SMB_INFO_QUERY_EAS_FROM_LIST	3
+#define SMB_INFO_QUERY_ALL_EAS		4
+#define SMB_INFO_IS_NAME_VALID		6
+
+/* Information Levels -  TRANSACT2_FINDFIRST */
+#define SMB_FIND_FILE_DIRECTORY_INFO		0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO	0x102
+#define SMB_FIND_FILE_NAMES_INFO		0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO	0x104
+
+/* Information Levels -  TRANSACT2_QPATHINFO */
+#define SMB_QUERY_FILE_BASIC_INFO	0x101
+#define SMB_QUERY_FILE_STANDARD_INFO	0x102
+#define SMB_QUERY_FILE_EA_INFO		0x103
+#define SMB_QUERY_FILE_NAME_INFO	0x104
+#define SMB_QUERY_FILE_ALL_INFO		0x107
+#define SMB_QUERY_FILE_ALT_NAME_INFO	0x108
+#define SMB_QUERY_FILE_STREAM_INFO	0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO	0x10b
+
+/* Information Levels - TRANSACT2_SETFILEINFO */
+#define SMB_SET_FILE_BASIC_INFO		0x101
+#define SMB_SET_FILE_DISPOSITION_INFO	0x102
+#define SMB_SET_FILE_ALLOCATION_INFO	0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO	0x104
+
+/*
+ * UNIX stuff  (from samba trans2.h)
+ */
+#define MIN_UNIX_INFO_LEVEL		0x200
+#define MAX_UNIX_INFO_LEVEL		0x2FF
+#define SMB_FIND_FILE_UNIX		0x202
+#define SMB_QUERY_FILE_UNIX_BASIC	0x200
+#define SMB_QUERY_FILE_UNIX_LINK	0x201
+#define SMB_QUERY_FILE_UNIX_HLINK	0x202
+#define SMB_SET_FILE_UNIX_BASIC		0x200
+#define SMB_SET_FILE_UNIX_LINK		0x201
+#define SMB_SET_FILE_UNIX_HLINK		0x203
+#define SMB_QUERY_CIFS_UNIX_INFO	0x200
+
+/* values which means "don't change it" */
+#define SMB_MODE_NO_CHANGE		0xFFFFFFFF
+#define SMB_UID_NO_CHANGE		0xFFFFFFFF
+#define SMB_GID_NO_CHANGE		0xFFFFFFFF
+#define SMB_TIME_NO_CHANGE		0xFFFFFFFFFFFFFFFFULL
+#define SMB_SIZE_NO_CHANGE		0xFFFFFFFFFFFFFFFFULL
+
+/* UNIX filetype mappings. */
+#define UNIX_TYPE_FILE		0
+#define UNIX_TYPE_DIR		1
+#define UNIX_TYPE_SYMLINK	2
+#define UNIX_TYPE_CHARDEV	3
+#define UNIX_TYPE_BLKDEV	4
+#define UNIX_TYPE_FIFO		5
+#define UNIX_TYPE_SOCKET	6
+#define UNIX_TYPE_UNKNOWN	0xFFFFFFFF
+
 #endif /* _SMBNO_H_ */
diff -urN linux-2.4.25-pre7/include/linux/usb_gadget.h linux-2.4.25-pre8/include/linux/usb_gadget.h
--- linux-2.4.25-pre7/include/linux/usb_gadget.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.25-pre8/include/linux/usb_gadget.h	2004-01-29 10:58:22.000000000 -0800
@@ -28,12 +28,20 @@
  * 	for mapping and unmapping the buffer.
  * @length: Length of that data
  * @no_interrupt: If true, hints that no completion irq is needed.
- *	Helpful sometimes with deep request queues.
+ *	Helpful sometimes with deep request queues that are handled
+ *	directly by DMA controllers.
  * @zero: If true, when writing data, makes the last packet be "short"
  *     by adding a zero length packet as needed;
  * @short_not_ok: When reading data, makes short packets be
  *     treated as errors (queue stops advancing till cleanup).
- * @complete: Function called when request completes
+ * @complete: Function called when request completes, so this request and
+ *	its buffer may be re-used.
+ *	Reads terminate with a short packet, or when the buffer fills,
+ *	whichever comes first.  When writes terminate, some data bytes
+ *	will usually still be in flight (often in a hardware fifo).
+ *	Errors (for reads or writes) stop the queue from advancing
+ *	until the completion function returns, so that any transfers
+ *	invalidated by the error may first be dequeued.
  * @context: For use by the completion callback
  * @list: For use by the gadget driver.
  * @status: Reports completion code, zero or a negative errno.
@@ -41,12 +49,13 @@
  * 	the completion callback returns.
  * 	Code "-ESHUTDOWN" indicates completion caused by device disconnect,
  * 	or when the driver disabled the endpoint.
- * @actual: Reports actual bytes transferred.  For reads (OUT
+ * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
  * 	transfers) this may be less than the requested length.  If the
  * 	short_not_ok flag is set, short reads are treated as errors
  * 	even when status otherwise indicates successful completion.
- * 	Note that for writes (IN transfers) the data bytes may still
- * 	reside in a device-side FIFO.
+ * 	Note that for writes (IN transfers) some data bytes may still
+ * 	reside in a device-side FIFO when the request is reported as
+ *	complete.
  *
  * These are allocated/freed through the endpoint they're used with.  The
  * hardware's driver can add extra per-request data to the memory it returns,
@@ -72,9 +81,9 @@
 	unsigned		length;
 	dma_addr_t		dma;
 
-	unsigned		no_interrupt : 1,
-				zero : 1,
-				short_not_ok : 1;
+	unsigned		no_interrupt:1;
+	unsigned		zero:1;
+	unsigned		short_not_ok:1;
 
 	void			(*complete)(struct usb_ep *ep,
 					struct usb_request *req);
@@ -122,9 +131,11 @@
 /**
  * struct usb_ep - device side representation of USB endpoint
  * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
+ * @ops: Function pointers used to access hardware-specific operations.
  * @ep_list:the gadget's ep_list holds all of its endpoints
- * @maxpacket:the maximum packet size used on this endpoint, as
- * 	configured when the endpoint was enabled.
+ * @maxpacket:The maximum packet size used on this endpoint.  The initial
+ *	value can sometimes be reduced (hardware allowing), according to
+ *      the endpoint descriptor used to configure the endpoint.
  * @driver_data:for use by the gadget driver.  all other fields are
  * 	read-only to gadget drivers.
  *
@@ -138,7 +149,7 @@
 	const char		*name;
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
-	unsigned		maxpacket : 16;
+	unsigned		maxpacket:16;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -285,6 +296,9 @@
  * Each request is turned into one or more packets.  The controller driver
  * never merges adjacent requests into the same packet.  OUT transfers
  * will sometimes use data that's already buffered in the hardware.
+ * Drivers can rely on the fact that the first byte of the request's buffer
+ * always corresponds to the first byte of some USB packet, for both
+ * IN and OUT transfers.
  *
  * Bulk endpoints can queue any amount of data; the transfer is packetized
  * automatically.  The last packet will be short if the request doesn't fill it
@@ -359,6 +373,9 @@
  *
  * Returns zero, or a negative error code.  On success, this call sets
  * underlying hardware state that blocks data transfers.
+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
+ * transfer requests are still queued, or if the controller hardware
+ * (usually a FIFO) still holds bytes that the host hasn't collected.
  */
 static inline int
 usb_ep_set_halt (struct usb_ep *ep)
@@ -391,8 +408,8 @@
  *
  * FIFO endpoints may have "unclaimed data" in them in certain cases,
  * such as after aborted transfers.  Hosts may not have collected all
- * the IN data written by the gadget driver, as reported by a request
- * completion.  The gadget driver may not have collected all the data
+ * the IN data written by the gadget driver (and reported by a request
+ * completion).  The gadget driver may not have collected all the data
  * written OUT to it by the host.  Drivers that need precise handling for
  * fault reporting or recovery may need to use this call.
  *
@@ -443,18 +460,21 @@
 
 /**
  * struct usb_gadget - represents a usb slave device
+ * @ops: Function pointers used to access hardware-specific operations.
  * @ep0: Endpoint zero, used when reading or writing responses to
  * 	driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
  * @name: Identifies the controller hardware type.  Used in diagnostics
  * 	and sometimes configuration.
+ * @dev: Driver model state for this abstract device.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
- * functions, handling all usb configurations and interfaces.  They
- * also have a hardware-specific driver (accessed through ops vectors),
- * which insulates the gadget driver from hardware details and packages
- * the hardware endpoints through generic i/o queues.
+ * functions, handling all usb configurations and interfaces.  Gadget
+ * drivers talk to hardware-specific code indirectly, through ops vectors.
+ * That insulates the gadget driver from hardware details, and packages
+ * the hardware endpoints through generic i/o queues.  The "usb_gadget"
+ * and "usb_ep" interfaces provide that insulation from the hardware.
  *
  * Except for the driver data, all fields in this structure are
  * read-only to the gadget driver.  That driver data is part of the
diff -urN linux-2.4.25-pre7/net/ipv4/igmp.c linux-2.4.25-pre8/net/ipv4/igmp.c
--- linux-2.4.25-pre7/net/ipv4/igmp.c	2004-01-29 10:58:19.000000000 -0800
+++ linux-2.4.25-pre8/net/ipv4/igmp.c	2004-01-29 10:58:22.000000000 -0800
@@ -2071,16 +2071,19 @@
 	 * Differs from 2.5.x here.	+-DLS 4/23/03
 	 */
 	if (im) {
-		for (psf=im->sources; psf; psf=psf->sf_next) {
-			if (psf->sf_inaddr == src_addr)
-				break;
-		}
-		if (psf)
-			rv = psf->sf_count[MCAST_INCLUDE] ||
-				psf->sf_count[MCAST_EXCLUDE] !=
-				im->sfcount[MCAST_EXCLUDE];
-		else
-			rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		if (src_addr) {
+			for (psf=im->sources; psf; psf=psf->sf_next) {
+				if (psf->sf_inaddr == src_addr)
+					break;
+			}
+			if (psf)
+				rv = psf->sf_count[MCAST_INCLUDE] ||
+					psf->sf_count[MCAST_EXCLUDE] !=
+					im->sfcount[MCAST_EXCLUDE];
+			else
+				rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		} else
+			rv = 1;
 	}
 	read_unlock(&in_dev->lock);
 	return rv;
diff -urN linux-2.4.25-pre7/net/ipv6/mcast.c linux-2.4.25-pre8/net/ipv6/mcast.c
--- linux-2.4.25-pre7/net/ipv6/mcast.c	2004-01-29 10:58:19.000000000 -0800
+++ linux-2.4.25-pre8/net/ipv6/mcast.c	2004-01-29 10:58:22.000000000 -0800
@@ -914,20 +914,24 @@
 				break;
 		}
 		if (mc) {
-			struct ip6_sf_list *psf;
+			if (!ipv6_addr_any(src_addr)) {
+				struct ip6_sf_list *psf;
 
-			spin_lock_bh(&mc->mca_lock);
-			for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
-				if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
-					break;
-			}
-			if (psf)
-				rv = psf->sf_count[MCAST_INCLUDE] ||
-					psf->sf_count[MCAST_EXCLUDE] !=
-					mc->mca_sfcount[MCAST_EXCLUDE];
-			else
-				rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
-			spin_unlock_bh(&mc->mca_lock);
+				spin_lock_bh(&mc->mca_lock);
+				for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+					if (ipv6_addr_cmp(&psf->sf_addr,
+					    src_addr) == 0)
+						break;
+				}
+				if (psf)
+					rv = psf->sf_count[MCAST_INCLUDE] ||
+						psf->sf_count[MCAST_EXCLUDE] !=
+						mc->mca_sfcount[MCAST_EXCLUDE];
+				else
+					rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+				spin_unlock_bh(&mc->mca_lock);
+			} else
+				rv = 1; /* don't filter unspecified source */
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);
